Networking, CNI, Services and DNS

Networking, CNI, Services and DNS

The Kubernetes network model

Three rules, implemented by the CNI plugin:

  1. Every Pod gets its own IP.
  2. Every Pod reaches every other Pod - on any node - without NAT.
  3. Agents on a node reach all Pods on that node.

Nothing else is promised: how packets travel is the CNI’s choice.

CNI: overlays and routing

graph LR subgraph worker01 PA[Pod 10.244.1.5] end subgraph worker02 PB[Pod 10.244.2.7] end PA -->|"encapsulated in node-to-node packet<br/>(VXLAN / IP-in-IP)"| PB
ModeHowTrade-off
Overlay - VXLAN, IP-in-IPPod packet wrapped in a node packetworks on any network; small overhead
Native routing - BGPnodes announce Pod routes to each other / the routerno overhead; network must cooperate
eBPF data planepacket handling in the kernel, replaces kube-proxyfastest; newer kernels
PluginOverlay / routingNetworkPolicyNotes
Calico (this cluster)VXLAN, IP-in-IP, BGP, eBPFyes + own policy CRDsmost common on-prem
CiliumVXLAN, native, eBPFyes + L7 policieseBPF-first, Hubble observability
FlannelVXLANnosimple, no policies
Cloud CNIs (Azure, AWS VPC)VPC-native IPsvia Calico / Ciliummanaged clusters

A CNI without NetworkPolicy support silently ignores your policies. Policies are Day 4.

Services

Pods come and go; a Service is the stable address in front of them.

graph LR C[Client] --> S[Service web<br/>ClusterIP 10.96.x.x] S --> P1[Pod 10.244.1.5] S --> P2[Pod 10.244.2.7] S --> P3[Pod 10.244.3.9]

The Service selects Pods by label. Ready Pod IPs land in an EndpointSlice; kube-proxy (iptables, IPVS or nftables mode) programs every node to translate the ClusterIP to a Pod IP.

TypeReachable fromNote
ClusterIPinside the clusterdefault
NodePort<any-node>:30000-32767opens the port on every node
LoadBalanceroutsidecloud or MetalLB - not in this cluster
ExternalName-DNS CNAME only
headless (clusterIP: None)-DNS returns Pod IPs (StatefulSets)
spec:
  type: NodePort
  selector:
    app: web            # must match the Pod labels
  ports:
    - port: 80          # Service port
      targetPort: 8080  # container port

DNS (CoreDNS)

web                          # same namespace
web.shop                     # namespace shop
web.shop.svc.cluster.local   # fully qualified
db-0.db.shop.svc.cluster.local   # one StatefulSet Pod

When it does not work

kubectl get endpointslices -l kubernetes.io/service-name=web

No endpoints = selector matches no ready Pod. Check labels, readiness, then targetPort.

References