Cilium Cilium

Set Up a Cluster for Cilium: Disable the Default CNI First

Cilium replaces your cluster's networking entirely, which means the order of operations matters more than with most add-ons.

12 min Beginner

Most Kubernetes add-ons install into an already-functioning cluster. Cilium is different: as a CNI, it is the cluster’s networking, which means a cluster has to be created without a default CNI already claiming that role, or Cilium has nothing to actually take over. This guide covers that sequencing, using a local kind cluster, then installing Cilium with Helm.

Why order matters here

A Kubernetes cluster normally comes up with some CNI already installed and managing Pod networking, kindnet on kind, or a cloud provider’s own default. If Cilium is installed on top of an already-active CNI, you end up with two networking plugins both trying to own the same job, which doesn’t work. Cilium has to be the only CNI, which means disabling whatever default would otherwise claim that role before Cilium is installed, not after.

Create a cluster with the default CNI disabled

On kind, this is a cluster configuration setting, not something you disable after the fact:

# kind-config.yaml
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
networking:
  disableDefaultCNI: true
nodes:
  - role: control-plane
    extraPortMappings:
      - containerPort: 30080
        hostPort: 80
      - containerPort: 30443
        hostPort: 443
  - role: worker
kind create cluster --config kind-config.yaml
kubectl get nodes

Expect every node to show NotReady. That’s expected, not a failure: with no CNI installed yet, nodes can’t be marked ready. The extraPortMappings here aren’t required for a basic install; they’re set up in advance for later guides in this series that expose services externally through kind, which has no cloud load balancer to hand out routable addresses on its own.

If you’re on a managed cloud Kubernetes service rather than a local cluster, check that provider’s own documentation for how to create a cluster without its default CNI; the mechanism differs by provider, but the underlying requirement, no CNI claiming the role before Cilium installs, is the same everywhere.

Install the Gateway API CRDs before Cilium, if you’ll use Gateway API

If you plan to use Kubernetes Gateway API with Cilium (covered in the next guide), install its CustomResourceDefinitions now, before enabling Gateway API support in Cilium’s own install. Cilium’s Gateway API controller expects those CRDs (GatewayClass, Gateway, HTTPRoute, and related types) to already exist in the cluster:

kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.4.1/standard-install.yaml

Pin to a specific Gateway API release rather than always pulling the newest one. Gateway API moves faster than every implementation can track, and Cilium’s own release notes specify which Gateway API version a given Cilium release has actually been tested against; using a newer CRD version than Cilium supports is a realistic source of confusing errors that have nothing to do with your own configuration.

Install Cilium with Helm

helm repo add cilium https://helm.cilium.io
helm repo update
helm show values cilium/cilium --version 1.19.0 > cilium-values.yaml

Reviewing the full default values file before installing is worth the few minutes it takes; it’s long, but it’s the authoritative list of what’s configurable. For a cluster where you’ll also use Gateway API, the settings that matter most:

# cilium-values.yaml (relevant excerpt)
kubeProxyReplacement: true

gatewayAPI:
  enabled: true
  gatewayClass:
    create: false   # create your own GatewayClass explicitly, covered in the next guide

hubble:
  enabled: true
  relay:
    enabled: true
  ui:
    enabled: true

kubeProxyReplacement: true has Cilium take over Service routing entirely, in eBPF, as covered in the previous guide, rather than running alongside kube-proxy. Setting gatewayClass.create to false is a deliberate choice, not a default you have to keep: it means you create and own the GatewayClass resource yourself (useful if you’re managing it through a GitOps tool like Argo CD or Flux, so it’s tracked the same way as the rest of your configuration) rather than letting the Helm chart create one implicitly. Enabling Hubble and its UI here gets you the observability tooling referenced throughout this series, though it isn’t required for Gateway API or BGP to function on their own.

helm install cilium cilium/cilium \
  --version 1.19.0 \
  --namespace kube-system \
  -f cilium-values.yaml

Confirm the install

kubectl get pods -n kube-system -l k8s-app=cilium
kubectl get nodes

Cilium’s Pods should reach Running, and once they do, the nodes that were NotReady immediately after cluster creation should flip to Ready, nothing else needs to happen for that transition; it’s Cilium’s own agent coming up on each node that unblocks it.

A note on what you can safely change later

kubeProxyReplacement and which CNI is installed are the kind of settings worth getting right at install time; changing them on a live cluster is disruptive and not something to casually experiment with. Most other values, resource limits, which features are enabled, Hubble configuration, can be adjusted later with helm upgrade against the same values file without that same level of caution.

Popular Guides