Back to home

BLOG

All About Networking In Kubernetes

A detailed guide to the Kubernetes network model, from Pod networking and CNI plugins to Services, DNS, kube-proxy, Ingress, and NetworkPolicy.

March 30, 202616 min read
  • Kubernetes
  • Networking
  • DevOps

Kubernetes networking often gets explained in one sentence: every Pod gets an IP, Services provide a stable address, and the platform routes traffic to the right backend. That summary is directionally correct, but it hides most of the important details. Once you start operating real systems, you need a stronger mental model. You need to know why Pods can talk directly, what a CNI plugin is actually doing, how Services are implemented, what kube-proxy changes on a node, where DNS fits in, and what NetworkPolicy can and cannot enforce.

This article is a practical deep dive into Kubernetes networking from the point of view of someone building and operating workloads. The goal is not to memorize every implementation detail of every CNI. The goal is to understand the abstractions Kubernetes promises, the components that implement them, and the layers you should inspect when traffic is not behaving the way you expect.

1. The Kubernetes Network Model

The official Kubernetes model is built around a few simple guarantees. Each Pod gets its own cluster-wide IP address. Containers inside the same Pod share a network namespace and can talk over `localhost`. Pods should be able to communicate with other Pods directly, whether they run on the same node or on different nodes, without the application needing to know anything about overlays, host port mappings, or intermediate translation steps. Services then add a stable virtual identity on top of a changing set of Pods.

This is a very different model from older container workflows where applications commonly exposed themselves through host ports and ad-hoc links. Kubernetes wants Pods to behave more like first-class machines on a shared network. That design choice simplifies service discovery, load balancing, and mobility, because workloads do not need to be rewritten every time a Pod gets rescheduled.

A UML-style system view of how traffic enters the cluster, resolves through service discovery, and reaches Pods under policy constraints.

At a high level, there are four separate networking problems in Kubernetes. First, communication between containers inside the same Pod. Second, Pod-to-Pod communication across the cluster. Third, Pod-to-Service communication, where a stable virtual endpoint represents a changing workload. Fourth, external-to-Service communication, where cluster traffic enters through a load balancer, Ingress, or Gateway. If you separate these concerns mentally, Kubernetes networking becomes much easier to debug.

2. Pods, Network Namespaces, and Localhost

The smallest unit of networking in Kubernetes is the Pod, not the container. All containers inside a Pod share the same network namespace. That means they share the same IP address, the same port space, and the same loopback interface. If a sidecar container needs to call the main application container, it does not need a Service. It can simply connect to `localhost` on the right port.

This shared namespace is why port planning matters inside a Pod. Two containers in the same Pod cannot both bind the same port unless one of them only listens on a different interface. It is also why Pods are ideal for tightly coupled helper containers such as log forwarders, proxies, auth sidecars, or metrics exporters that conceptually belong to the same unit of deployment.

Containers in the same Pod share one network namespace, one IP, one loopback device, and one port space.

3. How Pod-to-Pod Networking Actually Works

Kubernetes itself defines the network model, but it does not fully implement the data plane. That is the job of the container runtime plus the network plugin, which on Linux is usually a CNI plugin. The plugin is responsible for attaching interfaces, assigning Pod IPs, and creating the routes or encapsulation necessary for cross-node communication.

Different CNIs choose different strategies. Some use overlays, where Pod traffic is encapsulated between nodes. Some prefer routed approaches, where Pod CIDRs are advertised more directly. Some use eBPF to implement service handling and policy enforcement with lower overhead and tighter kernel integration. The important thing is that all of them are trying to satisfy the same Kubernetes contract: Pods should be able to talk to other Pods as if they were all on one flat network.

This also means Kubernetes networking is not a single binary feature. If a cluster has networking issues, the fault may exist at multiple layers: Pod interface attachment, node routing, overlay encapsulation, kube-proxy rule programming, service endpoint selection, or policy enforcement. The abstraction is simple, but the implementation stack is not.

bash
kubectl get pods -o wide
kubectl get nodes -o wide
ip route
ip addr

Those are the kinds of commands that start grounding the abstraction in reality. The Pod IPs, node IPs, and route tables often tell you immediately whether the cluster networking model is being honored or whether packets are dying before they ever reach a Service abstraction.

4. Services and Stable Virtual Endpoints

Pods are ephemeral by design. They can be recreated at any time, move to different nodes, and receive different IP addresses. That is great for scheduling and resilience, but terrible if clients bind directly to Pod addresses. Services exist to solve that problem. A Service gives you a stable virtual IP address and usually a stable DNS name for a logical backend set.

