This provider supports a tested addon flow for unmanaged STACKIT workload clusters:
cloud-provider-stackitis rendered into the workload cluster by the cluster template through a Cluster APIClusterResourceSet.- The CNI is installed after the workload API server is reachable.
- The default tested CNI path uses Cilium with the checked-in values in
templates/addons/cilium-values.yaml.
This split is intentional. The cloud provider must run early so Kubernetes Nodes get STACKIT provider IDs and the external cloud-provider taint is cleared. The CNI is a cluster operator choice because routing, network policy, MTU, IPAM, and upgrade strategy are environment-specific.
The classic and topology cluster templates include a
stackit-workload-cloud-provider-stackit ClusterResourceSet and Secret. The
resource set applies templates/addons/cloud-provider-stackit.yaml into the
workload cluster.
The addon template installs:
- the
stackit-cloud-controller-managerServiceAccount, RBAC, ConfigMap, Secret, and Deployment inkube-system - the
--cloud-provider=stackitcontroller configuration - the
cloud-node-controller,cloud-node-lifecycle-controller, andservice-lb-controller - tolerations required to run before Nodes are initialized
The kubeadm templates configure the control plane and kubelets for an external
cloud provider. When cloud-provider-stackit is healthy, it sets STACKIT
provider IDs on Nodes and removes the
node.cloudprovider.kubernetes.io/uninitialized taint.
Before creating the cluster, ensure the management cluster has
ClusterResourceSet enabled. The local clusterctl configuration in
hack/clusterctl-local.yaml enables it with CLUSTER_RESOURCE_SET=true.
Set the cloud provider inputs before rendering the template:
export STACKIT_SERVICE_ACCOUNT_JSON_FILE=./.stackit/cluster-api-provider-stackit-serviceaccount.json
export STACKIT_SERVICE_ACCOUNT_JSON_B64="$(base64 < "${STACKIT_SERVICE_ACCOUNT_JSON_FILE}" | tr -d '\n')"
export STACKIT_CLOUD_CONTROLLER_MANAGER_IMAGE="ghcr.io/stackitcloud/cloud-provider-stackit:<version>"The cloud-provider image minor version must match the Kubernetes minor version of the workload cluster. Use the version helper before rendering:
hack/validate-stackit-versions.shAfter the workload API server is reachable, retrieve the kubeconfig:
clusterctl get kubeconfig "${CLUSTER_NAME}" \
--namespace "${NAMESPACE}" \
> "${CLUSTER_NAME}.kubeconfig"Install the default tested Cilium CNI:
make install-workload-cni \
WORKLOAD_KUBECONFIG="${CLUSTER_NAME}.kubeconfig"The helper waits for the Cilium operator, Cilium DaemonSet, and Cilium Envoy DaemonSet when present.
To install Calico instead:
make install-workload-cni \
WORKLOAD_KUBECONFIG="${CLUSTER_NAME}.kubeconfig" \
STACKIT_WORKLOAD_CNI=calicoTo apply a custom CNI manifest:
make install-workload-cni \
WORKLOAD_KUBECONFIG="${CLUSTER_NAME}.kubeconfig" \
CNI_MANIFEST=./my-cni.yamlCustom manifests are applied as-is. The helper cannot know which workload resources prove that an arbitrary CNI is healthy, so custom CNI users must wait for their own rollout resources.
Verify that the cloud provider Deployment rolled out:
kubectl --kubeconfig "${CLUSTER_NAME}.kubeconfig" \
-n kube-system rollout status deployment/stackit-cloud-controller-manager \
--timeout=5mVerify Cilium rollout for the default path:
kubectl --kubeconfig "${CLUSTER_NAME}.kubeconfig" \
-n kube-system rollout status deployment/cilium-operator --timeout=10m
kubectl --kubeconfig "${CLUSTER_NAME}.kubeconfig" \
-n kube-system rollout status daemonset/cilium --timeout=10m
kubectl --kubeconfig "${CLUSTER_NAME}.kubeconfig" \
-n kube-system rollout status daemonset/cilium-envoy --timeout=10mVerify Nodes are Ready and have STACKIT provider IDs:
kubectl --kubeconfig "${CLUSTER_NAME}.kubeconfig" get nodes
kubectl --kubeconfig "${CLUSTER_NAME}.kubeconfig" \
get nodes \
-o custom-columns=NAME:.metadata.name,PROVIDER_ID:.spec.providerIDVerify the external cloud-provider taint is gone:
kubectl --kubeconfig "${CLUSTER_NAME}.kubeconfig" \
get nodes -o json \
| jq -e '[.items[].spec.taints[]? | select(.key == "node.cloudprovider.kubernetes.io/uninitialized")] | length == 0'Verify CAPI Machines and workload Nodes agree on STACKIT provider IDs:
kubectl -n "${NAMESPACE}" \
get machines,stackitmachines \
-l "cluster.x-k8s.io/cluster-name=${CLUSTER_NAME}" \
-o custom-columns=KIND:.kind,NAME:.metadata.name,PROVIDER_ID:.spec.providerID,NODE:.status.nodeRef.name
kubectl --kubeconfig "${CLUSTER_NAME}.kubeconfig" \
get nodes \
-o custom-columns=NAME:.metadata.name,PROVIDER_ID:.spec.providerIDThe e2e workload tests validate this flow by waiting for the embedded
cloud-provider-stackit rollout, installing CNI, waiting for Ready Nodes,
checking the external cloud-provider taint is removed, and verifying CAPI
Machine, StackitMachine, and Node provider IDs align.
ClusterResourceSet is useful for static bootstrap addons such as this tested
cloud-provider installation, but it is not a full addon lifecycle manager. For
production CNI management, prefer Helm, GitOps, or a Cluster API addon provider
that handles upgrades, rollback, and drift reconciliation.