Pod networking and CNI
How Pods get IP addresses and reach each other, the two address ranges of a cluster, and how to test a connection.
Key ideas in this lesson · tap one for a simple explanation
What you will be able to do
- State the three rules of the Kubernetes network model, and say which part makes each one work.
- Read the Pod and Service ranges from the control plane, and tell them apart from a node's podCIDR.
- Find any Pod's IP and node, then test Pod-to-Pod traffic from a temporary client Pod.
Every in a cluster gets its own IP address, and any Pod can reach any other Pod at that address. This lesson shows who hands out those addresses, how traffic travels between , and how to test it. The exam calls this Understand connectivity between Pods. It is rarely a task on its own, but every , and troubleshooting question builds on it.
The network model in three rules
Kubernetes sets three rules for the network. Every cluster must follow them.
- Every Pod gets its own IP address. All in one Pod share it, and they reach each other on
localhost. So two containers in one Pod cannot both use port 8080. - Any Pod can reach any other Pod at its real IP. A Pod on
cka-workercalls a Pod oncka-worker2directly. No address is rewritten on the way (no NAT), so the receiver sees the caller's real IP. - Programs on a node can reach every Pod on that node. That is how the runs liveness and .
CNI plugin and kube-proxy: two parts, two jobs
Kubernetes only writes these rules down. Two other parts make them work, and their jobs are easy to mix up:
So Pod-to-Pod is the CNI plugin, and Pod-to-Service is kube-proxy. Other CNI plugins you may meet are Cilium and Flannel. This lesson covers the CNI side; Services covers kube-proxy.
Two address ranges: Pod CIDR and Service CIDR
Every cluster has two separate ranges of IP addresses. Pods get their addresses from one, Services from the other. A range is written as a CIDR: 10.244.0.0/16 means every address that starts with 10.244..
Pod CIDR
Pod IPs, handed out by the CNI plugin
10.244.0.0/16
Service CIDR
Service IPs, handed out by the API server
10.96.0.0/16
The two ranges never overlap. Pod addresses are real; a Service address is virtual and sits on no network interface.
# Node shell. Lab: docker exec. Exam: ssh <control-plane-node>, then sudo -i if needed.
docker exec cka-control-plane grep -- --cluster-cidr /etc/kubernetes/manifests/kube-controller-manager.yaml
docker exec cka-control-plane grep -- --service-cluster-ip-range /etc/kubernetes/manifests/kube-apiserver.yaml
# Each node's own slice of the Pod range (not the cluster's Pod CIDR)
kubectl get nodes -o custom-columns=NAME:.metadata.name,PODCIDR:.spec.podCIDRNo node shell? The same flags are visible through the API too, as Control plane and node components shows.
How the CNI plugin connects a Pod
When a new Pod starts on a node, the calls the CNI plugin. The plugin does three jobs:
- 1.It plugs the Pod in. It creates a veth pair: a virtual network cable with two ends. One end becomes
eth0inside the Pod. The other end stays on the node; with Calico its name starts withcali. - 2.It picks an address. Its IPAM part (IP address management) takes a free IP from the pool. The plugin gives the Pod that IP, and adds a route on the node that points to the veth.
- 3.It connects the nodes. It adds routes to the other nodes' Pod blocks. Calico here uses an IP-in-IP tunnel; many other setups use VXLAN. Both wrap the Pod's packet inside a packet between the two nodes.
Pod A
on cka-worker
10.244.89.67
Node cka-worker
the veth carries the packet out; a route sends it to the other node
Node cka-worker2
a route hands it to Pod B's veth
Pod B
sees Pod A's real IP
10.244.157.130
The CNI plugin builds every step: the veth pair into each Pod, and the routes between the nodes.
When the Pod is deleted, the plugin frees its IP again. CNI, CSI and CRI shows where the plugin's files live on the node, and why a node without them stays NotReady.
docker exec -it cka-worker bash # exam: ssh <node>
ip -br link | grep cali # host ends of the veth pairs, one per local Pod
ip route # one /32 per local Pod, one route per remote node's block
# 10.244.89.67 dev caliad73dda8ffa scope link (a local Pod)
# 10.244.157.128/26 via 172.19.0.3 dev tunl0 onlink (another node's block, IP-in-IP)Find a Pod, then reach it
Most networking tasks start with three facts about a Pod: its name, its IP and its node. These commands print them.
kubectl get pods -o wide # IP and NODE columns
kubectl get pod web-0 -o jsonpath='{.status.podIP}{"\n"}'
kubectl get pod web-0 -o jsonpath='{.spec.nodeName}{"\n"}'
kubectl get pods -l tier=cache -o custom-columns=NAME:.metadata.name,IP:.status.podIP,NODE:.spec.nodeName
# A Pod IP is not stable. Delete the Pod and its replacement gets a new one,
# which is the whole reason Services exist.To test a connection, start a small client Pod and call the other Pod's IP from inside it. busybox:1.36 makes a good client: it is tiny, and it has wget and nslookup.
# Interactive: the one-liner you will type on the exam.
# --rm deletes the Pod afterwards; -T 3 stops wget waiting forever on a blocked port.
kubectl run tmp --image=busybox:1.36 --rm -it --restart=Never -- wget -qO- -T 3 http://10.244.89.67:8080/hostname
# Non-interactive (scripts, repeated checks): a long-lived client, then exec
kubectl run client --image=busybox:1.36 --restart=Never -- sleep 3600
kubectl wait --for=condition=Ready pod/client --timeout=60s
kubectl exec client -- wget -qO- -T 3 http://10.244.89.67:8080/hostname
kubectl delete pod client --nowIn the official docs· open on exam day too
- Cluster Networkingsearch: cluster networking
- Network Pluginssearch: network plugins cni
- Virtual IPs and Service Proxiessearch: kube-proxy mode
- Services, Load Balancing, and Networkingsearch: kubernetes network model
Record the Pod and Service address ranges
/tmp/cka/pod-cidr.txt. Find the range Service ClusterIPs are allocated from and write it to /tmp/cka/service-cidr.txt. Each file must contain only the CIDR.Cluster:kubectl config use-context kind-cka
- 1
Set up the scenario
curl -fsSL https://codewithmuh.com/labs/cka/t/nw-cni-1/setup | bash - 2
Solve it in your terminal
Use kubectl and the Kubernetes docs, like on exam day. Save any answer files under
/tmp/cka/. - 3
Check your work
curl -fsSL https://codewithmuh.com/labs/cka/t/nw-cni-1/verify | bashGot FAIL? Read which check failed, fix it, run it again. - 4
Clean up (optional)
curl -fsSL https://codewithmuh.com/labs/cka/t/nw-cni-1/cleanup | bash
Locate a Pod and reach it by IP
nw-cni. For the Pod labeled tier=cache: write its Pod IP to /tmp/cka/cache-ip.txt and the name of the node it runs on to /tmp/cka/cache-node.txt. Then, from a temporary Pod using image busybox:1.36 in the same namespace, request http://<that IP>:8080/hostname and save the response body to /tmp/cka/cache-hostname.txt. Remove the temporary Pod afterwards.Cluster:kubectl config use-context kind-cka
- 1
Set up the scenario
curl -fsSL https://codewithmuh.com/labs/cka/t/nw-cni-2/setup | bash - 2
Solve it in your terminal
Use kubectl and the Kubernetes docs, like on exam day. Save any answer files under
/tmp/cka/. - 3
Check your work
curl -fsSL https://codewithmuh.com/labs/cka/t/nw-cni-2/verify | bashGot FAIL? Read which check failed, fix it, run it again. - 4
Clean up (optional)
curl -fsSL https://codewithmuh.com/labs/cka/t/nw-cni-2/cleanup | bash
Finished this lesson?
0 of 2 tasks passed. Your readiness counts tasks, so run them before you move on.