Deploy a self-managed Kubernetes cluster
This guide covers deploying a self-managed Kubernetes cluster on evroc: which components to install, in what order, and the settings that connect them. Each component's own README is the source of truth for its installation steps, configuration, and reference.
For an overview of the components, see Self-managed Kubernetes on evroc.
Prerequisites
Before you begin, you'll need:
- The
evrocCLI configured against your project, andkubectlon your workstation. - For the CAPI path: a management cluster with CAPE installed, so you have an evroc credentials secret and
clusterctlconfigured.
1. Provision the cluster
There are two ways to provision a self-managed cluster on evroc:
- Cluster API (CAPE) - the recommended path for production clusters. CAPE manages the full cluster lifecycle declaratively from a management cluster. Scaling, rolling upgrades, and rollouts are first-class operations: change a field on the
ClusterorMachineDeploymentresource and CAPE handles the rest: cordon/drain, VM replacement, and health checking. Follow the CAPE Quick Start. - Terraform - the evroc Terraform provider can provision VMs and networking. The k3s-cluster example boots a small k3s cluster directly. This is best suited to small, throwaway test clusters where you don't need the lifecycle management CAPE provides. Terraform provisions infrastructure but doesn't manage the in-cluster lifecycle: scaling out means manually adding VM resources and bootstrapping nodes, upgrades mean replacing VMs and re-running
kubeadm/k3syourself, and rollouts are manual.
2. CAPI: set cloud-provider=external
When using CAPI, one setting is required for the evroc CCM to manage nodes: every kubelet must run with --cloud-provider=external, so the CCM (not the distribution's built-in cloud controller) initializes nodes. Add it to kubeletExtraArgs in both the control-plane and worker bootstrap configs:
spec:
kubeadmConfigSpec:
initConfiguration:
nodeRegistration:
kubeletExtraArgs:
- name: cloud-provider
value: external
joinConfiguration:
nodeRegistration:
kubeletExtraArgs:
- name: cloud-provider
value: external
Important: Without
--cloud-provider=external, the distribution's own cloud controller initializes nodes first and the CCM is never consulted. On k3s and RKE2 (including the Terraform k3s example), setdisable-cloud-controller: trueandkubelet-arg: ["cloud-provider=external"]instead.
Apply the cluster and wait for the machines to reach Running:
kubectl get machines -w
At this point nodes are NotReady because no CNI is installed. They also carry the node.cloudprovider.kubernetes.io/uninitialized taint, which stays until the CCM initializes them.
3. Install a CNI
Install a CNI, such as Cilium CNI. Most CNIs, including Cilium and Calico tolerate the node.cloudprovider.kubernetes.io/uninitialized taint, so their agent runs on nodes before the CCM has initialized them. This is required, since pods need a CNI to communicate and the CCM itself runs as pods.
For example, with Cilium run
clusterctl get kubeconfig <cluster-name> > <cluster-name>.kubeconfig
cilium install --kubeconfig <cluster-name>.kubeconfig --set ipam.operator.clusterPoolIPv4PodCIDRList=192.168.0.0/16
Note: The CAPE
defaultandprebuiltflavors install Cilium automatically viapostKubeadmCommands, so this step is only needed for custom templates without a built-in CNI.
Note: Cilium by default uses a
clusterPoolIPv4PodCIDRListvalue of10.0.0.0/8for IPAM within a Kubernetes cluster, which can often overlap with IPv4 address in your evroc cloud, so we recommend using192.168.0.0/16or another Private IPv4 range.
Nodes remain NotReady and carry the uninitialized taint until the CCM runs.
4. Install the CCM
Follow the CCM Quickstart to create the kubernetesCCMAgent service account, build the config secret, and install the Helm chart into your Kubernetes cluster.
The CCM must be installed after the CNI, because it runs as pods that need a working network, and before the CSI driver, because the CSI driver requires the topology.kubernetes.io/zone node labels the CCM sets.
Once the CCM is running, it initializes each node: setting the provider ID, adding topology labels, syncing addresses, and removing the node.cloudprovider.kubernetes.io/uninitialized taint. Verify:
kubectl --kubeconfig <cluster-name>.kubeconfig get nodes \
-o custom-columns='NAME:.metadata.name,READY:.status.conditions[-1].type,REGION:.metadata.labels.topology\.kubernetes\.io/region,ZONE:.metadata.labels.topology\.kubernetes\.io/zone'
When all nodes are Ready with region and zone labels, continue to the CSI driver.
5. Install the CSI driver
Follow the CSI driver README to create the kubernetesCSIAgent service account, build the config secret, and install the Helm chart into your Kubernetes cluster.
The CSI driver requires the topology.kubernetes.io/zone node label for topology-aware volume placement, so it must be installed after the CCM has initialized the nodes. To make evroc-standard the cluster's default StorageClass, pass --set storageClass.isDefault=true when installing the chart.
What your cluster can do now
Your cluster is integrated with the evroc cloud platform. You can deploy workloads and:
- Create
PersistentVolumeClaims - the CSI driver provisions evroc Disks automatically. - Create
type: LoadBalancerServices - the CCM provisions evroc load balancers and public IPs automatically.
Next steps
- Cluster API for evroc - Provision and manage Kubernetes clusters
- evroc CSI driver - Persistent block storage for Kubernetes
- evroc Cloud Controller Manager - Load balancers, public IPs, and node lifecycle