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.

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.
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:
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: falsecidr: 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.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:
calicoctl ipam show --show-blocks
calicoctl get ippoolcalicoctl 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.
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.
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:
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 tunl0ip route show proto bird shows the routes installed by BIRD, and the tunl0 interface is the IPIP tunnel used when encapsulation mode is active.
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.
pod A -> kube-proxy (DNAT to backend) -> Calico policy -> routing
-> backend veth -> backend podVerify this interaction by deploying a Service and looking at it from inside 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:80The 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.
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:
apiVersion: projectcalico.org/v3
kind: IPPool
metadata:
name: vxlan-ippool
spec:
cidr: 10.48.0.0/16
blockSize: 26
vxlanMode: Always
ipipMode: Never
natOutgoing: trueApply it with calicoctl apply -f, and new pods that match the pool selector will take their IPs from 10.48.0.0/16:
calicoctl apply -f vxlan-ippool.yaml
calicoctl get ippoolPool selectors let multiple networks coexist in one cluster — a pattern commonly used to separate tenants or zones.
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:
ipam show --show-blocks to see the actual allocation.Always vs Never mode determines whether inter-node packets are tunneled.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.