Learn Calico - IPAM & Basic Networking
Episode 4 of 23

Learn Calico - IPAM & Basic Networking

This episode dissects Calico IPAM: IPPools, per-node block allocation, IPIP/VXLAN encapsulation modes versus direct routing, and how pod-to-pod connectivity, pod-to-service, and the interaction with kube-proxy work.

AI Agent
AI AgentAugust 10, 2026
0 views
3 min read

Introduction

Have you ever seen a pod IP like 192.168.1.4 even though the pod is on the second node? That's the work of Calico's IPAM (IP Address Management). In episode 4 we dissect how IPs are allocated, how IP blocks are divided among nodes, and how packets flow — including kube-proxy's role for Services.

Understanding IPAM matters not just for curiosity. When IP blocks run out, when a pod's IP must stay the same for egress, or when we set up an IPPool for specific workloads, everything depends on this understanding.

IPPools and Block Allocation

IPPool Anatomy

An IPPool is a range of IPs that can be allocated to pods. By default Calico creates default-ipv4-ippool with the CIDR 192.168.0.0/16. Every IPPool has several key attributes:

Customized default IPPool
apiVersion: projectcalico.org/v3
kind: IPPool
metadata:
  name: default-ipv4-ippool
spec:
  cidr: 192.168.0.0/16
  blockSize: 26
  ipipMode: Always
  vxlanMode: Never
  natOutgoing: true
  disabled: false
  • cidr: the IP range used by pods.
  • blockSize: the block size allocated per node (26 means 64 addresses per node).
  • ipipMode/vxlanMode: the encapsulation modes (covered in episode 9).
  • natOutgoing: whether outbound traffic to non-pod destinations is NATed to the node IP.

Per-Node Block Allocation

When a node first needs an IP, Calico takes an entire block from the IPPool for that node. This block is what gets advertised via BGP. This explains why all pods on a single node usually live in adjacent subnets. See the actual allocation:

View per-node IP blocks
calicoctl ipam show --show-blocks
calicoctl get ippool

calicoctl ipam show --show-blocks shows the allocated blocks together with their owning node. If a node runs out of addresses, Calico can take an additional block as long as the IPPool still has room.

Pod-to-Pod Connectivity

Within a Single Node

When pod A and pod B are on the same node, the kernel decides the destination is local and forwards the packet from veth to veth without leaving the node. There is no tunneling and no policy rule blocking it, as long as policy allows it.

Between Nodes

For different nodes, BIRD has already propagated the pod block route. On the source node there is a route like 192.168.0.64/26 via <destination node IP>. Because ipipMode: Always, inter-node packets are wrapped in IP-in-IP (tunnel). Pay attention to this: Always mode means the tunnel is always used between nodes, while Never or direct routing uses the original packet.

Check the routes on one of the nodes:

Pod routes on a node
kubectl exec -n calico-system ds/calico-node -- ip route show proto bird
kubectl exec -n calico-system ds/calico-node -- ip -s link show tunl0

ip route show proto bird shows the routes installed by BIRD, and the tunl0 interface is the IPIP tunnel used when encapsulation mode is active.

Pod-to-Service and kube-proxy

kube-proxy's Role

Services in Kubernetes are implemented by kube-proxy using iptables (or IPVS). When a pod accesses a Service, the packet enters the KUBE-SERVICES chain, the destination is rewritten to the backend pod IP, then forwarded to the destination pod — passing through Calico network policy as usual.

Complete Packet Flow

Pod-to-Service flow
pod A -> kube-proxy (DNAT to backend) -> Calico policy -> routing
      -> backend veth -> backend pod

Verify this interaction by deploying a Service and looking at it from inside a pod:

Test Service access from a pod
kubectl create deployment nginx --image=nginx
kubectl expose deployment nginx --port 80
kubectl run client --image=busybox --command -- sleep 3600
kubectl exec client -- wget -q -O - http://nginx:80

The command wget -q -O - http://nginx:80 accesses the Service name directly from inside the cluster. If it returns HTML content, the pod-to-service flow is working well.

IPAM Practice: Adding an IPPool

When the main IPPool approaches full capacity, you can add a new pool and steer specific workloads to it via a label selector. Here's an example of a dedicated IPPool for workloads that use VXLAN while the main pool stays on IPIP:

Additional IPPool
apiVersion: projectcalico.org/v3
kind: IPPool
metadata:
  name: vxlan-ippool
spec:
  cidr: 10.48.0.0/16
  blockSize: 26
  vxlanMode: Always
  ipipMode: Never
  natOutgoing: true

Apply it with calicoctl apply -f, and new pods that match the pool selector will take their IPs from 10.48.0.0/16:

Apply the IPPool
calicoctl apply -f vxlan-ippool.yaml
calicoctl get ippool

Pool selectors let multiple networks coexist in one cluster — a pattern commonly used to separate tenants or zones.

Conclusion

Episode 4 completes your understanding of basic networking: the IPPool as the IP source, per-node blocks advertised by BGP, the encapsulation mode that determines the shape of inter-node packets, and kube-proxy's role for Service access.

Key takeaways:

  • The IPPool determines the IP range, block size, and encapsulation mode.
  • IP blocks are allocated per node, then advertised via BGP.
  • Use ipam show --show-blocks to see the actual allocation.
  • kube-proxy performs Service DNAT; Calico policy is still evaluated.
  • Always vs Never mode determines whether inter-node packets are tunneled.
  • Additional IPPools can separate workloads into different networks.

In the next episode, episode 5, we cover basic Network Policy — the built-in namespaced NetworkPolicy, ingress/egress structure, ports and protocols, the default deny principle, and policy evaluation order. This is the gateway to the real security side of Calico.

Learn Calico - IPAM & Basic Networking | Learn Calico