Cilium’s IP Address Management (IPAM) mode is the unsung hero that determines how your Kubernetes cluster gets IP addresses for its pods. The most surprising thing about these modes is that picking the wrong one isn’t usually a catastrophic failure, but a slow, insidious drain on your cluster’s scalability and efficiency, often manifesting as subtle performance issues or an inability to grow beyond a certain size.

Let’s see Cilium IPAM in action. Imagine a simple cluster with two nodes, node-a and node-b, and a few pods running.

# On node-a:
kubectl get pods -o wide
# NAME     READY   STATUS    RESTARTS   AGE   IP              NODE        NOMINATED NODE   READINESS GATES
# pod-a1   1/1     Running   0          10m   10.0.0.10       node-a      <none>           <none>
# pod-a2   1/1     Running   0          5m    10.0.0.11       node-a      <none>           <none>

# On node-b:
kubectl get pods -o wide
# NAME     READY   STATUS    RESTARTS   AGE   IP              NODE        NOMINATED NODE   READINESS GATES
# pod-b1   1/1     Running   0          8m    10.0.0.20       node-b      <none>           <none>
# pod-b2   1/1     Running   0          3m    10.0.0.21       node-b      <none>           <none>

In this output, the IP column shows the addresses assigned to the pods. The magic of how these addresses are generated and managed is dictated by the IPAM mode.

Cilium offers three primary IPAM modes:

  1. Cluster-Pool (Default): This is the most common and often the best starting point. Cilium manages a pool of IP addresses for the entire cluster. When a pod needs an IP, Cilium assigns one from this central pool. This mode is flexible and works well for most general-purpose clusters.
  2. Node-Local: In this mode, each Kubernetes node is responsible for managing its own local pool of IP addresses. When a pod starts on a node, that node assigns an IP from its own pool. This can reduce contention on the central IPAM controller but requires careful management of the subnet sizes for each node.
  3. Kubernetes (Host-Local): This mode leverages Kubernetes’ built-in IPAM for Pods. It essentially delegates IP address assignment to the Kubernetes API server itself, using the ipam.kubernetes.io/address annotation on Pods. This is often used when integrating Cilium with existing CNI plugins or specific network configurations where Kubernetes is already handling IP allocation.

The problem Cilium IPAM solves is fundamental: every pod needs a unique IP address within the cluster’s network for direct communication. Without a robust IPAM strategy, you’d face issues like:

  • IP Address Exhaustion: Running out of available IPs, preventing new pods from starting.
  • IP Address Collisions: Assigning the same IP to multiple pods, leading to unpredictable network behavior.
  • Scalability Bottlenecks: The IPAM mechanism itself becoming a bottleneck as the cluster grows.

Let’s look at the configuration. You typically set the IPAM mode in your Cilium configuration, often via a CiliumConfig custom resource or Helm values.

For Cluster-Pool, you might see something like:

# Example CiliumConfig for Cluster-Pool
apiVersion: cilium.io/v2alpha1
kind: CiliumConfig
metadata:
  name: cilium-config
spec:
  ipam:
    mode: "cluster-pool"
  clusterPoolIPv4PodCIDR: "10.0.0.0/8"
  clusterPoolIPv4MaskSize: 24

Here, clusterPoolIPv4PodCIDR defines the overall IP range for pods, and clusterPoolIPv4MaskSize determines the subnet size allocated to each node (e.g., /24 means each node gets 256 IPs).

For Node-Local, the configuration shifts focus to node-specific allocation:

# Example CiliumConfig for Node-Local
apiVersion: cilium.io/v2alpha1
kind: CiliumConfig
metadata:
  name: cilium-config
spec:
  ipam:
    mode: "node-local"
  nodeLocalIPAM:
    # This is typically managed by a daemonset that allocates CIDRs to nodes
    # For demonstration, assume each node gets a /24 from a larger pool
    podCIDRMaskSize:
      - 24 # Each node gets a /24

In node-local mode, you often rely on a separate mechanism (like a daemonset or a custom controller) to allocate a CIDR range to each node, and then Cilium on that node uses that CIDR for its pods. The podCIDRMaskSize in the CiliumConfig specifies the size of the subnet each node will manage.

The Kubernetes (Host-Local) mode is configured like this:

# Example CiliumConfig for Kubernetes IPAM
apiVersion: cilium.io/v2alpha1
kind: CiliumConfig
metadata:
  name: cilium-config
spec:
  ipam:
    mode: "kubernetes"

When using this mode, you don’t typically specify clusterPoolIPv4PodCIDR or nodeLocalIPAM configurations in Cilium. Instead, you ensure your Kubernetes cluster is configured to allocate Pod CIDRs to nodes, and Cilium will respect those allocations.

The key levers you control with IPAM are the overall IP address space available for pods and how that space is divided and managed. The clusterPoolIPv4MaskSize (or equivalent for node-local) is crucial: a smaller mask size (e.g., /24) gives each node more IPs but can lead to faster exhaustion of the overall cluster pool. A larger mask size (e.g., /28) conserves IPs but might require more careful planning if you have nodes with very high pod density.

A nuance many users overlook is how IPAM mode interacts with the underlying network infrastructure. If you’re using cluster-pool and your clusterPoolIPv4PodCIDR overlaps with your physical network or other cluster networks, you’ll have routing problems. Similarly, in node-local mode, the CIDRs allocated to each node must be unique and routable within your cluster. The kubernetes mode is less prone to this if your Kubernetes cluster itself is correctly configured with non-overlapping Pod CIDRs.

The next hurdle you’ll likely encounter is understanding how Cilium’s IPAM interacts with external network policies and service exposure.

Want structured learning?

Take the full Cilium course →