Cluster API Provider for Proxmox VE (CAPMOX)
repository·main·Indexed 19 days ago
https://github.com/ionos-cloud/cluster-api-provider-proxmoxCAPMOX is a Cluster API (CAPI) provider for the declarative management of Kubernetes clusters on Proxmox Virtual Environment (VE). It enables creating, configuring, and managing clusters using Kubernetes-style APIs. Key features include support for dual-stack (IPv4/IPv6) clusters, BGP-based LoadBalancer nodes via Cilium, tag-based VM template selection, and a convert CLI tool for upgrading manifests from v1alpha1 to v1alpha2.
What's inside cluster-api-provider-proxmox
- CAPMOX is a concrete implementation of the Cluster API specifically designed for Proxmox Virtual Environment (VE). It allows users to use declarative, Kubernetes-style APIs to create, configure, and manage Kubernetes clusters running on Proxmox VE infrastructure.
Configure additive IP pools for ProxmoxMachine network devices
mainIn
v1alpha2, IP address assignment usesnetwork.networkDevicesandipPoolRef.Important: Pool references are additive.
defaultIPv4ordefaultIPv6(set totrue) attaches addresses from the selected cluster zone (or the default zone ifnetwork.zoneis not specified).networkDevices[].ipPoolRefadds additional addresses from the listed pools.
If both are configured on the same NIC, that NIC will receive multiple addresses (one for each configured pool reference).
apiVersion: infrastructure.cluster.x-k8s.io/v1alpha2 kind: ProxmoxMachineTemplate metadata: name: "test-control-plane" spec: template: spec: network: networkDevices: - name: net0 bridge: ${BRIDGE} defaultIPv4: true ipPoolRef: - apiGroup: ipam.cluster.x-k8s.io kind: GlobalInClusterIPPool name: shared-inclusterippoolAutomatic conversion of existing cluster resources
mainCAPMOX v0.8 uses a conversion webhook to support both
v1alpha1andv1alpha2.- Automatic etcd conversion: Resources already stored in the cluster (etcd) are converted to
v1alpha2automatically upon upgrade. - Storage Version:
v1alpha2is the internal storage version. You can still read resources via thev1alpha1API, but all new writes should targetv1alpha2. - Lossy Conversions: Some
v1alpha2-only fields (e.g.,zoneConfigs, per-devicedefaultIPv4/defaultIPv6) have nov1alpha1equivalent. If reading viav1alpha1, these fields will be absent, though the provider preserves them via annotations during round-trips. - Status Changes:
FailureReasonandFailureMessageon status objects are removed inv1alpha2to comply with the Cluster API v1beta2 contract, which uses structured conditions instead.
- Automatic etcd conversion: Resources already stored in the cluster (etcd) are converted to
Understand breaking changes in CAPMOX v0.8 (v1alpha2)
mainUpgrading to v0.8 introduces several breaking changes that require manual updates to your YAML manifests, Helm charts, or GitOps templates. While existing resources in the cluster are converted automatically via a webhook, your source files must be updated.
Key Breaking Changes
Change Impact API version v1alpha1→v1alpha2All CAPMOX resources Cluster API v1beta1→v1beta2All Cluster, KubeadmControlPlane, MachineDeployment, KubeadmConfigTemplate resources Unsigned integer fields → signed integers All CAPMOX resources with numeric fields Network: default+additionalDevices→networkDeviceslistProxmoxMachineTemplate IP pool refs: ipv4PoolRef/ipv6PoolRef→ipPoolReflistProxmoxMachineTemplate kubeletExtraArgsformat changed from map to name/value listKubeadmControlPlane, KubeadmConfigTemplate CloneSpecremoved from ProxmoxClusterProxmoxCluster machineTemplate.infrastructureRefmoved intomachineTemplate.specKubeadmControlPlane Use Tag-based Template Selection
mainCAPMOX can look up Proxmox VM templates using tags instead of explicit IDs. This is managed via the
TemplateSelectoron theProxmoxMachineresource.Resolution Policies:
exact(default): The template's tags must be an exact 1:1 match with the requestedmatchTags.subset: The template's tags must contain all of thematchTags, but can include additional tags.
Integration with ClusterClass: When using a
ClusterClass, you can drive selection via thespec.topology.variables.templateSelectorfield on theClusterresource. If set, the ClusterClass injects the selector into allProxmoxMachineTemplateresources and ignoressourceNode/templateID.Use Cluster Templates and Flavors
mainCAPMOX provides several templates (flavors) for different use cases. Some flavors, like
ciliumandcalico, require creatingConfigMapscontainingClusterResourceSet(CRS) files before deployment to enable CNI.| Flavor | Template File | CRS File | |---------------------|----------------------------------------------|-----------------------------------------| | cilium | templates/cluster-template-cilium.yaml | templates/crs/cni/cilium.yaml | | calico | templates/cluster-template-calico.yaml | templates/crs/cni/calico.yaml | | multiple-vlans | templates/cluster-template-multiple-vlans.yaml | - | | default | templates/cluster-template.yaml | - | | cilium loadbalancer | templates/cluster-template-cilium-load-balancer.yaml | templates/crs/cni/cilium.yaml, templates/crs/metallb.yaml | | external-creds | templates/cluster-template-external-creds.yaml | - | | flatcar | templates/cluster-template-flatcar.yaml | - |Set up a CAPMOX development environment with Tilt
mainTo develop CAPMOX using Tilt, you must set up a specific directory structure containing the Cluster API ecosystem repositories. Tilt manages the orchestration of these components.
Prerequisites
- Required Tools:
git,make,Go,Docker,Tilt,kubectl,kind,clusterctl. - Proxmox Access: A running Proxmox VE instance and an API token.
Setup Steps
Clone Repositories: Create a parent directory and clone the following into it:
cluster-api(This will be your working directory for Tilt)cluster-api-ipam-provider-in-clustercluster-api-provider-proxmox
Configure Tilt: Inside the
cluster-apidirectory, create atilt-settings.jsonfile:{ "default_registry": "ghcr.io/ionos-cloud", "provider_repos": ["../cluster-api-provider-proxmox/", "../cluster-api-ipam-provider-in-cluster/"], "enable_providers": ["ipam-in-cluster", "proxmox", "kubeadm-bootstrap", "kubeadm-control-plane"], "allowed_contexts": ["minikube"], "kustomize_substitutions": {}, "extra_args": { "proxmox": ["--v=4"] }, "debug": { "proxmox": { "port": 30000 } } }Note: The
debugsection enables a Delve remote debugger on port 30000. To use it, run:kubectl port-forward deployments/capmox-controller-manager 30000:30000 -n capmox-system.Configure Proxmox Environment Variables:
- Copy
../cluster-api-provider-proxmox/envfile.exampleto../cluster-api-provider-proxmox/envfile. - Populate it with your Proxmox credentials (refer to
Usage.md#environment-variables). - If using a specific
kindcluster name, addCAPI_KIND_CLUSTER_NAME=<yourclustername>to this file.
- Copy
Launch: From the
cluster-apidirectory, run:. ../cluster-api-provider-proxmox/envfile && tilt up
. ../cluster-api-provider-proxmox/envfile && tilt up- Required Tools:
Resolve node deployment failures with mixed interface models
mainKubelet selects the first interface to acquire a
node-ipbased on the in-kernel order (determined by PCI bus scan order and driver loading). If you have mixed interface types (e.g.,virtioande1000), the wrong interface might be chosen.Example Scenario: If
e1000interfaces are detected beforevirtiointerfaces, they will be assigned lower index numbers (e.g.,eth0), causing Kubelet to pick them as the primary interface.Fix: If you must use mixed interface types, ensure the intended default network interface is the one that appears first in the kernel/PCI scan order.
Configure LoadBalancer nodes with BGP
mainThe
cilium-load-balancerflavor provides specialized nodes for load balancing. These nodes feature an extra network card connected to BGP receiving switches. All services of typeLoadBalancerwill use IPs fromMETALLB_IPV4_RANGEorMETALLB_IPV6_RANGE, which are announced via BGP.Technical Requirements:
- Routing: Uses source IP-based routing. This requires all nodes to be created with
ipvsinkube-proxyandstrictARPenabled to prevent reverse path filter issues. - Immutability: If you need to change
METALLB_IPV{4,6}_RANGEafter deployment, you must redeploy the load balancer nodes because these variables are used during bootstrap for routing. - Node Behavior: LoadBalancer nodes are tainted to ensure only load-balancing pods run on them.
# Example environment variables for BGP LoadBalancer setup export LOAD_BALANCER_MACHINE_COUNT=2 export EXT_SERVICE_BRIDGE="vmbr2" export LB_BGP_IPV4_RANGES="[172.16.4.10-172.16.4.20]" export LB_BGP_IPV4_PREFIX="24" export METALLB_IPV4_ASN="65400" export METALLB_IPV4_BGP_PEER="172.16.4.1" export METALLB_IPV4_BGP_PEER2="172.16.4.2" export METALLB_IPV4_BGP_PEER_ASN="65500" export METALLB_IPV4_RANGE="7.6.5.0/24" # Generate the cluster clusterctl generate cluster test-bgp-lb \\ --infrastructure proxmox \\ --kubernetes-version v1.34.8 \\ --control-plane-machine-count=1 \\ --worker-machine-count=2 \\ --flavor=cilium-load-balancer > cluster.yaml- Routing: Uses source IP-based routing. This requires all nodes to be created with
Update CAPI v1beta2 kubeletExtraArgs and infrastructureRef
mainWhen upgrading to Cluster API (CAPI) v1beta2, two structural changes are required in your
KubeadmControlPlaneorKubeadmConfigTemplateresources:kubeletExtraArgs: This field has changed from a flat map to a list of name/value pairs. This applies toinitConfiguration,joinConfiguration, and other locations where it appears.infrastructureRef: This field has moved one level deeper, undermachineTemplate.spec. Additionally, theapiVersionfield is replaced byapiGroupin all resource references.
Example Changes
kubeletExtraArgs:
# v1beta1 kubeletExtraArgs: provider-id: "proxmox://..." # v1beta2 kubeletExtraArgs: - name: provider-id value: "proxmox://..."infrastructureRef:
# v1beta1 spec: machineTemplate: infrastructureRef: kind: ProxmoxMachineTemplate apiVersion: infrastructure.cluster.x-k8s.io/v1alpha1 name: my-cluster-control-plane # v1beta2 spec: machineTemplate: spec: infrastructureRef: kind: ProxmoxMachineTemplate apiGroup: infrastructure.cluster.x-k8s.io name: my-cluster-control-planeProvision a cluster with External Credentials
mainThe
external-credsflavor allows you to use different Proxmox Datacenters by referencing a Kubernetes Secret instead of using environment variables directly in the manifest. The secret must include a labelplatform.ionos.com/secret-type: "proxmox-credentials".apiVersion: infrastructure.cluster.x-k8s.io/v1alpha2 kind: ProxmoxCluster metadata: name: "my-cluster" spec: controlPlaneEndpoint: host: ${CONTROL_PLANE_ENDPOINT_IP} port: 6443 # ... credentialsRef: name: "my-cluster-proxmox-credentials" --- apiVersion: v1 kind: Secret metadata: name: my-cluster-proxmox-credentials labels: platform.ionos.com/secret-type: "proxmox-credentials" stringData: secret: ${PROXMOX_SECRET} token: ${PROXMOX_TOKEN} url: ${PROXMOX_URL}Dependencies for CAPMOX
mainTo deploy a Kubernetes cluster using the Cluster API Provider for Proxmox VE (CAPMOX), you must satisfy the following requirements:
- Proxmox VE Template: Required for cluster creation. You can build these using:
- Proxmox VE builder (recommended).
- image-builder.
- Building Raw Images.
- clusterctl: The Cluster API CLI, available via CAPI releases.
- Management Cluster: A running Kubernetes cluster to host the CAPMOX controller.
- Proxmox VE Bridge: A configured bridge (e.g.,
vmbr0) with an available IP range for the VMs. - IPAM Provider: The cluster-api provider IPAM
in-clusteris required to manage IPv4 and/or IPv6 addresses for machines without DHCP and to support dual-stack setups.
- Proxmox VE Template: Required for cluster creation. You can build these using: