ivinco
Kubernetes Networking Explained: A Deep Dive

Kubernetes Networking Explained: A Deep Dive

Ivinco Team··Updated

What is Kubernetes networking?

Kubernetes networking is how pods, Services and outside clients reach each other in a cluster. Every pod gets its own IP address, and any pod can reach any other pod without NAT. A CNI plugin builds this pod network. kube-proxy or a replacement routes Service traffic, and CoreDNS gives Services stable names.

Kubernetes defines the rules and the APIs. Add-ons you choose do most of the work, so two clusters can move the same packet in very different ways.

This guide goes layer by layer, from the network model to troubleshooting. The deep-dive section shows the commands to trace one pod's traffic on a node. Version details reflect Kubernetes 1.37, the current release in October 2026.

How the Kubernetes networking model works

The Kubernetes network model comes down to four rules:

  • Each pod gets its own IP address, unique across the cluster.
  • Containers in a pod share one network namespace. They talk to each other over localhost.
  • Every pod can reach every other pod on any node, without proxies or NAT, unless you segment the network on purpose.
  • Agents on a node, such as the kubelet, can reach all pods on that node.

The result is one flat address space. The docs say pods "can be treated much like VMs or physical hosts" for ports, naming, service discovery and load balancing.

Kubernetes implements only a few parts of this model itself. The rest comes from components you install:

PartProvided by
Pod network namespaceThe container runtime, such as containerd or CRI-O
Pod networkA CNI plugin, such as Calico, Cilium or Flannel
Service routingkube-proxy, or the network plugin's own proxy
NetworkPolicyUsually the network plugin
Gateway APIOne of many implementations

This split explains a common surprise. If your plugin doesn't implement NetworkPolicy, the API still accepts policies, and they have no effect.

The four types of Kubernetes networking

The Cluster Networking docs split the job into four problems:

TrafficSolved by
Container to containerA shared network namespace and localhost
Pod to podThe pod network, built by the CNI plugin
Pod to ServiceServices, kube-proxy and cluster DNS
External to ServiceNodePort, LoadBalancer, Ingress or Gateway API

Traffic that leaves the cluster, called egress, is a fifth path. By default, a pod may connect to anything. Network policies can restrict that, as shown later.

Kubernetes cluster networking: IP ranges for nodes, pods and Services

A cluster needs three IP ranges that don't overlap:

  • Node IPs come from the machines' own network. The kubelet or the cloud-controller-manager assigns them.
  • Pod IPs come from the network plugin.
  • Service IPs, also called ClusterIPs, come from the kube-apiserver's --service-cluster-ip-range.

The examples in this article use a typical layout for a kubeadm cluster:

NetworkExample rangeSet by
Nodes10.0.0.0/24Your VPC or LAN
Pods10.244.0.0/16, a /24 per nodekubeadm's --pod-network-cidr, or the plugin's own IPAM
Services10.96.0.0/12kubeadm's default --service-cidr

The pod range is the default in Flannel's manifest, and each node gets a /24 slice of it, such as 10.244.1.0/24. kubeadm gives cluster DNS the tenth address of its default Service range, 10.96.0.10.

Take your ranges from the RFC 1918 private blocks, and keep them clear of your VPC, peered networks and VPNs. If pod IPs are routable outside the cluster, they must be unique across the wider network. Since Kubernetes 1.33, you can add Service ranges later with ServiceCIDR objects.

Dual-stack networking has been stable since Kubernetes 1.23. It gives each pod one IPv4 and one IPv6 address. It needs pod and Service ranges for both families, nodes with routable IPv4 and IPv6 interfaces, and a network plugin that supports it. A Service picks its families with .spec.ipFamilyPolicy, set to SingleStack, PreferDualStack or RequireDualStack.

How Kubernetes pod networking works on a node

Three Linux features do the work on each node.

Network namespaces. A network namespace gives processes their own network devices, IP stack, routing tables, firewall rules and port numbers. Linux has eight namespace types, and the network namespace is the one that matters here. Every pod gets its own.

veth pairs. A veth pair is two virtual Ethernet devices joined like a pipe. A packet sent into one end comes out of the other. One end sits in the pod as eth0. The other end stays on the host.

A bridge. With the CNI bridge plugin, the host ends plug into a Linux bridge, a virtual switch in the host's namespace. Pods on the same node reach each other through it. Other plugins wire the host end differently, but every pod still gets a namespace and an interface.

The pause container ties it together. It holds the pod's namespaces, and the app containers join them. The CNI spec requires the runtime to create the network namespace before it calls any plugin.

A pod with hostNetwork: true uses the node's network namespace instead, so it shares the node's IP address and ports.

What is CNI in Kubernetes?

CNI, the Container Network Interface, is a small contract between a container runtime and network plugins. A plugin is an executable. The runtime runs it with a command such as ADD or DEL, passes the network config on stdin and reads a JSON result back.

When a pod starts, the runtime calls ADD. The main plugin creates the pod's interface, usually gets an address from an IPAM plugin, and sets up routes. Chained plugins can adjust the result afterwards, for example to map host ports.

Since Kubernetes 1.24, only the container runtime manages CNI plugins. That release removed the kubelet's --network-plugin and --cni-bin-dir flags. In containerd, the defaults are /etc/cni/net.d for config files and /opt/cni/bin for plugin binaries.

Here is a minimal config for the bridge plugin on a node that owns 10.244.1.0/24. It goes in /etc/cni/net.d/:

{
  "cniVersion": "1.0.0",
  "name": "pod-network",
  "type": "bridge",
  "bridge": "cni0",
  "isGateway": true,
  "ipMasq": true,
  "ipam": {
    "type": "host-local",
    "ranges": [[{"subnet": "10.244.1.0/24"}]],
    "routes": [{"dst": "0.0.0.0/0"}]
  }
}

What the fields do, per the bridge plugin docs:

  • "type": "bridge" plugs every pod on the node into one Linux bridge, here cni0.
  • "isGateway": true gives the bridge an IP address, so it becomes the pods' default gateway.
  • "ipMasq": true masquerades traffic from the node's pod subnet to anything outside that subnet, including pods on other nodes. The NAT section shows how to check it.
  • The host-local IPAM plugin hands out addresses from the node's range, with the gateway at .1 by default. It keeps its state on the node's disk, so addresses are unique per node.

If a pod needs more than one interface, Multus is a CNI plugin that attaches extra ones.

Kubernetes networking deep dive: trace a pod on your own node

You can check each layer above on a live node. The steps below trace one pod in the example cluster, on a node that owns 10.244.1.0/24. They assume containerd and the cni0 bridge, which the bridge plugin and Flannel create by default. Other plugins use other names, but the steps carry over. Run the node commands as root.

1. Find the pod's node. kubectl get pod <pod> -o wide shows the node and the pod's IP. Open a shell on that node.

2. Find the pod's pause container. On containerd, every pod starts with a pause container, the pod's sandbox. It runs no app code. Its job is to hold the pod's network namespace, which the app containers then join. That is why all containers in a pod share one IP address and one localhost. kubectl doesn't list the pause container, but crictl asks the runtime directly:

crictl pods --name <pod>    # the sandbox ID
crictl inspectp <pod-id>    # look for "pid" and "cniResult"
lsns -t net                 # one /pause process per pod

The pid field is the pause process, and cniResult shows what the CNI plugin set up. lsns lists the network namespaces on the node, and each pod's namespace shows its /pause process.

3. Look inside the pod's network namespace. The namespace is the pod's private copy of the network stack, with its own interfaces and routes. nsenter runs the node's own tools inside it, using the pause container's PID:

nsenter -t <pid> -n ip addr
nsenter -t <pid> -n ip route

You should see lo and eth0 with the pod's IP. The interface shows as eth0@ifN, where N is the index of its veth peer on the node. The default route points at the bridge, 10.244.1.1 on this node.

4. Find the node's end of the veth pair.

ip -o link | grep "^N:"
ip link show master cni0

The first command shows that veth and the bridge it plugs into. The second lists every port on cni0, one per pod on the node.

5. Check the node's routes. On the node, ip route shows 10.244.1.0/24 going to cni0. Routes to other nodes' pod subnets come from the network plugin or the cloud, as the next section shows.

For a longer walkthrough with captured output, see Nicolas Leiva's Kubernetes Networking: Behind the scenes. He traced a cluster built with Kelsey Hightower's Kubernetes The Hard Way in 2018, so some tools and defaults have changed since.

How do pods on different nodes communicate?

The bridge plugin gives each node a route to its own pod subnet only. In the example cluster, node 1 owns 10.244.1.0/24 and node 2 owns 10.244.2.0/24. A packet from a pod on node 1 to a pod on node 2 must leave node 1. The network then has to know that 10.244.2.0/24 sits behind node 2. Something has to add a route for each node's slice, or carry pod traffic inside packets between node IPs.

The smallest setups add one static route per node, as Kubernetes The Hard Way does. On node 1, for example:

sudo ip route add 10.244.2.0/24 via <node-2-ip>

Production clusters leave this to the network plugin or the cloud. There are three common approaches:

ApproachHow packets cross nodesExamples
OverlayEncapsulated in VXLAN, Geneve or IP-in-IPFlannel, Calico, Cilium
RoutedRoutes to each pod subnet, static or via BGPCalico, Cilium, Flannel host-gw
VPC-nativePods get addresses from the cloud networkAmazon VPC CNI, GKE, Azure CNI Pod Subnet

An overlay runs on almost any network, because the network underneath only sees node IPs. It costs some CPU, the extra header shrinks the usable packet size, and pod IPs can't be reached from outside the cluster. Routed and VPC-native setups skip the encapsulation. In exchange, the network must carry pod routes, and pods use up real addresses. With the Amazon VPC CNI, each pod gets a private address from your VPC. On GKE VPC-native clusters, pod IPs are routable across the VPC and peered VPCs.

On bare metal, there is no cloud router to hold pod routes. Plugins such as Calico can peer with your routers over BGP or build an overlay instead. We moved a long-term client's big-data platform onto on-prem Kubernetes, and we still run those clusters, from version upgrades to moving their databases in.

Does Kubernetes use NAT between pods?

The model says pod-to-pod traffic needs no NAT, and routing alone meets that rule. Some setups add NAT anyway. With "ipMasq": true, the bridge plugin masquerades everything that leaves the node's pod subnet, except multicast. A pod on another node then sees the sending node's IP as the source. To check a node, list its NAT rules and the tracked connections to a remote pod:

sudo iptables -t nat -S POSTROUTING
sudo conntrack -L -d <remote-pod-ip>

In a conntrack entry, the first src= is the sender and the second dst= is where replies go. If replies go to the node's IP, the source was masqueraded.

NAT still has a job at the edge of the cluster. In an AKS overlay network, for example, traffic that leaves the cluster is translated to the node's IP. Inside the cluster, kube-proxy uses destination NAT to send Service traffic to a pod, as the next section shows.

How Kubernetes Services and kube-proxy work

Pod IPs change every time a pod is replaced. A Service gives a set of pods one stable virtual IP and a DNS name. The control plane lists the pods behind it in EndpointSlices, with up to 100 endpoints per slice by default. On every node, kube-proxy watches Services and EndpointSlices and programs the node to forward Service traffic.

TypeReachable fromHow
ClusterIPInside the clusterA virtual IP, the default type
NodePortEvery node's IPA port from 30000–32767 on each node
LoadBalancerOutside the clusterAn external load balancer
ExternalNameInside the clusterA DNS CNAME, no proxying

A headless Service sets clusterIP: None. It gets no virtual IP, kube-proxy ignores it, and DNS returns the pod IPs directly.

Outside traffic reaches Services through a NodePort, a LoadBalancer Service, Ingress or Gateway API. The Ingress API is frozen, and Kubernetes recommends Gateway API instead. Ingress NGINX, one of the most popular Ingress controllers, was retired in March 2026. Its repository is now read-only, and it gets no more releases or security fixes. The Kubernetes load balancing guide covers all four options, and our Kubernetes Ingress guide covers the move off Ingress NGINX.

The older Endpoints API has been deprecated since Kubernetes 1.33, and kubectl get endpoints now prints a warning. It can't represent dual-stack Services and truncates long endpoint lists. Query EndpointSlices by label instead:

kubectl get endpointslice -l kubernetes.io/service-name=myservice

How kube-proxy sends Service traffic to a pod

A Service IP isn't answered by any single host. kube-proxy programs every node to capture traffic to the Service's IP and port and send it to one of its endpoints. In iptables mode, the nat table's PREROUTING and OUTPUT chains jump to KUBE-SERVICES. A rule there matches the Service's IP and port and jumps to a KUBE-SVC- chain for that Service. That chain picks one endpoint at random through the statistic match. Each endpoint has a KUBE-SEP- chain that rewrites the destination to the pod's IP and port.

A NodePort enters through the KUBE-NODEPORTS chain. It matches the port and jumps to the Service's KUBE-EXT- chain for external traffic. With the default traffic policy, that chain passes the packet on to the same KUBE-SVC- chain. If the chosen pod runs on another node, the receiving node forwards the packet.

By default, kube-proxy also source-NATs NodePort traffic, so the pod sees a node's IP as the client. LoadBalancer Services behave the same way. externalTrafficPolicy: Local keeps the client IP, but a node with no ready local pod drops the traffic. Troubleshooting step 5 shows how to print these rules on a node.

kube-proxy modes in 2026: iptables, nftables and IPVS

The proxy mode decides how kube-proxy programs a node:

ModeStatus in 1.37Notes
iptablesDefault on LinuxRules grow with Services and endpoints
nftablesStable since 1.33Needs kernel 5.13+, planned future default
ipvsDeprecated since 1.35Off by default in 1.40, removed in 1.43
kernelspaceWindows onlyPrograms the Windows VFP

The docs advise setting the mode explicitly in every cluster, so an upgrade can't change it. Moving to nftables changes two NodePort behaviors. NodePorts answer only on the node's primary IP, and kube-proxy stops adding firewall accept rules for them.

Some plugins replace kube-proxy entirely. Cilium, for example, load-balances Services in eBPF at the socket level. On such clusters, the iptables chains above don't apply, so use the plugin's own tools.

How does DNS work in Kubernetes?

CoreDNS is the default cluster DNS. It runs as pods in kube-system, behind a Service still named kube-dns for backward compatibility. In the example ranges, that Service sits at 10.96.0.10.

The kubelet writes each pod's /etc/resolv.conf. A pod in the namespace payments gets a file like this:

nameserver 10.96.0.10
search payments.svc.cluster.local svc.cluster.local cluster.local
options ndots:5

Records follow a fixed pattern:

  • A Service gets an A or AAAA record, my-svc.my-namespace.svc.cluster.local, that points to its ClusterIP.
  • A headless Service's name returns the IPs of its pods.
  • Named ports get SRV records, such as _http._tcp.my-svc.my-namespace.svc.cluster.local.

The search list lets pods use short names. From namespace test, the name data finds the Service data in test, and data.prod finds it in prod. The ndots:5 option has a cost. A name with fewer than five dots is tried with each search domain first, so one lookup for api.example.com can turn into several queries.

On busy clusters, NodeLocal DNSCache runs a DNS cache on every node. Pods query the cache on their own node, so those queries skip DNAT and connection tracking. The cache sends misses on to CoreDNS.

How do Kubernetes network policies work?

NetworkPolicy is a firewall for pods at layers 3 and 4. Without any policy, every pod accepts traffic from anywhere and can send it anywhere. A policy that selects a pod isolates it in the directions the policy lists. From then on, only connections that some policy allows get through. Inbound traffic from the pod's own node, such as kubelet health checks, is still allowed.