A Service does not itself run a process that proxies every byte in user space. Instead, it is an API object that expresses traffic intent. The cluster then uses endpoint objects and a service proxy implementation to translate traffic sent to the virtual address into traffic sent to one of the matching Pod backends.

yaml
apiVersion: v1
kind: Service
metadata:
  name: api
spec:
  selector:
    app: api
  ports:
    - port: 80
      targetPort: 8080
  type: ClusterIP

In this example, `api` is exposed internally as a `ClusterIP` Service. Clients connect to port `80`, but the selected Pods actually listen on `8080`. The Service selector links the Service to Pods labeled `app: api`, and Kubernetes keeps the backend set updated as Pods come and go.

Different Service types solve different exposure problems. `ClusterIP` is internal-only and is the default. `NodePort` opens a port on each node. `LoadBalancer` asks a supported cloud environment to provision an external load balancer. `ExternalName` maps a Service to an external DNS name. But even with these variants, the core idea stays the same: Services create a stable network identity over an unstable workload set.

It also helps to understand that modern Kubernetes uses EndpointSlices as the scalable representation of which Pods back a Service. If you are troubleshooting a Service, a crucial question is not only “does the Service exist?” but also “does it have correct EndpointSlices pointing at healthy Pods?”

A Service gives clients one stable virtual address while EndpointSlices track the real backend Pods currently eligible to receive traffic.

5. kube-proxy, IPVS, iptables, and eBPF Paths

Once a client sends traffic to a Service virtual IP, something on the node has to make that virtual abstraction real. Traditionally, that job belongs to kube-proxy. kube-proxy watches Services and EndpointSlices and then programs the node’s packet handling so traffic addressed to the Service gets redirected to a real backend Pod.

A UML-style debugging path showing the main networking layers to verify when traffic fails inside a cluster.

Depending on configuration, kube-proxy may use `iptables` mode or `ipvs` mode. Some modern CNIs bypass kube-proxy entirely and implement Service translation in eBPF. For day-to-day users, the exact data plane is less important than knowing that there is always a mechanism turning a virtual Service identity into real backend routing on the node path.

This matters for debugging because the failure might be in rule programming rather than in the Pods themselves. A healthy Pod and a correct Service object still do not guarantee successful traffic if the node’s service proxy state is stale, incomplete, or being replaced by another network component with a different behavior model.

6. DNS for Services and Pods

Cluster DNS is what makes Service access usable at application level. Instead of asking workloads to remember Service IPs, Kubernetes exposes DNS names such as `api.default.svc.cluster.local`. In most clusters, CoreDNS watches cluster state and answers those names dynamically.

A surprisingly large class of networking bugs are actually DNS bugs. If the Service exists but the app cannot resolve its name, the problem may be CoreDNS, namespace assumptions, search domains, or an incorrect FQDN. If the name resolves but traffic still fails, the problem is further down the path.

bash
kubectl exec -it deploy/web -- nslookup api.default.svc.cluster.local
kubectl get svc api
kubectl get endpointslices -l kubernetes.io/service-name=api

Those commands form a great first-pass checklist. If DNS fails, you are still at the discovery layer. If DNS works but EndpointSlices are empty, the Service abstraction exists but has no real backends. If both DNS and EndpointSlices look correct, the problem is probably in routing, policy, or the workload itself.

7. External Traffic, Ingress, and Gateway API

So far, everything has been east-west cluster traffic: workloads talking to workloads inside the cluster. External traffic is a different concern. At that boundary, Kubernetes needs a way to accept outside requests and route them to internal Services. This is where `LoadBalancer` Services, Ingress controllers, and increasingly the Gateway API come in.

Ingress is HTTP-focused. It lets you define host- and path-based routing rules, typically backed by an ingress controller such as NGINX. Gateway API generalizes this idea and provides a richer, more extensible model for traffic management. Ingress is still common in real clusters, so you need to understand it even if Gateway API is where the ecosystem is moving.

yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: platform-ingress
spec:
  ingressClassName: nginx
  rules:
    - host: app.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: api
                port:
                  number: 80

A helpful way to think about Ingress is that it does not replace Services. It sits in front of them. It terminates or accepts outside requests, applies host/path routing rules, and forwards to internal Services, which then forward to Pods. When you debug ingress failures, you should always separate “did traffic reach the controller?” from “did the controller route to the right Service?” from “did the Service reach healthy Pods?”

North-south traffic usually flows through an external load balancer into an ingress controller, then through routing rules to a Service and finally to Pods.

