Skip to content

Commit a60121d

Browse files
committed
Add multiple node PVE templates (with local storage) capability to cluster classes.
1 parent e393e18 commit a60121d

File tree

4 files changed

+615
-114
lines changed

4 files changed

+615
-114
lines changed

docs/advanced-setups.md

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,47 @@ For example, you can set the `TEMPLATE_TAGS="tag1,tag2"` environment variable. Y
197197
* Each node listed in the `allowedNodes` is expected to have a copy of the template stored locally.
198198
* If any of the nodes in `allowedNodes` is missing the template, the operation fails.
199199

200+
### Template lookup and cluster classes
201+
With the ClusterClasses provided in this repo, in your cluster you can choose one of two ways to tell CAPMOX which
202+
Proxmox VM template to clone from. 1) Selector mode (tag-based) — recommended for multi-node setups:
203+
```yaml
204+
spec:
205+
topology:
206+
variables:
207+
- name: templateSelector
208+
value:
209+
matchTags: ["capmox","ubuntu-24.04","k8s-1.33"]
210+
```
211+
This enables `templateSelector.matchTags`, and removes `sourceNode` and `templateID`.
212+
213+
Or 2) Explicit mode (sourceNode/templateID) — default if templateSelector is not set.
214+
```yaml
215+
spec:
216+
topology:
217+
variables:
218+
- name: cloneSpec
219+
value:
220+
machineSpec:
221+
controlPlane:
222+
sourceNode: pve1
223+
templateID: 100
224+
workerNode:
225+
sourceNode: pve1
226+
templateID: 100
227+
loadBalancer:
228+
sourceNode: pve1
229+
templateID: 100
230+
```
231+
232+
If using local (not shared) storage on nodes, you can also set `localStorage: true` in the selector:
233+
```yaml
234+
spec:
235+
topology:
236+
variables:
237+
- name: localStorage
238+
value: true
239+
```
240+
See earlier `localStorage` section for details.
200241

201242
## Proxmox RBAC with least privileges
202243

@@ -322,6 +363,71 @@ spec:
322363
You can set either `ipv4PoolRef` or `ipv6PoolRef` or you can also set them both for dual-stack.
323364
It's up for you also to manage the IP Pool, you can choose a `GlobalInClusterIPPool` or an `InClusterIPPool`.
324365