Three rules shape every policy set:

  • Policies only add. The allowed traffic is the union of all policies that apply, so order never matters. There are no deny rules.
  • Both ends must agree. A connection needs egress allowed at the source pod and ingress allowed at the destination pod.
  • The plugin enforces them. Without a plugin that supports NetworkPolicy, policies are stored and ignored.

Start each namespace with a default deny in both directions:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-all
  namespace: payments
spec:
  podSelector: {}
  policyTypes: ["Ingress", "Egress"]

A default deny on egress also blocks DNS, so add DNS back first. This policy lets every pod in the namespace reach CoreDNS, whose pods carry the k8s-app: kube-dns label:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-dns
  namespace: payments
spec:
  podSelector: {}
  policyTypes: ["Egress"]
  egress:
  - to:
    - namespaceSelector:
        matchLabels:
          kubernetes.io/metadata.name: kube-system
      podSelector:
        matchLabels:
          k8s-app: kube-dns
    ports:
    - protocol: UDP
      port: 53
    - protocol: TCP
      port: 53

Then allow each flow your apps need. This policy lets pods labeled app: backend reach the database pods on port 5432:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: backend-to-postgres
  namespace: payments
spec:
  podSelector:
    matchLabels:
      app: postgres
  policyTypes: ["Ingress"]
  ingress:
  - from:
    - podSelector:
        matchLabels:
          app: backend
    ports:
    - protocol: TCP
      port: 5432

Because egress is denied too, the backend pods also need an egress policy that allows app: postgres on port 5432. Watch for three common mistakes:

  • Selector indentation. namespaceSelector and podSelector in one list item mean both must match. As two items, either one is enough. kubectl describe networkpolicy shows how Kubernetes read the policy.
  • ipBlock for pods. ipBlock is meant for addresses outside the cluster, since pod IPs change.
  • Expecting more than layer 4. NetworkPolicy can't target Services by name, log blocked connections or handle anything TLS-related.

For rules that cover the whole cluster, SIG Network is developing ClusterNetworkPolicy, an alpha API at policy.networking.k8s.io/v1alpha2. Calico 3.32 supports it. Amazon EKS has its own ClusterNetworkPolicy in the networking.k8s.aws/v1alpha1 group, with VPC CNI 1.21 or later. Calico and Cilium also have their own policy APIs. Network policies are one layer of cluster security, and the Kubernetes security checklist covers the rest.

Kubernetes networking options: Calico vs Cilium vs Flannel

Most Kubernetes networking solutions are CNI plugins. The one you pick decides how packets cross nodes and whether network policies work.

PluginMoves packets withNetworkPolicy
FlannelVXLAN (recommended), host-gw or WireGuardNeeds an add-on
CalicoVXLAN or IP-in-IP overlay, or BGP routingYes, plus its own API with tiers and global policies
CiliumVXLAN or Geneve overlay, or native routingYes, plus its own API with L7 and DNS rules
Cloud CNIsVPC addresses or a provider overlayDepends on the provider

Flannel describes itself as a simple way to build a layer 3 network for Kubernetes. It moves traffic between nodes, and its daemon doesn't enforce network policies. Its Helm chart can deploy the Kubernetes SIGs policy controller alongside it, or you can pair it with Calico.

Managed clusters often decide for you. On EKS, the Amazon VPC CNI is the only CNI that AWS supports for nodes on AWS infrastructure. You can install another plugin, such as Calico or Cilium, with support from its vendor or your own team. EKS Auto Mode doesn't support other plugins, and Fargate nodes run only the VPC CNI. GKE Dataplane V2 is built on Cilium. AKS Automatic uses Azure CNI powered by Cilium by default.

Calico or Cilium?