8. NetworkPolicy and What It Actually Controls

Flat connectivity is powerful, but it is not always what you want from a security perspective. NetworkPolicy lets you describe which Pods may send or receive traffic at layer 3 and layer 4. Without policy, clusters often allow broad east-west communication by default, which is convenient for development but risky for production systems.

yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-api-from-web
spec:
  podSelector:
    matchLabels:
      app: api
  policyTypes:
    - Ingress
  ingress:
    - from:
        - podSelector:
            matchLabels:
              app: web
      ports:
        - protocol: TCP
          port: 8080

That policy says only Pods labeled `app: web` may reach the `api` Pods on port `8080`. In real systems, these rules become an important part of defense-in-depth, especially when multiple services or tenants share the same cluster.

There are two especially important limitations to remember. First, NetworkPolicy is generally enforced by the network plugin, not by Kubernetes core itself. If your CNI does not implement policy enforcement, the object may exist in the API and still have no effect. Second, NetworkPolicy is fundamentally about layer 3 and layer 4 traffic control. It does not understand application semantics the way an API gateway or service mesh policy might.

This is why default-deny strategies matter. In a serious multi-service environment, it is often safer to start by denying broad communication and then explicitly allow only what each service needs. That turns the cluster from an open east-west network into a more intentional communication graph.

NetworkPolicy turns an open east-west network into an explicit communication graph where only required paths stay reachable.

9. What Kubernetes Promises vs What The Plugin Implements

One of the easiest mistakes to make when learning Kubernetes networking is to blur the Kubernetes API model together with the implementation details of a specific plugin or cloud. Kubernetes promises the abstraction: Pod IPs, Services, policy objects, endpoint discovery. The plugin implements the mechanics: overlays, routing, encapsulation, rule programming, eBPF hooks, and policy enforcement.

That distinction matters because two clusters can both be “valid Kubernetes” while behaving differently under the hood. One cluster may use overlay networking. Another may use direct routing. One may rely on kube-proxy. Another may replace it. One may enforce policy strongly. Another may expose the API but not actually implement those semantics. If you understand the abstraction boundary, you can reason about cluster portability much more clearly.

10. A Practical Debugging Order

When networking breaks in Kubernetes, I try not to jump randomly between layers. I move in order. First, confirm the workload and labels are correct. Second, confirm the Service exists and targets the right port. Third, confirm EndpointSlices contain the expected backends. Fourth, confirm DNS resolution. Fifth, inspect ingress or gateway routing if external traffic is involved. Sixth, inspect NetworkPolicy. Seventh, inspect node-level service proxying or CNI behavior if everything above appears correct.

bash
kubectl get pods -o wide
kubectl get svc
kubectl get endpointslices
kubectl describe ingress platform-ingress
kubectl describe networkpolicy
kubectl logs -n ingress-nginx deploy/ingress-nginx-controller

You can think of this as a narrowing funnel. At the top, you validate Kubernetes objects and discovery. In the middle, you validate routing and exposure. At the bottom, you validate node-local packet handling and plugin behavior. That order prevents you from digging into kernel-level networking when the real issue is simply an empty endpoint set or a selector mismatch.

11. Common Misconceptions

A few misunderstandings show up again and again. First, a Service is not a Pod-sidecar proxy; it is a virtual abstraction implemented by the cluster data plane. Second, DNS success does not mean backend reachability. Third, Pod readiness matters because not every running Pod should necessarily be considered a healthy endpoint. Fourth, a declared NetworkPolicy does not guarantee enforcement unless the CNI supports it.

Another misconception is treating Ingress as the entire networking model. Ingress is only one part of external HTTP exposure. Most Kubernetes networking questions are really about Pod networking, Services, DNS, and policy. If those layers are understood well, Ingress becomes much easier to reason about because it is simply one more routing layer on top.

12. Final Mental Model

What makes Kubernetes networking manageable is not memorizing every packet path. It is keeping a reliable conceptual stack in your head. Pods are first-class network participants. Services give workloads stable network identities. DNS makes those identities usable. kube-proxy or an equivalent datapath turns the abstractions into real routing behavior. Ingress and Gateway handle external traffic. NetworkPolicy constrains who may talk to whom. CNI plugins provide the mechanics that make all of that real on each node.

Once that model becomes intuitive, most networking problems stop feeling mysterious. They become layered systems problems with a finite number of places to inspect. And that is really the key to operating Kubernetes well: not assuming the network is magic, but understanding exactly which abstraction you are debugging at any moment.