366+
## Additional Volumes
367+
By default, only a boot volume is created in machines. If additional disks are required for data storage, they can be
368+
specified in the ProxmoxMachineTemplates.
369+
370+
```yaml
371+
kind: ProxmoxMachineTemplate
372+
spec:
373+
template:
374+
spec:
375+
storage: local-lvm # Optional: a default storage to use when a volume doesn't set .storage
376+
disks:
377+
additionalVolumes:
378+
- disk: scsi1
379+
sizeGb: 200
380+
- disk: scsi2 # target slot (e.g. scsi1, sata1, virtio1, ide2)
381+
sizeGb: 80 # capacity in gigabytes
382+
# Optional flags:
383+
storage: my-nfs # Optional per-volume storage override. Uses .spec.template.spec.storage if omitted
384+
format: qcow2 # Only specify if using file-backed storage. If omitted, default for disk is used.
385+
discard: true
386+
ioThread: true
387+
ssd: true
388+
```
389+
In the same way, additionalVolumes can also be specified in ProxmoxClusters, ProxmoxClusterTemplates,
390+
and ProxmoxMachines. Flags: format, discard, ioThread, and ssd are supported by this provider.
391+
See Proxmox [docs](https://pve.proxmox.com/pve-docs/qm.1.html#qm_hard_disk) for details about these flags.
392+
393+
Alternatively if using cluster-class, define additionalVolumes in your cluster:
394+
```yaml
395+
kind: Cluster
396+
spec:
397+
topology:
398+
class: proxmox-clusterclass-cilium-v0.1.0
399+
variables:
400+
- name: workerAdditionalVolumes
401+
value:
402+
- { disk: scsi1, sizeGb: 80, storage: my-lvm }
403+
- { disk: ide1, sizeGb: 80, storage: my-zfs }
404+
- name: controlPlaneAdditionalVolumes
405+
value:
406+
- { disk: virtio1, sizeGb: 80, storage: my-zfs }
407+
- name: loadBalancerAdditionalVolumes
408+
value:
409+
- { disk: sata1, sizeGb: 80, storage: my-nfs, format: qcow2 }
410+
```
411+
To use the same storage for all machines of a given type, can specify a `<type>Storage` variable and then omit `storage`
412+
from the `workerAdditionalVolumes`. Eg for workers:
413+
```yaml
414+
kind: Cluster
415+
metadata:
416+
labels:
417+
cluster.x-k8s.io/proxmox-cluster-cni: cilium
418+
name: capmox-cluster
419+
spec:
420+
topology:
421+
class: proxmox-clusterclass-cilium-v0.1.0
422+
variables:
423+
- name: workerStorage
424+
value: my-lvm
425+
- name: workerAdditionalVolumes
426+
value:
427+
- { disk: scsi1, sizeGb: 80 }
428+
- { disk: scsi2, sizeGb: 80 }
429+
```
430+
325431
## Notes
326432

327433
* Clusters with IPV6 only is supported.

templates/cluster-class-calico.yaml

Lines changed: 167 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,29 @@ spec:
166166
mode:
167167
type: string
168168
enum: ["ipvs","iptables"]
169+
- name: templateSelector
170+
required: false
171+
schema:
172+
openAPIV3Schema:
173+
description: When set, we use tag-based template selection (and drop sourceNode/templateID).
174+
type: object
175+
properties:
176+
matchTags:
177+
type: array
178+
items:
179+
type: string
180+
minItems: 1
181+
required:
182+
- matchTags
183+
- name: localStorage
184+
required: false
185+
schema:
186+
openAPIV3Schema:
187+
type: boolean
188+
default: false
189+
description: >
190+
If true, CAPMOX will schedule clones from a template on the same node where the VM is created (works with
191+
templateSelector or explicit sourceNode/templateID). Defaults to false.
169192
- name: cloneSpec
170193
required: true
171194
schema:
@@ -187,8 +210,6 @@ spec:
187210
properties:
188211
controlPlane: &machineSpec
189212
type: object
190-
required:
191-
- sourceNode
192213
properties:
193214
disks:
194215
type: object
@@ -512,20 +533,162 @@ spec:
512533
path: /etc/kubernetes/admin.conf
513534
type: FileOrCreate
514535
name: kubeconfig
536+
- name: ApplyLocalStorageFlag-ControlPlane
537+
definitions:
515538
- selector:
516539
apiVersion: infrastructure.cluster.x-k8s.io/v1alpha1
517540
kind: ProxmoxMachineTemplate
518541
matchResources:
519542
controlPlane: true
520543
jsonPatches:
521-
- op: replace
544+
- op: add
545+
path: /spec/template/spec/localStorage
546+
valueFrom:
547+
template: '{{ .localStorage | default false }}'
548+
549+
- name: ApplyLocalStorageFlag-Worker
550+
definitions:
551+
- selector:
552+
apiVersion: infrastructure.cluster.x-k8s.io/v1alpha1
553+
kind: ProxmoxMachineTemplate
554+
matchResources:
555+
machineDeploymentClass:
556+
names:
557+
- proxmox-worker
558+
jsonPatches:
559+
- op: add
560+
path: /spec/template/spec/localStorage
561+
valueFrom:
562+
template: '{{ .localStorage | default false }}'
563+
564+
- name: ApplyLocalStorageFlag-LoadBalancer
565+
definitions:
566+
- selector:
567+
apiVersion: infrastructure.cluster.x-k8s.io/v1alpha1
568+
kind: ProxmoxMachineTemplate
569+
matchResources:
570+
machineDeploymentClass:
571+
names:
572+
- proxmox-loadbalancer
573+
jsonPatches:
574+
- op: add
575+
path: /spec/template/spec/localStorage
576+
valueFrom:
577+
template: '{{ .localStorage | default false }}'
578+
579+
# (A) Selector mode: if templateSelector is provided, set it and REMOVE sourceNode/templateID
580+
- name: TemplateSelectorMode-ControlPlane
581+
enabledIf: '{{ if .templateSelector }}true{{ end }}'
582+
definitions:
583+
- selector:
584+
apiVersion: infrastructure.cluster.x-k8s.io/v1alpha1
585+
kind: ProxmoxMachineTemplate
586+
matchResources:
587+
controlPlane: true
588+
jsonPatches:
589+
- op: add
590+
path: /spec/template/spec/templateSelector
591+
valueFrom:
592+
variable: templateSelector
593+
- op: remove
594+
path: /spec/template/spec/sourceNode
595+
- op: remove
596+
path: /spec/template/spec/templateID
597+
- name: TemplateSelectorMode-Worker
598+
enabledIf: '{{ if .templateSelector }}true{{ end }}'
599+
definitions:
600+
- selector:
601+
apiVersion: infrastructure.cluster.x-k8s.io/v1alpha1
602+
kind: ProxmoxMachineTemplate
603+
matchResources:
604+
machineDeploymentClass:
605+
names:
606+
- proxmox-worker
607+
jsonPatches:
608+
- op: add
609+
path: /spec/template/spec/templateSelector
610+
valueFrom:
611+
variable: templateSelector
612+
- op: remove
613+
path: /spec/template/spec/sourceNode
614+
- op: remove
615+
path: /spec/template/spec/templateID
616+
- name: TemplateSelectorMode-LoadBalancer
617+
enabledIf: '{{ if .templateSelector }}true{{ end }}'
618+
definitions:
619+
- selector:
620+
apiVersion: infrastructure.cluster.x-k8s.io/v1alpha1
621+
kind: ProxmoxMachineTemplate
622+
matchResources:
623+
machineDeploymentClass:
624+
names:
625+
- proxmox-loadbalancer
626+
jsonPatches:
627+
- op: add
628+
path: /spec/template/spec/templateSelector
629+
valueFrom:
630+
variable: templateSelector
631+
- op: remove
632+
path: /spec/template/spec/sourceNode
633+
- op: remove
634+
path: /spec/template/spec/templateID
635+
636+
# (B) Explicit mode: when NO templateSelector, set sourceNode/templateID from cloneSpec
637+
- name: ExplicitMode-ControlPlane
638+
enabledIf: '{{ if not .templateSelector }}true{{ end }}'
639+
definitions:
640+
- selector:
641+
apiVersion: infrastructure.cluster.x-k8s.io/v1alpha1
642+
kind: ProxmoxMachineTemplate
643+
matchResources:
644+
controlPlane: true
645+
jsonPatches:
646+
- op: add
522647
path: /spec/template/spec/sourceNode
523648
valueFrom:
524649
variable: cloneSpec.machineSpec.controlPlane.sourceNode
525-
- op: replace
650+
- op: add
526651
path: /spec/template/spec/templateID
527652
valueFrom:
528653
variable: cloneSpec.machineSpec.controlPlane.templateID
654+
- name: ExplicitMode-Worker
655+
enabledIf: '{{ if not .templateSelector }}true{{ end }}'
656+
definitions:
657+
- selector:
658+
apiVersion: infrastructure.cluster.x-k8s.io/v1alpha1
659+
kind: ProxmoxMachineTemplate
660+
matchResources:
661+
machineDeploymentClass:
662+
names:
663+
- proxmox-worker
664+
jsonPatches:
665+
- op: add
666+
path: /spec/template/spec/sourceNode
667+
valueFrom:
668+
variable: cloneSpec.machineSpec.workerNode.sourceNode
669+
- op: add
670+
path: /spec/template/spec/templateID
671+
valueFrom:
672+
variable: cloneSpec.machineSpec.workerNode.templateID
673+
- name: ExplicitMode-LoadBalancer
674+
enabledIf: '{{ if not .templateSelector }}true{{ end }}'
675+
definitions:
676+
- selector:
677+
apiVersion: infrastructure.cluster.x-k8s.io/v1alpha1
678+
kind: ProxmoxMachineTemplate
679+
matchResources:
680+
machineDeploymentClass:
681+
names:
682+
- proxmox-loadbalancer
683+
jsonPatches:
684+
- op: add
685+
path: /spec/template/spec/sourceNode
686+
valueFrom:
687+
variable: cloneSpec.machineSpec.loadBalancer.sourceNode
688+
- op: add
689+
path: /spec/template/spec/templateID
690+
valueFrom:
691+
variable: cloneSpec.machineSpec.loadBalancer.templateID
529692
- name: kube-proxy-setup
530693
description: "kube-proxy configuration"
531694
enabledIf: "{{ if eq .kubeProxy.mode \"ipvs\" }}true{{ end }}"
@@ -573,23 +736,6 @@ spec:
573736
template: |
574737
- name: root
575738
sshAuthorizedKeys: {{ .cloneSpec.sshAuthorizedKeys }}
576-
- selector:
577-
apiVersion: infrastructure.cluster.x-k8s.io/v1alpha1
578-
kind: ProxmoxMachineTemplate
579-
matchResources:
580-
controlPlane: false
581-
machineDeploymentClass:
582-
names:
583-
- proxmox-worker
584-
jsonPatches:
585-
- op: replace
586-
path: /spec/template/spec/sourceNode
587-
valueFrom:
588-
variable: cloneSpec.machineSpec.workerNode.sourceNode
589-
- op: replace
590-
path: /spec/template/spec/templateID
591-
valueFrom:
592-
variable: cloneSpec.machineSpec.workerNode.templateID
593739
- name: LoadBalancerSetup
594740
description: "Configure LoadBalancer Node Initialisation"
595741
definitions:
@@ -607,23 +753,6 @@ spec:
607753
template: |
608754
- name: root
609755
sshAuthorizedKeys: {{ .cloneSpec.sshAuthorizedKeys }}
610-
- selector:
611-
apiVersion: infrastructure.cluster.x-k8s.io/v1alpha1
612-
kind: ProxmoxMachineTemplate
613-
matchResources:
614-
controlPlane: false
615-
machineDeploymentClass:
616-
names:
617-
- proxmox-loadbalancer
618-
jsonPatches:
619-
- op: replace
620-
path: /spec/template/spec/sourceNode
621-
valueFrom:
622-
variable: cloneSpec.machineSpec.loadBalancer.sourceNode
623-
- op: replace
624-
path: /spec/template/spec/templateID
625-
valueFrom:
626-
variable: cloneSpec.machineSpec.loadBalancer.templateID
627756
- name: ControlPlaneNodeSockets
628757
description: "Configure Control Plane Sockets"
629758
enabledIf: "{{ if .cloneSpec.machineSpecs.controlPlane.numSockets }}true{{ end }}"

0 commit comments

Comments
 (0)