Hitesh Sahu
Hitesh SahuHitesh Sahu
  1. Home
  2. ›
  3. posts
  4. ›
  5. …

  6. ›
  7. 2 5 Networking

Loading ⏳
Fetching content, this won’t take long…


💡 Did you know?

🦈 Sharks existed before trees 🌳.

🍪 This website uses cookies

No personal data is stored on our servers however third party tools Google Analytics cookies to measure traffic and improve your website experience. Learn more

Loading ⏳
Fetching content, this won’t take long…


💡 Did you know?

🍯 Honey never spoils — archaeologists found 3,000-year-old jars still edible.
kubernetes

    AI-AgenticAI

    AI-DeepLearning

    AI-GenAI

    AI-Infrastructure

    AI-Machine-Learning

    AI-Math

    AWS

    Azure

    Hobbies

    kubernetes
    • Kubernetes and Cloud Native Certification Path

    • Kubernetes: Control Loops, Scheduling, and GPUs

    • Kubernetes API Server Internals

    • etcd Architecture Explained

    • Kubernetes Scheduler Internals

    • Kubernetes Informers & Controllers Explained

    • Kubernetes Networking: Pods, Services, Ingress, and CNI

    • Kubernetes Storage: PV, PVC, StorageClass, and CSI

    • Helm: Kubernetes Package Manager

    • Cloud Native Observability: Prometheus, Grafana, OpenTelemetry, and Tracing

    • GPU Scheduling in Kubernetes: Device Plugins, GPU Operator & MIG

    • NVIDIA Network Operator: InfiniBand, SR-IOV, RDMA, and Multus

    • Dynamic Resource Allocation: The Future of GPU Scheduling in Kubernetes

    • Kubernetes Performance at Scale

    • Optimizing AI Inference at Scale: The Full Stack

    • Kueue: Kubernetes-Native Job Queuing and Quota Management

    • Multi-Node Distributed Training on Kubernetes

    • Kubernetes Topology Manager: NUMA-Aware GPU Scheduling

    • NVIDIA NIM: Optimized Inference Microservices on Kubernetes

    • GPU Autoscaling on Kubernetes: KEDA, HPA, and Cluster Autoscaler

    • kubernetes Index


    Management

    Programming

    Terraform

    Z_Appendix

    0-root

Cover Image for Kubernetes Networking: Pods, Services, Ingress, and CNI
kubernetes

Kubernetes Networking: Pods, Services, Ingress, and CNI

How Kubernetes networking works from the ground up — the flat Pod network model, CNI plugins, kube-proxy and iptables, Services (ClusterIP, NodePort, LoadBalancer, Headless), CoreDNS service discovery, Ingress, NetworkPolicies, and why overlay networks are replaced by InfiniBand for GPU training.

Kubernetes
Networking
CNI
Services
Ingress
CoreDNS
← Previous

Kubernetes Informers & Controllers Explained

Next →

Kubernetes Storage: PV, PVC, StorageClass, and CSI

Kubernetes Networking: Pods, Services, Ingress, and CNI

Kubernetes networking is built on one rule that everything else follows from:

Every Pod gets its own IP address. Pods can reach any other Pod directly, without NAT.

This sounds simple. Implementing it across hundreds of nodes, cloud VPCs, and heterogeneous hardware is what the networking stack is for.


The Kubernetes Networking Model

Three requirements the model must satisfy:

Requirement Meaning
Pod-to-Pod Any Pod can reach any other Pod using its IP, even on a different node
No NAT The IP a Pod sees as its own is the same IP other Pods use to reach it
Node-to-Pod Nodes can reach any Pod directly

This is called the flat network model — from any Pod's perspective, every other Pod is reachable at its IP with no address translation.

flowchart LR

subgraph Node1["Node 1"]
  PodA["Pod A\n10.244.1.5"]
  PodB["Pod B\n10.244.1.6"]
end

subgraph Node2["Node 2"]
  PodC["Pod C\n10.244.2.3"]