Neither wins everywhere. Both enforce standard NetworkPolicy, both can encrypt pod traffic with WireGuard, and both offer an eBPF data plane. They differ in where they fit best:

  • Calico fits mixed Linux and Windows clusters, and teams that want a choice of data planes, from iptables and nftables to eBPF, Windows and VPP. Its eBPF data plane can replace kube-proxy, and Calico Whisker shows flow logs. On-prem, its most common setup peers with your routers over BGP. It can also run as the policy engine on top of the AWS or Azure CNI.
  • Cilium fits clusters that want L7 and DNS-aware policies, or multi-cluster networking with Cluster Mesh, in the open-source project. Calico's DNS policies and cluster mesh come with its paid editions. Cilium can also replace kube-proxy, and Hubble shows flows. It needs Linux kernel 5.10 or later.

Cilium is a CNCF graduated project. Both have commercial editions. Calico has Calico Enterprise and Calico Cloud, and Isovalent, part of Cisco, sells an enterprise platform built on Cilium. Pick by the features you'll use and the platform you run on.

If you're unsure what your CNI and network policies enforce, our Kubernetes consulting team starts with read-only access and a written list of what to fix first.

Do you need a service mesh?

A service mesh adds features NetworkPolicy lacks, such as mutual TLS between workloads, retries and timeouts, traffic splitting and per-request metrics. For anything TLS-related, the NetworkPolicy docs themselves point to a mesh or an ingress controller. The main open-source options take three designs:

  • Istio ambient mode has been generally available since Istio 1.24. A per-node proxy called ztunnel handles mTLS and layer 4 policy without sidecars. Optional waypoint proxies, built on Envoy, add layer 7 features where you need them. Istio still supports sidecars as well.
  • Linkerd adds a small sidecar proxy, written in Rust, to each pod. The open-source project now ships only edge releases. Since February 2024, stable releases come from vendors.
  • Cilium Service Mesh builds IPsec or WireGuard encryption and L7 policy into the CNI, with Gateway API support. Its mutual authentication is still in beta.

Add a mesh when you need encrypted, identity-based traffic between services or routing per request. If NetworkPolicy and your CNI's encryption cover your needs, a mesh is one more system to upgrade and debug.

How to troubleshoot Kubernetes networking

Work through the layers in order. Start with DNS, then check the Service, the policies and the path between nodes.

SymptomLikely causeFirst check
Names don't resolveCoreDNS, or a policy blocking port 53nslookup, CoreDNS logs
Service IP fails, pod IP worksNo endpoints, or proxy rulesEndpointSlices, iptables-save
Pod IP failsA policy, routes or the CNIPolicies, ip route
Large transfers stallMTU too high for the overlayPod and node MTU

1. Find the pod and its node.

kubectl get pods -o wide

2. Get tools into the pod's network namespace. An ephemeral container runs temporarily inside an existing pod and shares its network. The netshoot image bundles dig, curl, tcpdump, conntrack and nftables:

kubectl debug -it <pod> --image=nicolaka/netshoot --target=<container>

3. Test DNS. These checks come from the DNS debugging guide, which also shows how to start the dnsutils test pod:

kubectl exec -i -t dnsutils -- nslookup kubernetes.default
kubectl get pods --namespace=kube-system -l k8s-app=kube-dns
kubectl logs --namespace=kube-system -l k8s-app=kube-dns

If lookups fail in only some namespaces, look for a default-deny egress policy without a DNS rule. If the CoreDNS pods are in CrashLoopBackOff, check their logs for a forwarding loop, as our CrashLoopBackOff guide shows.

4. Check that the Service has endpoints.

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

If the ENDPOINTS column shows <unset>, no pod the Service selects has an IP. Usually the selector matches no pods. Check that its selector matches the pod labels. A typo in a label is a common cause. EndpointSlices also list pods that aren't ready, so check pod readiness too.

5. Check the proxy rules on a node. If the pod IP answers and the Service IP doesn't, look at what kube-proxy programmed:

iptables-save | grep <service>    # iptables mode
nft list table ip kube-proxy      # nftables mode

Without SSH access, kubectl debug node/<node> -it --image=nicolaka/netshoot --profile=sysadmin opens a shell in the node's network namespace. The sysadmin profile makes the pod privileged, which covers iptables-save and nft.

6. Check network policies.