end

PodA

-->|"direct IP\nno NAT"| PodC

PodA

-->|"same node\nloopback bridge"| PodB

Pod IPs come from a cluster-wide Pod CIDR (e.g., 10.244.0.0/16). Each node gets a slice of that range (e.g., 10.244.1.0/24 for Node 1, 10.244.2.0/24 for Node 2).


CNI — Container Network Interface

Kubernetes does not implement networking itself. It delegates to a CNI plugin via the Container Network Interface spec.

flowchart LR

Kubelet

-->|"calls CNI"| CNI["CNI Plugin\n(Flannel / Calico / Cilium)"]

CNI

-->|"sets up"| VethPair["veth pair\n(Pod ↔ host bridge)"]

CNI

-->|"routes packets"| CrossNode["Cross-node routing\n(overlay or BGP)"]

When a Pod is created, the Kubelet calls the CNI plugin to:

  1. Create a network namespace for the Pod
  2. Create a veth pair — one end inside the Pod (eth0), one end on the host bridge
  3. Assign the Pod's IP from the node's slice of Pod CIDR
  4. Set up routing so packets to other nodes' Pod CIDRs reach the right node

Common CNI Plugins

Plugin Mechanism Key strength
Flannel VXLAN overlay (UDP encapsulation) Simple, works anywhere
Calico BGP routing (no overlay) High performance, NetworkPolicy support
Cilium eBPF (kernel-level packet processing) Observability, L7 policy, high performance
Weave Encrypted overlay Easy multi-cluster

Same-Node vs Cross-Node Communication

flowchart TB

subgraph "Same node"
  PodA["Pod A\n10.244.1.5"]
  -->|"veth → bridge"| Bridge["cbr0 bridge\n(Linux bridge)"]
  Bridge
  -->|"veth → Pod"| PodB["Pod B\n10.244.1.6"]
end

subgraph "Cross-node (Flannel VXLAN)"
  PodC["Pod C\n10.244.1.7"]
  -->|"veth → bridge → VXLAN"| Tunnel["UDP tunnel\n(encapsulated)"]
  Tunnel
  -->|"decapsulate"| PodD["Pod D\n10.244.2.3\non Node 2"]
end

Same-node: packets go through the Linux bridge — no overhead, effectively loopback speed.

Cross-node with VXLAN: packets are encapsulated in UDP, sent to the destination node's IP, then decapsulated. This is the "overlay" — it adds ~10–15% CPU overhead and latency, which is why GPU training workloads replace it with InfiniBand (see Network Operator post).


Services — Stable Endpoints for Ephemeral Pods

Pod IPs are ephemeral — when a Pod is replaced (crash, rolling update), it gets a new IP.

A Service provides a stable virtual IP (ClusterIP) that load-balances across all healthy Pods matching a label selector.

flowchart LR

Client["Client Pod"]

-->ClusterIP["Service ClusterIP\n10.96.45.12\n(stable forever)"]

ClusterIP

-->|"kube-proxy\niptables rules"| Pod1["Pod 10.244.1.5"]

ClusterIP

-->Pod2["Pod 10.244.1.7"]

ClusterIP

-->Pod3["Pod 10.244.2.3"]

Service Types

Type Use case How it works
ClusterIP In-cluster communication Virtual IP only reachable inside the cluster
NodePort Basic external access Opens a port (30000–32767) on every node; traffic forwarded to Service
LoadBalancer Production external access Cloud provider provisions a load balancer with a public IP
ExternalName DNS alias to external service Returns a CNAME — no proxying
Headless StatefulSets, direct Pod access No ClusterIP; DNS returns individual Pod IPs
# ClusterIP (default)
apiVersion: v1
kind: Service
metadata:
  name: web-svc
spec:
  selector:
    app: web          # routes to all Pods with this label
  ports:
  - port: 80
    targetPort: 8080

---
# LoadBalancer — gets a cloud public IP
apiVersion: v1
kind: Service
metadata:
  name: web-lb
spec:
  type: LoadBalancer
  selector:
    app: web
  ports:
  - port: 80
    targetPort: 8080

---
# Headless — for StatefulSets (stable DNS per Pod)
apiVersion: v1
kind: Service
metadata:
  name: postgres-headless
spec:
  clusterIP: None     # ← headless
  selector:
    app: postgres
  ports:
  - port: 5432

kube-proxy — How Service IPs Work

Services have no process listening on the ClusterIP. The IP is virtual — kube-proxy programs iptables rules on every node that intercept packets to the ClusterIP and DNAT them to a real Pod IP.

sequenceDiagram

participant Pod as Client Pod
participant IPTables as iptables (on node)
participant Backend as Backend Pod

Pod->>IPTables: packet to 10.96.45.12:80
IPTables->>IPTables: match Service rule\nDNAT → 10.244.1.5:8080\n(randomly selected backend)
IPTables->>Backend: packet to 10.244.1.5:8080
Backend-->>Pod: response (src IP = Pod IP)

At very high connection rates (> 10,000 Services), iptables rule chaining becomes slow. IPVS mode (Layer-4 load balancing in the kernel) or Cilium eBPF replaces iptables for high-scale clusters.


CoreDNS — Service Discovery

Pods don't hardcode ClusterIPs. They use DNS names that resolve to Service ClusterIPs.

Every Service gets a DNS name: <service-name>.<namespace>.svc.cluster.local

flowchart LR

Pod["Pod\nnslookup web-svc"]

-->CoreDNS["CoreDNS\n(kube-dns Service)"]

CoreDNS

-->|"A record → ClusterIP"| IP["10.96.45.12"]

IP

-->|"routed by kube-proxy"| Backend["Backend Pod"]
# Inside any Pod:
curl http://web-svc                          # same namespace
curl http://web-svc.default                 # explicit namespace
curl http://web-svc.default.svc.cluster.local  # fully qualified

# Headless Service — returns individual Pod IPs:
# postgres-0.postgres-headless.default.svc.cluster.local → 10.244.1.5
# postgres-1.postgres-headless.default.svc.cluster.local → 10.244.2.3

CoreDNS is a Deployment (typically 2 replicas) that watches the API Server for Service and Pod changes and updates DNS records automatically.


Ingress — HTTP Routing into the Cluster

Services of type LoadBalancer give each Service its own cloud load balancer (expensive for dozens of Services). Ingress puts one load balancer in front and routes to many Services by hostname or URL path.

flowchart LR

Internet

-->LB["Cloud Load Balancer\n(one public IP)"]

LB

-->IngressCtrl["Ingress Controller\n(NGINX / Traefik / AWS ALB)"]

IngressCtrl

-->|"api.example.com"| APISvc["api Service"]

IngressCtrl

-->|"example.com/dashboard"| DashSvc["dashboard Service"]

IngressCtrl

-->|"TLS termination"| TLS["TLS cert\n(cert-manager)"]
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: app-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  ingressClassName: nginx
  tls:
  - hosts:
    - api.example.com
    secretName: api-tls-cert
  rules:
  - host: api.example.com
    http:
      paths:
      - path: /v1
        pathType: Prefix
        backend:
          service:
            name: api-svc
            port:
              number: 80
  - host: example.com
    http:
      paths:
      - path: /dashboard
        pathType: Prefix
        backend:
          service:
            name: dashboard-svc
            port:
              number: 3000

The Ingress Controller (a Pod running NGINX, Traefik, or a cloud-native controller) watches Ingress objects and configures its load balancer rules dynamically. Kubernetes defines the Ingress API but does not ship a controller — you install one separately.


NetworkPolicies — Firewall Rules for Pods

By default, all Pods can reach all other Pods (the flat model has no built-in isolation).

NetworkPolicy adds firewall rules at the Pod level:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-only-frontend
  namespace: backend