kubectl get networkpolicy -n <namespace>
kubectl describe networkpolicy <name> -n <namespace>

7. Capture packets. On the node, tcpdump -i any host <pod-ip> shows whether packets leave the source and reach the destination node. sudo conntrack -L -d <pod-ip> shows whether an address was rewritten on the way.

8. Check the MTU. An overlay adds a header to every packet. Calico's MTU guide lists 50 bytes for IPv4 VXLAN and 20 for IP-in-IP. If the pod MTU leaves no room for it, large packets get dropped or fragmented.

For problems outside the network, see the Kubernetes troubleshooting guide.

Kubernetes networking best practices

  1. Plan address ranges before the first cluster. Pods, Services and nodes need separate ranges. Routable pod IPs must not collide with the rest of your network.
  2. Pick a CNI that enforces NetworkPolicy. On managed clusters, check what the provider's default does.
  3. Default-deny every namespace. Then allow DNS and each flow your apps need.
  4. Set the kube-proxy mode explicitly. Move off IPVS before Kubernetes 1.40 turns it off by default.
  5. Use EndpointSlices in scripts, dashboards and controllers. The Endpoints API is deprecated.
  6. Replace Ingress NGINX with Gateway API, which Kubernetes recommends, or another maintained Ingress controller.
  7. Encrypt pod traffic where you need to. Calico, Cilium and Flannel offer WireGuard, and a mesh adds mTLS with workload identity.
  8. Watch DNS and the data plane. CoreDNS exports Prometheus metrics such as coredns_dns_request_duration_seconds. kube-proxy reports kubeproxy_sync_proxy_rules_duration_seconds. Hubble and Calico Whisker show flows.
  9. Keep traffic in its zone where that makes sense, with trafficDistribution: PreferSameZone on the Service.
  10. Add a service mesh only for a need it meets, such as mTLS between services or routing per request.

We have run production systems since 2009 and have managed more than 1,350 production servers. If you'd rather not trace all of this alone, our Kubernetes consulting team starts with read-only access and a written list of what to fix first.

Frequently Asked Questions

What is a Kubernetes network?

A Kubernetes network is the flat IP network that connects every pod in a cluster. Each pod gets its own IP address and can reach any other pod without NAT. A CNI plugin builds it on each node. Services add stable virtual IPs and DNS names on top, and network policies limit who can talk to whom.

What are the types of Kubernetes networking?

Kubernetes networking covers four types of traffic. Containers in one pod talk over localhost. Pods talk to other pods directly through the pod network that the CNI plugin builds. Pods reach Services through a stable virtual IP and DNS name. Outside clients reach Services through NodePort, LoadBalancer, Ingress or Gateway API.

What does a CNI plugin do in Kubernetes?

A CNI plugin connects each new pod to the cluster network. The container runtime calls it when a pod starts. The plugin creates the pod's network interface, assigns an IP address, usually through an IPAM plugin, and sets up routes. Plugins such as Calico and Cilium also enforce network policies and can encrypt pod traffic.

What is the pause container in Kubernetes?

The pause container is a tiny container that runtimes such as containerd start first in each pod. It holds the pod's network namespace. The app containers join that namespace, so they share one IP address and reach each other over localhost. kubectl doesn't list it. On a containerd node, lsns -t net shows it as /pause.

Which is better, Calico or Cilium?

Neither is better for every cluster. Both enforce Kubernetes network policies, offer an eBPF data plane that can replace kube-proxy, encrypt traffic with WireGuard and show flows. Calico suits mixed Linux and Windows clusters, BGP peering on-prem and a choice of data planes. Cilium suits teams that want L7 and DNS-aware policies and Cluster Mesh in open source.

How do I check if a network policy is applied to a pod?

The Kubernetes API doesn't report when a plugin has applied a policy. List the policies in the pod's namespace and compare each podSelector with the pod's labels, using kubectl describe networkpolicy. Then test real traffic from a debug pod. If nothing gets blocked, check that your network plugin enforces NetworkPolicy.