spec:
  podSelector:
    matchLabels:
      app: api             # applies to "api" Pods
  policyTypes:
  - Ingress
  - Egress
  ingress:
  - from:
    - podSelector:
        matchLabels:
          app: frontend    # only frontend Pods can reach api
    ports:
    - protocol: TCP
      port: 8080
  egress:
  - to:
    - podSelector:
        matchLabels:
          app: postgres    # api can only talk to postgres
    ports:
    - protocol: TCP
      port: 5432

NetworkPolicies are additive — you can only allow, not explicitly deny. A common pattern is a default-deny policy that blocks all ingress/egress, then explicit allow policies for each allowed connection:

# Default deny all ingress in namespace
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-ingress
spec:
  podSelector: {}      # matches all Pods in namespace
  policyTypes:
  - Ingress
  # no ingress rules → deny all

NetworkPolicy enforcement requires a CNI plugin that supports it — Calico and Cilium do; Flannel alone does not.


The Full Request Flow

A browser request hitting an application running in Kubernetes:

sequenceDiagram

participant Browser
participant LB as Cloud Load Balancer
participant NGINX as Ingress Controller Pod
participant SvcIP as kube-proxy (iptables)
participant AppPod as App Pod

Browser->>LB: GET https://api.example.com/v1/users
LB->>NGINX: TCP to NodePort 443
NGINX->>NGINX: TLS termination\nroute by hostname + path
NGINX->>SvcIP: HTTP to api-svc ClusterIP:80
SvcIP->>AppPod: DNAT → 10.244.2.3:8080
AppPod-->>Browser: 200 OK (response path)

Why This Matters for GPU Workloads

The CNI overlay network (VXLAN) is fine for API traffic — a few MB/s per request.

For distributed training, AllReduce between 8 DGX nodes transfers hundreds of GB/s of gradient data. The VXLAN overhead and CPU involvement make overlay networking a hard bottleneck.

The solution (covered in the Network Operator post):

  • A second NIC on each GPU node — an InfiniBand HCA
  • RDMA — bypasses the kernel and CPU entirely
  • Multus CNI — attaches both the cluster CNI (for API traffic) and the RDMA NIC (for training traffic) to the same Pod

The cluster CNI (Calico/Cilium) handles all Kubernetes control plane and application traffic. InfiniBand handles all GPU-to-GPU training traffic. They are completely separate data paths.


Key Takeaways

Concept Purpose
Flat network model Every Pod has a routable IP; no NAT between Pods
CNI plugin Implements pod networking (veth pairs, IP assignment, cross-node routing)
Service Stable virtual IP + DNS name for a set of Pods; survives Pod restarts
kube-proxy Programs iptables/IPVS rules that implement Service virtual IPs
CoreDNS Resolves <svc>.<ns>.svc.cluster.local → ClusterIP
Ingress HTTP routing: one load balancer, many Services, by hostname/path
NetworkPolicy Pod-level firewall; additive allow rules; requires CNI support
For GPU training Replace overlay CNI with RDMA over InfiniBand — different data path, not a replacement for the cluster CNI
Hitesh Sahu
Written by Hitesh Sahu, a passionate developer and blogger.

Tue Jul 07 2026

Share This on

← Previous

Kubernetes Informers & Controllers Explained

Next →

Kubernetes Storage: PV, PVC, StorageClass, and CSI

kubernetes/2-5-Networking
Let's work together
+49 176-2019-2523
hiteshkrsahu@gmail.com
WhatsApp
Skype
Munich 🥨, Germany 🇩🇪, EU
Playstore
Hitesh Sahu's apps on Google Play Store
Need Help?
Let's Connect
Navigation
  Home/About
  Skills
  Work/Projects
  Lab/Experiments
  Contribution
  Awards
  Art/Sketches
  Thoughts
  Contact
Links
  Sitemap
  Legal Notice
  Privacy Policy

Made with

NextJS logo

NextJS by

hitesh Sahu

| © 2026 All rights reserved.