<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: ADITYA RAJ</title>
    <description>The latest articles on DEV Community by ADITYA RAJ (@iadiraj).</description>
    <link>https://dev.to/iadiraj</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3815431%2F0b7def24-9695-441b-a025-808542b6cda8.png</url>
      <title>DEV Community: ADITYA RAJ</title>
      <link>https://dev.to/iadiraj</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/iadiraj"/>
    <language>en</language>
    <item>
      <title>Kubernetes Networking [Level-9: Kubernetes Networking Internals]</title>
      <dc:creator>ADITYA RAJ</dc:creator>
      <pubDate>Mon, 24 Aug 2026 11:02:43 +0000</pubDate>
      <link>https://dev.to/iadiraj/kubernetes-networking-level-9-kubernetes-networking-internals-1g5j</link>
      <guid>https://dev.to/iadiraj/kubernetes-networking-level-9-kubernetes-networking-internals-1g5j</guid>
      <description>&lt;p&gt;This is &lt;strong&gt;Level 9&lt;/strong&gt; of our Kubernetes networking series — and it's where everything we've learned finally converges into a single story. In earlier levels, we mostly viewed networking from the outside:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Pod → Service → Pod
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we're going &lt;strong&gt;inside the Node&lt;/strong&gt;, following one packet through the actual Linux kernel:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Network namespace
   ↓
veth
   ↓
Linux kernel
   ↓
routing
   ↓
iptables / eBPF / IPVS
   ↓
conntrack / NAT
   ↓
veth
   ↓
destination Pod
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The goal of this article is simple: &lt;strong&gt;understand what actually happens to a packet inside a Kubernetes Node.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;The Complete Picture, First&lt;/li&gt;
&lt;li&gt;Network Namespaces, Revisited&lt;/li&gt;
&lt;li&gt;The veth Pair&lt;/li&gt;
&lt;li&gt;Why eth0 Is Confusing&lt;/li&gt;
&lt;li&gt;Pod → Node: The Core Diagram&lt;/li&gt;
&lt;li&gt;Linux Routing Inside the Pod&lt;/li&gt;
&lt;li&gt;Routing Is a Decision, Not Magic&lt;/li&gt;
&lt;li&gt;Same-Node Pod Communication&lt;/li&gt;
&lt;li&gt;The Linux Bridge&lt;/li&gt;
&lt;li&gt;What Happens When the Packet Reaches the Node&lt;/li&gt;
&lt;li&gt;Direct Pod Traffic vs Service Traffic&lt;/li&gt;
&lt;li&gt;Netfilter: Linux's Packet-Processing Framework&lt;/li&gt;
&lt;li&gt;Where iptables Fits In&lt;/li&gt;
&lt;li&gt;NAT, Revisited With a Real Example&lt;/li&gt;
&lt;li&gt;Why NAT Needs State&lt;/li&gt;
&lt;li&gt;conntrack: Connection Tracking&lt;/li&gt;
&lt;li&gt;Why conntrack Matters in Production&lt;/li&gt;
&lt;li&gt;A Simplified Linux Packet Path&lt;/li&gt;
&lt;li&gt;There's No Single Universal Packet Path&lt;/li&gt;
&lt;li&gt;Pod-to-Pod, Same Node&lt;/li&gt;
&lt;li&gt;Pod-to-Pod, Different Nodes&lt;/li&gt;
&lt;li&gt;Overlay Internals&lt;/li&gt;
&lt;li&gt;Why Overlays Exist&lt;/li&gt;
&lt;li&gt;Routing-Based Networking&lt;/li&gt;
&lt;li&gt;Why BGP Sometimes Appears&lt;/li&gt;
&lt;li&gt;CNI vs the Linux Kernel&lt;/li&gt;
&lt;li&gt;eBPF in the Internal Path&lt;/li&gt;
&lt;li&gt;NetworkPolicy in the Packet Path&lt;/li&gt;
&lt;li&gt;Service + NetworkPolicy Together&lt;/li&gt;
&lt;li&gt;Why Services Don't Have Network Interfaces&lt;/li&gt;
&lt;li&gt;Node IP vs Pod IP vs Service IP&lt;/li&gt;
&lt;li&gt;Why Pod IPs Aren't Directly Routable from the Internet&lt;/li&gt;
&lt;li&gt;A Full External Traffic Example&lt;/li&gt;
&lt;li&gt;The Complete Kubernetes Networking Stack&lt;/li&gt;
&lt;li&gt;A Real Packet Journey, Start to Finish&lt;/li&gt;
&lt;li&gt;Return Traffic&lt;/li&gt;
&lt;li&gt;What Can Break&lt;/li&gt;
&lt;li&gt;The Most Important Troubleshooting Principle&lt;/li&gt;
&lt;li&gt;Direct Pod IP vs Service IP: The Best Diagnostic Test&lt;/li&gt;
&lt;li&gt;Useful Linux Commands&lt;/li&gt;
&lt;li&gt;Interview Traps Worth Knowing&lt;/li&gt;
&lt;li&gt;The Entire Series So Far&lt;/li&gt;
&lt;li&gt;Level 9 Checkpoint&lt;/li&gt;
&lt;li&gt;The Most Important Lesson From This Article&lt;/li&gt;
&lt;li&gt;What's Next: Production Troubleshooting&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  The Complete Picture, First
&lt;/h2&gt;

&lt;p&gt;Let's set up a running example. A Frontend Pod (&lt;code&gt;10.244.1.10&lt;/code&gt;) calls &lt;code&gt;backend.default.svc.cluster.local&lt;/code&gt;. DNS resolves this to &lt;code&gt;10.96.120.50&lt;/code&gt;. The backend Pods are &lt;code&gt;10.244.1.20&lt;/code&gt;, &lt;code&gt;10.244.2.20&lt;/code&gt;, and &lt;code&gt;10.244.3.20&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;logical&lt;/em&gt; path looks simple:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Frontend Pod (10.244.1.10)
      ↓
Service IP (10.96.120.50)
      ↓
Service dataplane
      ↓
Backend Pod (10.244.2.20)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But physically, inside Linux, there's a lot more going on — and that's exactly what this article unpacks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Network Namespaces, Revisited
&lt;/h2&gt;

&lt;p&gt;A Pod gets its own &lt;strong&gt;network namespace&lt;/strong&gt; — think of it as a completely separate networking world inside Linux, with its own interfaces, IP addresses, routes, and network state:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Pod network namespace
┌─────────────────────────┐
│ eth0                    │
│ 10.244.1.10             │
│ route table             │
└─────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Node itself lives in its own, separate network namespace:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Node network namespace
┌─────────────────────────┐
│ eth0                    │
│ cni interfaces          │
│ routes                  │
│ iptables/eBPF           │
└─────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The key takeaway: &lt;strong&gt;Pod namespace ≠ Node namespace.&lt;/strong&gt; They're isolated from each other by design.&lt;/p&gt;

&lt;h2&gt;
  
  
  The veth Pair
&lt;/h2&gt;

&lt;p&gt;How do these two isolated worlds talk to each other? Commonly, through a &lt;strong&gt;veth pair&lt;/strong&gt; — a virtual Ethernet cable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Pod namespace                 Node namespace

┌──────────────┐             ┌──────────────┐
│    eth0      │=============│   vethXXXX   │
└──────────────┘             └──────────────┘
                    ↑
                 veth pair
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One end lives inside the Pod's namespace; the other lives inside the Node's namespace.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why eth0 Is Confusing
&lt;/h2&gt;

&lt;p&gt;Inside the Pod, &lt;code&gt;ip addr&lt;/code&gt; shows &lt;code&gt;eth0&lt;/code&gt; at &lt;code&gt;10.244.1.10&lt;/code&gt;. But on the Node itself, you generally won't find another interface &lt;em&gt;also&lt;/em&gt; called &lt;code&gt;eth0&lt;/code&gt; representing that same Pod. Instead, the Node-side end typically has an implementation-specific name, like &lt;code&gt;vethabc123&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Pod:  eth0
Node: vethabc123
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These two differently-named ends form a single virtual Ethernet connection between the two namespaces.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pod → Node: The Core Diagram
&lt;/h2&gt;

&lt;p&gt;The simplest possible mental model, and one of the most important diagrams in all of Kubernetes networking:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Pod → eth0 → veth → Node
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Linux Routing Inside the Pod
&lt;/h2&gt;

&lt;p&gt;Once a packet is inside the Pod, with &lt;code&gt;source = 10.244.1.10&lt;/code&gt; and &lt;code&gt;destination = 10.244.2.20&lt;/code&gt;, the Pod's network namespace needs to decide: &lt;em&gt;where should this go?&lt;/em&gt; Linux answers that using its &lt;strong&gt;routing table&lt;/strong&gt;, viewable with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ip route
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Conceptually:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Destination       Next hop
10.244.1.0/24      local
default            ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The exact contents depend entirely on your CNI implementation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Routing Is a Decision, Not Magic
&lt;/h2&gt;

&lt;p&gt;Think of the routing table as a map:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Packet destination (10.244.2.20)
        ↓
Routing table
        ↓
Which route matches?
        ↓
Which interface/next hop?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The core principle: &lt;strong&gt;Linux always chooses the most specific matching route.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Same-Node Pod Communication
&lt;/h2&gt;

&lt;p&gt;Suppose Pod A (&lt;code&gt;10.244.1.10&lt;/code&gt;) and Pod B (&lt;code&gt;10.244.1.20&lt;/code&gt;) are both on Node 1:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Pod A → eth0 → veth → Node networking → veth → eth0 → Pod B
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There might be a Linux bridge, straightforward routing, eBPF processing, or something else entirely in the middle — it depends on the CNI. &lt;strong&gt;Don't memorize "every Kubernetes cluster uses a bridge"&lt;/strong&gt; — that's simply false. The correct mental model is: &lt;em&gt;the CNI/networking implementation provides a path between the Pod namespaces, using whatever mechanism it's designed around.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Linux Bridge
&lt;/h2&gt;

&lt;p&gt;A common Linux networking component is the &lt;strong&gt;bridge&lt;/strong&gt; — think of it as a virtual Layer-2 switch:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;             Linux bridge
          ┌───────────────┐
          └─┬─────┬─────┬─┘
            │     │     │
          veth   veth   veth
            │     │     │
          Pod A Pod B Pod C
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A bridge can connect multiple interfaces at Layer 2. But again — &lt;strong&gt;not every CNI uses a Linux bridge as its main datapath.&lt;/strong&gt; Some rely on routing, overlays, cloud-native networking, or eBPF instead.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Happens When the Packet Reaches the Node
&lt;/h2&gt;

&lt;p&gt;Suppose Pod A (&lt;code&gt;10.244.1.10&lt;/code&gt;) sends a packet destined for &lt;code&gt;10.244.2.20&lt;/code&gt;. The packet exits through &lt;code&gt;eth0&lt;/code&gt; and arrives at the Node's networking stack — and this is exactly where Level 8 becomes relevant again. From here, the packet may pass through routing, iptables, IPVS, eBPF, conntrack, and/or NAT, depending on the implementation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Direct Pod Traffic vs Service Traffic
&lt;/h2&gt;

&lt;p&gt;It's worth comparing two very different packets side by side.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Direct Pod-to-Pod:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Pod A → Pod B
Destination: 10.244.2.20
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Service traffic:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Pod A → Service → Pod B
Destination (initially): 10.96.120.50
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The second path requires Service handling — the Service dataplane has to translate &lt;code&gt;10.96.120.50 → 10.244.2.20&lt;/code&gt; before normal Pod-to-Pod delivery can even begin. This is exactly why Service traffic is more involved than plain Pod-to-Pod traffic.&lt;/p&gt;

&lt;h2&gt;
  
  
  Netfilter: Linux's Packet-Processing Framework
&lt;/h2&gt;

&lt;p&gt;Now for a foundational Linux concept: &lt;strong&gt;Netfilter&lt;/strong&gt;. Netfilter is Linux's framework of packet-processing hooks — tools and features like iptables, NAT, and conntrack all interact with this underlying infrastructure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Packet
   ↓
Linux networking stack
   ↓
Netfilter hooks
   ↓
filter / NAT / connection tracking
   ↓
routing / forwarding
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Modern systems may use &lt;code&gt;nftables&lt;/code&gt; underneath familiar iptables tooling depending on the environment, but the conceptual Linux packet-processing framework — Netfilter — remains the important idea to hold onto.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where iptables Fits In
&lt;/h2&gt;

&lt;p&gt;From Level 8, we know: &lt;code&gt;Service → iptables → backend&lt;/code&gt;. Now we can place it precisely within the kernel's processing pipeline:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Packet → Linux kernel → Netfilter → iptables rules → NAT / filtering / Service handling
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Kubernetes programs networking rules directly into this pipeline on each Node.&lt;/p&gt;

&lt;h2&gt;
  
  
  NAT, Revisited With a Real Example
&lt;/h2&gt;

&lt;p&gt;Let's revisit NAT concretely. A client sends &lt;code&gt;SRC = 10.244.1.10&lt;/code&gt;, &lt;code&gt;DST = 10.96.120.50:80&lt;/code&gt;. The Service dataplane selects a backend, say &lt;code&gt;10.244.2.20:80&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;10.96.120.50:80
        ↓
      DNAT
        ↓
10.244.2.20:80
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The destination changes — that's &lt;strong&gt;Destination NAT&lt;/strong&gt; in action.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why NAT Needs State
&lt;/h2&gt;

&lt;p&gt;Now suppose &lt;code&gt;Client → Service → Backend&lt;/code&gt;, and the response needs to travel &lt;code&gt;Backend → Client&lt;/code&gt;. The kernel needs to &lt;em&gt;remember&lt;/em&gt; the original translation to correctly map the response back. That's exactly what &lt;strong&gt;conntrack&lt;/strong&gt; provides.&lt;/p&gt;

&lt;h2&gt;
  
  
  conntrack: Connection Tracking
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;conntrack&lt;/strong&gt; is short for &lt;strong&gt;connection tracking&lt;/strong&gt; — Linux's mechanism for maintaining state about active network connections. Given &lt;code&gt;Client (10.244.1.10:50000) → Service (10.96.120.50:80) → Backend (10.244.2.20:80)&lt;/code&gt;, the kernel tracks the relevant connection and NAT state:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Connection → conntrack → NAT state → return traffic handled correctly
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Why conntrack Matters in Production
&lt;/h2&gt;

&lt;p&gt;This is a major real-world troubleshooting topic. You can end up in situations where new connections start failing, or existing connections start behaving unexpectedly — both can trace back to connection tracking / NAT state. At scale, conntrack itself becomes a resource with real limits. Watch for: &lt;strong&gt;conntrack table exhaustion, dropped connections, NAT failures,&lt;/strong&gt; and &lt;strong&gt;intermittent connectivity.&lt;/strong&gt; We'll dig into these production failure modes much more deeply in Level 10.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Simplified Linux Packet Path
&lt;/h2&gt;

&lt;p&gt;For a packet entering a Node, a simplified path looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Network interface
       ↓
Linux kernel
       ↓
packet processing
       ↓
routing decision
       ↓
forwarding / local delivery
       ↓
destination interface
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For Kubernetes specifically, additional processing frequently includes iptables, conntrack, NAT, eBPF, NetworkPolicy enforcement, and Service load balancing — depending entirely on the networking implementation in use.&lt;/p&gt;

&lt;h2&gt;
  
  
  There's No Single Universal Packet Path
&lt;/h2&gt;

&lt;p&gt;This point is critical enough to repeat explicitly: &lt;strong&gt;there is no single universal Kubernetes packet path.&lt;/strong&gt; Clusters can use iptables, IPVS, eBPF, plain routing, overlays, cloud-native networking, or entirely different CNIs — and each combination produces a genuinely different path. The right approach is: &lt;strong&gt;learn the conceptual packet path first, then learn the implementation-specific path for your actual cluster.&lt;/strong&gt; This is precisely how experienced engineers troubleshoot Kubernetes networking in the real world.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pod-to-Pod, Same Node
&lt;/h2&gt;

&lt;p&gt;The easiest case: Pod A (&lt;code&gt;10.244.1.10&lt;/code&gt;) and Pod B (&lt;code&gt;10.244.1.20&lt;/code&gt;) on the same Node.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌────────── Pod A ──────────┐
│ eth0 (10.244.1.10)        │
└────────────┬──────────────┘
             │
           veth
             │
             ↓
       Node networking
             │
             ↓
           veth
             │
┌────────────┴──────────────┐
│ eth0 (10.244.1.20)        │
└────────── Pod B ──────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The exact middle processing depends entirely on the CNI implementation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pod-to-Pod, Different Nodes
&lt;/h2&gt;

&lt;p&gt;Now Pod A (&lt;code&gt;10.244.1.10&lt;/code&gt;) is on Node 1 and Pod B (&lt;code&gt;10.244.2.20&lt;/code&gt;) is on Node 2:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Pod A → veth → Node 1 → Node-to-Node network → Node 2 → veth → Pod B
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Node-to-Node portion can be implemented via routing, an overlay, a cloud provider's native network, or eBPF — again, entirely dependent on the CNI.&lt;/p&gt;

&lt;h2&gt;
  
  
  Overlay Internals
&lt;/h2&gt;

&lt;p&gt;Suppose the CNI uses an overlay. The inner packet is &lt;code&gt;Pod A → Pod B&lt;/code&gt;, and it gets wrapped inside an outer packet &lt;code&gt;Node 1 → Node 2&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌───────────────────────────────┐
│ Outer packet: Node1 → Node2   │
│                               │
│   ┌─────────────────────────┐ │
│   │ Inner packet:           │ │
│   │ Pod A → Pod B           │ │
│   └─────────────────────────┘ │
└───────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Node 2 strips off the outer wrapper and delivers the inner packet toward Pod B. That's the basic idea behind overlay networking, made concrete.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Overlays Exist
&lt;/h2&gt;

&lt;p&gt;Imagine your physical network only knows about Node 1 (&lt;code&gt;192.168.1.10&lt;/code&gt;) and Node 2 (&lt;code&gt;192.168.1.20&lt;/code&gt;) — it has no idea about &lt;code&gt;10.244.1.10&lt;/code&gt; or &lt;code&gt;10.244.2.20&lt;/code&gt;. The physical network doesn't need to know about every individual Pod route; instead, the overlay carries the Pod network &lt;em&gt;inside&lt;/em&gt; the Node network — literally, a network running over another network.&lt;/p&gt;

&lt;h2&gt;
  
  
  Routing-Based Networking
&lt;/h2&gt;

&lt;p&gt;An alternative to overlays: teach the physical network how to reach each Pod CIDR directly. Given &lt;code&gt;Node 1 → 10.244.1.0/24&lt;/code&gt; and &lt;code&gt;Node 2 → 10.244.2.0/24&lt;/code&gt;, Node 1 can simply have a route: &lt;code&gt;10.244.2.0/24 → Node 2&lt;/code&gt;. Then:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Pod A → Node 1 → route → Node 2 → Pod B
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No encapsulation required at all.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why BGP Sometimes Appears
&lt;/h2&gt;

&lt;p&gt;If many Nodes each own different Pod CIDRs, you need a way to distribute all those routes across the cluster. Some networking implementations use &lt;strong&gt;BGP (Border Gateway Protocol)&lt;/strong&gt; for exactly this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Node 1 (10.244.1.0/24) ↔ BGP ↔ Node 2 (10.244.2.0/24)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is exactly why BGP comes up so often in discussions of Calico and Kubernetes networking.&lt;/p&gt;

&lt;h2&gt;
  
  
  CNI vs the Linux Kernel
&lt;/h2&gt;

&lt;p&gt;An important distinction: &lt;strong&gt;the CNI/networking implementation doesn't replace Linux networking — it configures and uses it.&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CNI → configure → Linux networking → interfaces / routes / kernel dataplane
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For example: &lt;code&gt;CNI → create veth → Linux kernel&lt;/code&gt;, or &lt;code&gt;CNI → configure routes → Linux kernel&lt;/code&gt;, or &lt;code&gt;CNI → load eBPF programs → Linux kernel&lt;/code&gt;. The CNI is the orchestrator; the kernel is what actually does the work.&lt;/p&gt;

&lt;h2&gt;
  
  
  eBPF in the Internal Path
&lt;/h2&gt;

&lt;p&gt;Connecting Level 8 back to Level 9: with an eBPF-based CNI, packet processing might conceptually look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Pod → veth → Linux kernel → eBPF program → routing / policy / load balancing → destination
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The exact hook points and processing path depend on the specific implementation. The core concept to hold onto: &lt;strong&gt;eBPF lets a networking implementation inject programmable packet-processing logic directly into the Linux kernel.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  NetworkPolicy in the Packet Path
&lt;/h2&gt;

&lt;p&gt;Suppose a NetworkPolicy states &lt;code&gt;frontend → backend:8080 = ALLOW&lt;/code&gt;. The networking implementation has to enforce that somewhere along the path:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Packet → network dataplane → NetworkPolicy check → ALLOW → Backend
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or, alternatively:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Packet → NetworkPolicy check → DENY → ✗
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The exact enforcement point in the kernel depends on the implementation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Service + NetworkPolicy Together
&lt;/h2&gt;

&lt;p&gt;Now combine Service and NetworkPolicy. The Service selects backend Pods; NetworkPolicy applies restrictions to those Pods:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Frontend → Service IP → Service dataplane → Backend Pod → NetworkPolicy enforcement
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The exact ordering within the kernel can vary by implementation — don't treat this as a strict, universal literal sequence. The important conceptual point: &lt;strong&gt;the Service selects and forwards toward backend Pods; NetworkPolicy controls what Pod traffic is actually allowed.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Services Don't Have Network Interfaces
&lt;/h2&gt;

&lt;p&gt;An excellent interview question. You might assume the Service IP &lt;code&gt;10.96.120.50&lt;/code&gt; must correspond to some &lt;code&gt;eth0&lt;/code&gt; somewhere — but that's usually the wrong way to think about it. A &lt;strong&gt;ClusterIP is a virtual IP implemented by the Service dataplane&lt;/strong&gt;, not a physical interface:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ClusterIP (10.96.120.50) → virtual service → backend endpoints
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It simply doesn't need to be — and usually isn't — a physical network interface anywhere.&lt;/p&gt;

&lt;h2&gt;
  
  
  Node IP vs Pod IP vs Service IP
&lt;/h2&gt;

&lt;p&gt;By Level 9, you should be completely comfortable distinguishing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Node IP    (192.168.1.10)  → physical/VM host networking
Pod IP     (10.244.1.10)   → workload networking
Service IP (10.96.120.50)  → virtual service endpoint
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three distinct layers, each solving a different problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Pod IPs Aren't Directly Routable from the Internet
&lt;/h2&gt;

&lt;p&gt;A Pod's IP, like &lt;code&gt;10.244.1.10&lt;/code&gt;, is generally an internal cluster address — an internet router has no idea how to reach &lt;code&gt;10.244.1.0/24&lt;/code&gt;. That's exactly why external access normally has to go through a LoadBalancer, NodePort, Ingress, Gateway, NAT, or some form of cloud-native networking, depending on your architecture.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Full External Traffic Example
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Internet
    ↓
Public IP
    ↓
Load Balancer
    ↓
Node
    ↓
Service dataplane
    ↓
Pod
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Zooming into the Node itself: &lt;code&gt;Node → iptables/IPVS/eBPF → Pod&lt;/code&gt;. And zooming into the Pod: &lt;code&gt;Pod namespace → eth0 → veth → Node&lt;/code&gt;. Now you can see exactly how all these layers connect into one continuous path.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Complete Kubernetes Networking Stack
&lt;/h2&gt;

&lt;p&gt;This is the single diagram worth remembering from this entire article:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                         INTERNET
                            |
                            ↓
                    LoadBalancer / Ingress
                            |
                            ↓
                         Node
                            |
                ┌───────────┴───────────┐
                │ Linux kernel          │
                │                       │
                │ Service dataplane     │
                │ iptables / IPVS /     │
                │ eBPF                  │
                │                       │
                │ conntrack / NAT       │
                │                       │
                │ routing               │
                └───────────┬───────────┘
                            |
                          veth
                            |
                     Pod namespace
                            |
                           eth0
                            |
                           Pod
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And across Nodes: &lt;code&gt;Pod → veth → Node 1 → Node-to-Node network → Node 2 → veth → Pod&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Real Packet Journey, Start to Finish
&lt;/h2&gt;

&lt;p&gt;Let's trace one complete, concrete example. We have Frontend Pod &lt;code&gt;10.244.1.10&lt;/code&gt;, Backend Service &lt;code&gt;10.96.120.50:80&lt;/code&gt; (with &lt;code&gt;port: 80&lt;/code&gt;, &lt;code&gt;targetPort: 8080&lt;/code&gt;), and Backend Pod &lt;code&gt;10.244.2.20:8080&lt;/code&gt;. The frontend runs &lt;code&gt;curl http://backend&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1 — DNS:&lt;/strong&gt; &lt;code&gt;backend → 10.96.120.50&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2 — TCP connection:&lt;/strong&gt; the frontend creates a packet with &lt;code&gt;SRC = 10.244.1.10:&amp;lt;ephemeral-port&amp;gt;&lt;/code&gt;, &lt;code&gt;DST = 10.96.120.50:80&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3 — Pod namespace routing:&lt;/strong&gt; the packet leaves through the Pod's &lt;code&gt;eth0&lt;/code&gt; and crosses the veth pair.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 4 — Node kernel:&lt;/strong&gt; the Node's networking stack now processes it — potentially involving routing, conntrack, the Service dataplane, NetworkPolicy, and NAT, depending on the implementation and packet path.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 5 — Service translation:&lt;/strong&gt; the Service dataplane knows &lt;code&gt;10.96.120.50:80&lt;/code&gt; should map to &lt;code&gt;10.244.2.20:8080&lt;/code&gt;, and performs that translation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 6 — Route to backend:&lt;/strong&gt; the networking layer determines how to actually reach &lt;code&gt;10.244.2.20&lt;/code&gt; — if the backend lives on another Node, this involves &lt;code&gt;Node 1 → Node network → Node 2&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 7 — Backend Node:&lt;/strong&gt; Node 2 receives the packet, processes it through its own networking implementation, and delivers it: &lt;code&gt;veth → Pod namespace → eth0 → backend application&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Return Traffic
&lt;/h2&gt;

&lt;p&gt;The backend responds: &lt;code&gt;Backend (10.244.2.20:8080) → Frontend (10.244.1.10:&amp;lt;port&amp;gt;)&lt;/code&gt;. The Linux networking stack's NAT and connection-tracking state ensures the response correctly maps back through the original Service connection. Crucially, the frontend application never needs to know the backend Pod's real IP was &lt;code&gt;10.244.2.20&lt;/code&gt; — it only ever knew it connected to &lt;code&gt;backend:80&lt;/code&gt;. That abstraction is the entire point.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Can Break
&lt;/h2&gt;

&lt;p&gt;We're now firmly in production troubleshooting territory. This full packet journey can fail at many distinct points:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DNS → Service → EndpointSlice → Service dataplane → routing → CNI → NetworkPolicy → Pod → application
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Possible failure modes include: DNS not resolving, a Service with no endpoints, a wrong &lt;code&gt;targetPort&lt;/code&gt;, incorrect iptables/IPVS/eBPF state, a missing route, a broken veth, a Pod with no IP, a CNI failure, NetworkPolicy blocking traffic, conntrack problems, a Node-level firewall, a cloud network ACL or security group, or simply an application that isn't listening. This is exactly why Level 10 will feel much more approachable after this article.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Most Important Troubleshooting Principle
&lt;/h2&gt;

&lt;p&gt;Don't ask: &lt;em&gt;"Kubernetes networking is broken — what command should I run?"&lt;/em&gt; Instead ask:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;"At which hop did the packet actually stop?"&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For example, if DNS works, the Service exists, the endpoint exists, and the Pod IP is directly reachable — but the Service IP specifically fails — that strongly points toward the &lt;strong&gt;Service dataplane&lt;/strong&gt;, not CNI. Alternatively, if &lt;code&gt;Pod IP → Pod IP&lt;/code&gt; fails outright, that points much more toward &lt;strong&gt;CNI, routing, or NetworkPolicy.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Direct Pod IP vs Service IP: The Best Diagnostic Test
&lt;/h2&gt;

&lt;p&gt;This single comparison is one of the most valuable troubleshooting techniques in Kubernetes networking. Test &lt;code&gt;Pod A → Pod B IP&lt;/code&gt; directly, then test &lt;code&gt;Pod A → Service IP&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If the Pod IP works but the Service IP fails:&lt;/strong&gt; the likely culprit is the Service, its EndpointSlice, or the Service dataplane (kube-proxy/eBPF).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If both the Pod IP and the Service IP fail:&lt;/strong&gt; investigate lower layers instead — CNI, routing, veth, NetworkPolicy, or Node networking.&lt;/p&gt;

&lt;p&gt;This simple two-step comparison narrows down the problem space dramatically before you touch a single low-level command.&lt;/p&gt;

&lt;h2&gt;
  
  
  Useful Linux Commands
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Inside a Pod:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ip addr    &lt;span class="c"&gt;# interfaces/IPs&lt;/span&gt;
ip route   &lt;span class="c"&gt;# routes&lt;/span&gt;
ss &lt;span class="nt"&gt;-lntp&lt;/span&gt;   &lt;span class="c"&gt;# listening TCP sockets&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;On a Node:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ip addr
ip route
ip &lt;span class="nb"&gt;link&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These commands together help you understand exactly what interfaces, addresses, and routes actually exist at each layer.&lt;/p&gt;

&lt;h3&gt;
  
  
  Seeing veth Interfaces
&lt;/h3&gt;

&lt;p&gt;On a Node, &lt;code&gt;ip link&lt;/code&gt; may reveal interfaces belonging to Pod networking — often named &lt;code&gt;veth...&lt;/code&gt; or something CNI-specific. Don't assume any particular naming pattern always maps to a specific CNI; interface naming is implementation-dependent.&lt;/p&gt;

&lt;h3&gt;
  
  
  Seeing Routes
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;ip route&lt;/code&gt; on a Node may show entries like &lt;code&gt;10.244.1.0/24 ...&lt;/code&gt; and &lt;code&gt;10.244.2.0/24 ...&lt;/code&gt;, telling Linux exactly where Pod traffic should be directed. Again, the actual routes present depend entirely on your CNI.&lt;/p&gt;

&lt;h3&gt;
  
  
  Seeing iptables
&lt;/h3&gt;

&lt;p&gt;If your cluster uses an iptables-based dataplane:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;iptables-save
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This can reveal a large volume of Kubernetes-related networking state, including Kubernetes-specific chains. Don't worry about memorizing chain names yet — just understand conceptually that &lt;code&gt;iptables rules → Service / NAT / filtering behavior&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Seeing IPVS
&lt;/h3&gt;

&lt;p&gt;If your cluster uses IPVS:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ipvsadm &lt;span class="nt"&gt;-L&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This may show virtual services and their backend destinations, conceptually:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;10.96.120.50:80
       +--- 10.244.1.20:80
       +--- 10.244.2.20:80
       +--- 10.244.3.20:80
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Seeing eBPF
&lt;/h3&gt;

&lt;p&gt;If your cluster uses an eBPF-based implementation like Cilium, its own tooling can show endpoints, routes, service maps, policy state, and connectivity — the exact commands vary by implementation. The key Level 9 lesson here: &lt;strong&gt;don't inspect iptables just because you happen to know iptables — first determine which dataplane your cluster actually uses.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Interview Traps Worth Knowing
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;"Does every Kubernetes cluster use kube-proxy?"&lt;/strong&gt;&lt;br&gt;
No. Many clusters do, but alternative networking dataplanes can implement Kubernetes Service functionality without it — an eBPF-based implementation can provide full kube-proxy replacement.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;"Does every CNI use a Linux bridge?"&lt;/strong&gt;&lt;br&gt;
No. Possible approaches include bridging, routing, overlays, cloud-native networking, and eBPF — the implementation determines the actual datapath.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;"Is the Service IP configured on a Pod?"&lt;/strong&gt;&lt;br&gt;
No. A ClusterIP is a virtual Service address implemented by the Service dataplane; backend Pods each have their own separate, real IPs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;"Does the CNI forward Service traffic?"&lt;/strong&gt;&lt;br&gt;
The precise answer: CNI/networking provides Pod networking, while Kubernetes Service traffic is implemented by a separate Service dataplane — kube-proxy/iptables/IPVS, or an eBPF-based networking implementation. The exact packet path depends on the cluster. That's a far better answer than simply saying "CNI handles everything."&lt;/p&gt;
&lt;h2&gt;
  
  
  The Entire Series So Far
&lt;/h2&gt;

&lt;p&gt;We can now connect all nine levels into one continuous story:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;LEVEL 0 — Linux networking      → interfaces / routes / namespaces / NAT
LEVEL 1 — Pod networking        → Pod namespace / eth0 / veth
LEVEL 2 — Pod-to-Pod            → routing / node networking
LEVEL 3 — Services              → ClusterIP / endpoints
LEVEL 4 — DNS                   → Service name → ClusterIP
LEVEL 5 — Ingress / Gateway     → external HTTP/HTTPS → Service
LEVEL 6 — NetworkPolicy         → allowed network traffic
LEVEL 7 — CNI                   → Pod network implementation
LEVEL 8 — Service dataplane     → kube-proxy / iptables / IPVS / eBPF
LEVEL 9 — Internals             → Linux kernel packet path
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Level 9 Checkpoint
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. What is a network namespace?&lt;/strong&gt;&lt;br&gt;
An isolated Linux networking environment with its own interfaces, addresses, routes, and network state.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. What is a veth pair?&lt;/strong&gt;&lt;br&gt;
A pair of virtual Ethernet interfaces commonly used to connect a Pod's network namespace to the Node.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. What is a Linux bridge?&lt;/strong&gt;&lt;br&gt;
A virtual Layer-2 switch that can connect multiple interfaces together.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Does every CNI use a bridge?&lt;/strong&gt;&lt;br&gt;
No.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. What is routing?&lt;/strong&gt;&lt;br&gt;
The process of deciding where a packet should be sent, based on its destination address.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6. What is DNAT?&lt;/strong&gt;&lt;br&gt;
Changing a packet's destination address/port — the common Kubernetes example is &lt;code&gt;Service IP → backend Pod IP&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;7. What is SNAT?&lt;/strong&gt;&lt;br&gt;
Changing a packet's source address/port — a common example is &lt;code&gt;Pod IP → Node IP&lt;/code&gt; when traffic leaves the cluster, depending on configuration.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;8. What is conntrack?&lt;/strong&gt;&lt;br&gt;
Linux's connection tracking mechanism, which maintains state about network flows, including NAT state.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;9. What is an overlay?&lt;/strong&gt;&lt;br&gt;
A virtual network carried on top of another underlying network — a Pod network riding over a Node network.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;10. Why can BGP be used?&lt;/strong&gt;&lt;br&gt;
To distribute routing information, such as routes to individual Pod CIDRs, across Nodes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;11. Why doesn't every Kubernetes cluster have the same packet path?&lt;/strong&gt;&lt;br&gt;
Because networking implementations and dataplanes genuinely differ from cluster to cluster.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;12. How should you troubleshoot?&lt;/strong&gt;&lt;br&gt;
Find the first hop where the packet actually stops.&lt;/p&gt;
&lt;h2&gt;
  
  
  The Most Important Lesson From This Article
&lt;/h2&gt;

&lt;p&gt;Don't memorize: &lt;em&gt;"packets always go through iptables → bridge → veth."&lt;/em&gt; That's far too simplistic and, frankly, often wrong. Instead, memorize the general shape:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Pod namespace
     ↓
Pod interface
     ↓
Node networking
     ↓
Service dataplane (if Service traffic)
     ↓
routing / NAT / policy / kernel dataplane
     ↓
destination network
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then always ask: &lt;em&gt;"Which implementation is my cluster actually using?"&lt;/em&gt; That single question determines the real, concrete path your packets take.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Next: Production Troubleshooting
&lt;/h2&gt;

&lt;p&gt;In &lt;strong&gt;Level 10&lt;/strong&gt;, we stop learning isolated components and start diagnosing real failures: a Pod that can't reach another Pod, a Pod that can't reach a Service, a Service with no endpoints, DNS that works while &lt;code&gt;curl&lt;/code&gt; still fails, an Ingress returning 502/504, a NetworkPolicy that accidentally broke DNS, traffic that only fails across Nodes, a single misbehaving Node, intermittent connection failures, conntrack exhaustion, MTU problems, and outright CNI failures. That's where this entire 0-to-9 journey turns into a genuinely practical troubleshooting methodology.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Kubernetes networking internals aren't actually magic — they're Linux networking primitives (namespaces, veth pairs, routing tables, Netfilter, conntrack) orchestrated by a CNI and a Service dataplane. The single biggest shift in this article is moving from &lt;em&gt;"Pod talks to Pod"&lt;/em&gt; as an abstraction to actually tracing a packet through real kernel mechanisms: crossing a veth pair, hitting a routing decision, potentially getting DNAT'd by a Service dataplane, and having its connection state tracked by conntrack the entire way.&lt;/p&gt;

&lt;p&gt;The most valuable habit from this entire article: when something breaks, don't guess at commands — ask &lt;em&gt;"at which hop did the packet actually stop?"&lt;/em&gt; and use the Pod-IP-vs-Service-IP test to instantly narrow down whether you're dealing with a CNI-layer problem or a Service-layer problem.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Enjoyed this deep dive?&lt;/strong&gt; Follow along for Level 10, where we turn this entire series into a hands-on production troubleshooting methodology. Drop your questions in the comments, and share this with a teammate who's still treating Kubernetes networking as an unexplainable black box. Let's finish building this Kubernetes networking roadmap together. 🚀&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>kubernetes</category>
      <category>linux</category>
      <category>networking</category>
    </item>
    <item>
      <title>Kubernetes Networking [Level-8: kube-proxy / iptables / IPVS / eBPF]</title>
      <dc:creator>ADITYA RAJ</dc:creator>
      <pubDate>Wed, 19 Aug 2026 12:02:50 +0000</pubDate>
      <link>https://dev.to/iadiraj/kubernetes-networking-level-8-kube-proxy-iptables-ipvs-ebpf-4alm</link>
      <guid>https://dev.to/iadiraj/kubernetes-networking-level-8-kube-proxy-iptables-ipvs-ebpf-4alm</guid>
      <description>&lt;p&gt;This is &lt;strong&gt;Level 8&lt;/strong&gt; of our Kubernetes networking series, and it's where we finally go inside the &lt;strong&gt;Service dataplane&lt;/strong&gt;. Back in Level 3, we learned that a client Pod talks to a Service's ClusterIP, which somehow routes traffic to a backend Pod:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Client Pod → Service (10.96.120.50:80) → Backend Pod (10.244.1.10:80)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We deliberately left one question unanswered until now: &lt;strong&gt;how does traffic sent to that Service IP actually end up at a real Pod?&lt;/strong&gt; That's exactly what this article unpacks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;The Problem: A Service IP Isn't a Real Interface&lt;/li&gt;
&lt;li&gt;The Basic Idea: A Service Dataplane&lt;/li&gt;
&lt;li&gt;What Is kube-proxy?&lt;/li&gt;
&lt;li&gt;kube-proxy's Job&lt;/li&gt;
&lt;li&gt;kube-proxy Doesn't Create Pods&lt;/li&gt;
&lt;li&gt;kube-proxy Runs on Every Node&lt;/li&gt;
&lt;li&gt;The Classic Mental Model: iptables and DNAT&lt;/li&gt;
&lt;li&gt;What Is DNAT?&lt;/li&gt;
&lt;li&gt;Tracing the Packet Journey&lt;/li&gt;
&lt;li&gt;The Full Picture: DNS to Pod&lt;/li&gt;
&lt;li&gt;iptables in Kubernetes&lt;/li&gt;
&lt;li&gt;Control Plane vs Dataplane&lt;/li&gt;
&lt;li&gt;Why EndpointSlices Matter Here&lt;/li&gt;
&lt;li&gt;Load Balancing Across Endpoints&lt;/li&gt;
&lt;li&gt;Session Affinity&lt;/li&gt;
&lt;li&gt;The Scaling Problem with iptables&lt;/li&gt;
&lt;li&gt;IPVS: IP Virtual Server&lt;/li&gt;
&lt;li&gt;iptables vs IPVS&lt;/li&gt;
&lt;li&gt;An Important Modern Nuance&lt;/li&gt;
&lt;li&gt;eBPF Enters the Picture&lt;/li&gt;
&lt;li&gt;Why eBPF Is Interesting for Kubernetes&lt;/li&gt;
&lt;li&gt;Cilium and eBPF&lt;/li&gt;
&lt;li&gt;eBPF Can Replace Parts of kube-proxy&lt;/li&gt;
&lt;li&gt;Don't Confuse kube-proxy Replacement with CNI&lt;/li&gt;
&lt;li&gt;Three Generations to Remember&lt;/li&gt;
&lt;li&gt;What kube-proxy Actually Watches&lt;/li&gt;
&lt;li&gt;Why Services Survive Pod Churn&lt;/li&gt;
&lt;li&gt;Where CNI Fits Into All of This&lt;/li&gt;
&lt;li&gt;Service vs CNI vs kube-proxy: A Reference Table&lt;/li&gt;
&lt;li&gt;Following One Complete Packet&lt;/li&gt;
&lt;li&gt;What Is SNAT?&lt;/li&gt;
&lt;li&gt;Why SNAT Is Needed&lt;/li&gt;
&lt;li&gt;DNAT vs SNAT&lt;/li&gt;
&lt;li&gt;Why Return Traffic Works&lt;/li&gt;
&lt;li&gt;NodePort, Revisited&lt;/li&gt;
&lt;li&gt;LoadBalancer, Revisited&lt;/li&gt;
&lt;li&gt;A Layered Troubleshooting Model&lt;/li&gt;
&lt;li&gt;A Production Troubleshooting Tree&lt;/li&gt;
&lt;li&gt;What to Inspect on a Node&lt;/li&gt;
&lt;li&gt;How Do I Know Which Dataplane I'm Using?&lt;/li&gt;
&lt;li&gt;The Most Important Conceptual Separation&lt;/li&gt;
&lt;li&gt;Interview Questions&lt;/li&gt;
&lt;li&gt;Level 8 Mental Model&lt;/li&gt;
&lt;li&gt;What's Next: Kubernetes Networking Internals&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  The Problem: A Service IP Isn't a Real Interface
&lt;/h2&gt;

&lt;p&gt;Suppose we have a &lt;code&gt;frontend&lt;/code&gt; Pod at &lt;code&gt;10.244.1.5&lt;/code&gt;, and a Service named &lt;code&gt;backend&lt;/code&gt; with ClusterIP &lt;code&gt;10.96.120.50:80&lt;/code&gt;, backed by three Pods:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;10.244.1.10:80
10.244.2.10:80
10.244.3.10:80
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The frontend runs &lt;code&gt;curl http://backend:80&lt;/code&gt;. DNS resolves &lt;code&gt;backend → 10.96.120.50&lt;/code&gt;, so the outgoing packet looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SOURCE:      10.244.1.5
DESTINATION: 10.96.120.50:80
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here's the strange part: &lt;code&gt;10.96.120.50&lt;/code&gt; usually isn't a real, physical network interface attached to any Pod. So &lt;strong&gt;who transforms &lt;code&gt;10.96.120.50:80&lt;/code&gt; into something like &lt;code&gt;10.244.2.10:80&lt;/code&gt;?&lt;/strong&gt; That transformation is the job of the &lt;strong&gt;Service dataplane&lt;/strong&gt; — and that's exactly what this article is about.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Basic Idea: A Service Dataplane
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Service (10.96.120.50:80)
       ↓
Service dataplane
       ↓
Backend Pod (10.244.2.10:80)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Historically, Kubernetes clusters implemented this using &lt;strong&gt;kube-proxy&lt;/strong&gt;. Modern clusters can implement it very differently. The core concepts we need to understand across this article are: &lt;strong&gt;kube-proxy, iptables, IPVS,&lt;/strong&gt; and &lt;strong&gt;eBPF&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is kube-proxy?
&lt;/h2&gt;

&lt;p&gt;Despite its name, &lt;strong&gt;kube-proxy isn't simply a traditional HTTP proxy&lt;/strong&gt; — that's a genuinely useful interview point to remember. kube-proxy is a component that helps implement Kubernetes Service networking on each Node:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Service
   ↓
kube-proxy / service dataplane
   ↓
backend Pods
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It watches Kubernetes objects — specifically &lt;strong&gt;Services&lt;/strong&gt; and &lt;strong&gt;EndpointSlices&lt;/strong&gt; — and programs the Node's networking rules/dataplane to match what it observes.&lt;/p&gt;

&lt;h2&gt;
  
  
  kube-proxy's Job
&lt;/h2&gt;

&lt;p&gt;Given a Service &lt;code&gt;backend&lt;/code&gt; at &lt;code&gt;10.96.120.50:80&lt;/code&gt; with EndpointSlice entries pointing to &lt;code&gt;10.244.1.10:80&lt;/code&gt;, &lt;code&gt;10.244.2.10:80&lt;/code&gt;, and &lt;code&gt;10.244.3.10:80&lt;/code&gt;, kube-proxy's conceptual job is simple:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"When traffic arrives for this Service IP and port, send it to one of these backend endpoints."&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;10.96.120.50:80
        ↓
 ┌──────┼──────┐
 ↓      ↓      ↓
Pod 1  Pod 2  Pod 3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  kube-proxy Doesn't Create Pods
&lt;/h2&gt;

&lt;p&gt;Another important distinction worth locking in:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Deployment        → creates/manages Pods
Service           → defines a stable endpoint
kube-proxy/dataplane → implements Service traffic forwarding
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three genuinely different responsibilities, each handled by a different component.&lt;/p&gt;

&lt;h2&gt;
  
  
  kube-proxy Runs on Every Node
&lt;/h2&gt;

&lt;p&gt;kube-proxy typically runs as a &lt;strong&gt;DaemonSet&lt;/strong&gt;, so every Node gets its own instance:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Node 1 → Pods + kube-proxy
Node 2 → Pods + kube-proxy
Node 3 → Pods + kube-proxy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each Node needs the ability to handle Service traffic that arrives locally.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Classic Mental Model: iptables and DNAT
&lt;/h2&gt;

&lt;p&gt;Historically, kube-proxy commonly programmed &lt;strong&gt;iptables&lt;/strong&gt; rules to do this work:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Pod
 ↓
Service IP
 ↓
iptables rules
 ↓
DNAT
 ↓
Pod IP
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The key term here is &lt;strong&gt;DNAT&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is DNAT?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;DNAT = Destination Network Address Translation.&lt;/strong&gt; Suppose a packet starts out as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SOURCE:      10.244.1.5
DESTINATION: 10.96.120.50:80
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Service dataplane can rewrite the &lt;em&gt;destination&lt;/em&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SOURCE:      10.244.1.5
DESTINATION: 10.244.2.10:80
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So &lt;code&gt;10.96.120.50 → 10.244.2.10&lt;/code&gt; — that transformation is destination NAT in action.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tracing the Packet Journey
&lt;/h2&gt;

&lt;p&gt;Let's slow this down and walk through it explicitly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Frontend:&lt;/strong&gt; &lt;code&gt;10.244.1.5&lt;/code&gt; — &lt;strong&gt;Service:&lt;/strong&gt; &lt;code&gt;10.96.120.50:80&lt;/code&gt; — &lt;strong&gt;Backend:&lt;/strong&gt; &lt;code&gt;10.244.2.10:80&lt;/code&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The frontend sends a packet: &lt;code&gt;SRC = 10.244.1.5&lt;/code&gt;, &lt;code&gt;DST = 10.96.120.50:80&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The Node's Service dataplane recognizes &lt;code&gt;10.96.120.50:80&lt;/code&gt; and selects a backend, say &lt;code&gt;10.244.2.10:80&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The packet effectively becomes: &lt;code&gt;SRC = 10.244.1.5&lt;/code&gt;, &lt;code&gt;DST = 10.244.2.10:80&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;From here, normal Pod networking (CNI, covered in Level 7) takes over and delivers it.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The Full Picture: DNS to Pod
&lt;/h2&gt;

&lt;p&gt;Connecting this back to Level 4:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Pod
 ↓
DNS
 ↓
Service name
 ↓
ClusterIP
 ↓
Service dataplane
 ↓
Endpoint
 ↓
Pod IP
 ↓
CNI networking
 ↓
destination Pod
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or, with concrete values:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;frontend (10.244.1.5)
   | "backend"
   ↓
DNS
   ↓
10.96.120.50
   ↓
Service dataplane
   ↓
10.244.2.10
   ↓
CNI
   ↓
backend Pod
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  iptables in Kubernetes
&lt;/h2&gt;

&lt;p&gt;Linux has a built-in packet-filtering and NAT framework called &lt;strong&gt;iptables&lt;/strong&gt;. Kubernetes can program iptables rules so that Service traffic gets redirected to the correct backend endpoint:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Packet
  ↓
iptables
  ↓
Service rule
  ↓
Backend selection
  ↓
DNAT
  ↓
Pod
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Conceptually, given a Service at &lt;code&gt;10.96.120.50:80&lt;/code&gt; with endpoints &lt;code&gt;10.244.1.10:80&lt;/code&gt;, &lt;code&gt;10.244.2.10:80&lt;/code&gt;, and &lt;code&gt;10.244.3.10:80&lt;/code&gt;, the Node might carry rules that resemble: &lt;em&gt;"traffic to &lt;code&gt;10.96.120.50:80&lt;/code&gt; → choose an endpoint → DNAT to one of the three addresses above."&lt;/em&gt; Real Kubernetes iptables rule sets are considerably more complex than this simplification — don't worry about memorizing actual chain names yet.&lt;/p&gt;

&lt;h2&gt;
  
  
  Control Plane vs Dataplane
&lt;/h2&gt;

&lt;p&gt;It helps to think of Kubernetes networking in two layers:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Control plane&lt;/strong&gt; decides &lt;em&gt;what should happen&lt;/em&gt;: which Pods exist, which Services exist, which endpoints belong to a Service.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dataplane&lt;/strong&gt; actually &lt;em&gt;handles packets&lt;/em&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Control plane → "Service backend Pods are A, B, C"
      ↓
Dataplane → "Send packets to A/B/C"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Why EndpointSlices Matter Here
&lt;/h2&gt;

&lt;p&gt;Recall from Level 3: a Service like &lt;code&gt;backend&lt;/code&gt; has an associated EndpointSlice listing its live backend IPs. The Service dataplane depends directly on this information:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Service + EndpointSlice → Service dataplane → forwarding rules
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Without accurate, up-to-date EndpointSlice data, the dataplane has nothing correct to forward traffic to.&lt;/p&gt;

&lt;h2&gt;
  
  
  Load Balancing Across Endpoints
&lt;/h2&gt;

&lt;p&gt;Given a Service with three backend Pods, a connection to the Service might land on any one of them:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Request 1 → Pod A
Request 2 → Pod C
Request 3 → Pod B
Request 4 → Pod A
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The exact algorithm and distribution behavior depends on the dataplane implementation and configuration. The key idea to hold onto: &lt;strong&gt;the Service is a stable front door, while the dataplane is what actually selects a backend endpoint for each connection.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Session Affinity
&lt;/h2&gt;

&lt;p&gt;Kubernetes Services can optionally enable &lt;strong&gt;session affinity&lt;/strong&gt;, e.g.:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;sessionAffinity&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ClientIP&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this enabled, the same client tends to keep landing on the same backend Pod:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Client A → Pod A
Client A → Pod A
Client A → Pod A
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Again, the precise implementation details depend on which dataplane your cluster is running.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Scaling Problem with iptables
&lt;/h2&gt;

&lt;p&gt;The classic &lt;code&gt;kube-proxy → iptables → DNAT → Pod&lt;/code&gt; flow works well for many clusters. But there's a scaling consideration: compare 10 Services with 100 total endpoints to 10,000 Services with 100,000 total endpoints. The volume of networking rules involved can grow enormous. This is exactly the pressure that led to &lt;strong&gt;IPVS&lt;/strong&gt;, and eventually to &lt;strong&gt;eBPF&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  IPVS: IP Virtual Server
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;IPVS&lt;/strong&gt; stands for &lt;strong&gt;IP Virtual Server&lt;/strong&gt; — a Linux kernel technology purpose-built for high-performance load balancing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Service IP (10.96.120.50:80)
       ↓
      IPVS
       ↓
 ┌───┼───┐
 ↓   ↓   ↓
Pod A Pod B Pod C
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Instead of thinking in terms of a long chain of packet-filter rules, think of IPVS as a kernel-level virtual server / load-balancing mechanism purpose-built for exactly this job.&lt;/p&gt;

&lt;h2&gt;
  
  
  iptables vs IPVS
&lt;/h2&gt;

&lt;p&gt;Simplified comparison:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;iptables:&lt;/strong&gt; &lt;code&gt;packet → rules → rules → rules → backend&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;IPVS:&lt;/strong&gt; &lt;code&gt;packet → virtual service → backend selection&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;IPVS can offer more specialized load-balancing behavior, and historically was attractive for clusters with large numbers of Services thanks to its performance characteristics. That said, modern Kubernetes networking has moved beyond simply choosing between these two — eBPF-based dataplanes are increasingly significant.&lt;/p&gt;

&lt;h2&gt;
  
  
  An Important Modern Nuance
&lt;/h2&gt;

&lt;p&gt;You may hear the claim: &lt;em&gt;"IPVS is always faster than iptables."&lt;/em&gt; Don't treat that as an absolute rule. Real-world performance depends on cluster size, traffic patterns, kernel version, configuration, the specific dataplane implementation, and even the underlying hardware. The important conceptual difference to remember is simpler:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;iptables → packet filtering/NAT rules
IPVS     → kernel virtual-server load balancing
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  eBPF Enters the Picture
&lt;/h2&gt;

&lt;p&gt;Now we reach a genuinely important modern technology: &lt;strong&gt;eBPF&lt;/strong&gt;. You don't need to master every detail yet — at a high level:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;eBPF = programmable logic that can run inside the Linux kernel.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This lets networking systems perform operations directly in the kernel, rather than bouncing through separate userspace components or long rule chains.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why eBPF Is Interesting for Kubernetes
&lt;/h2&gt;

&lt;p&gt;The traditional path looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Packet → iptables rules → NAT → routing
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;An eBPF-based networking implementation can inject custom packet-processing logic straight into the kernel:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Packet → eBPF program → routing / load balancing / policy → destination
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This can avoid some of the overhead inherent in traditional networking paths and enables much more flexible dataplane behavior.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cilium and eBPF
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Cilium&lt;/strong&gt; is one of the best-known Kubernetes networking implementations built on eBPF:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Kubernetes → Cilium → eBPF → Linux kernel → networking + load balancing + NetworkPolicy + observability
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is exactly why Cilium came up briefly back in Level 7 — and now the pieces should be clicking into place.&lt;/p&gt;

&lt;h2&gt;
  
  
  eBPF Can Replace Parts of kube-proxy
&lt;/h2&gt;

&lt;p&gt;This is an important, genuinely modern Kubernetes concept. Some eBPF-based networking implementations can provide Service load balancing entirely on their own. Instead of:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Service → kube-proxy → iptables → Pod
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;you can have:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Service → eBPF dataplane → Pod
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In such a setup, kube-proxy may not even be needed for Service handling at all. This is commonly referred to as &lt;strong&gt;"kube-proxy replacement,"&lt;/strong&gt; and Cilium is a well-known example of a system that offers it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Don't Confuse kube-proxy Replacement with CNI
&lt;/h2&gt;

&lt;p&gt;Keep these terms distinct in your head:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CNI                   = networking interface/ecosystem
Cilium                = a networking implementation
eBPF                  = a kernel technology
kube-proxy replacement = one specific capability/configuration
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;They're related, but not interchangeable. A cleaner way to see the relationship:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Cilium → uses eBPF → can implement Kubernetes networking → can provide Service load balancing → can replace kube-proxy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Three Generations to Remember
&lt;/h2&gt;

&lt;p&gt;A simple learning model for Service traffic handling:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                    Service traffic

                       Service IP
                           |
            ┌──────────────┼──────────────┐
            ↓              ↓              ↓
         iptables         IPVS           eBPF
            ↓              ↓              ↓
        kernel rules   virtual server   kernel programs
            ↓              ↓              ↓
                         Pod
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This isn't a strict historical replacement chain — real clusters can (and do) use any of these approaches — but it's a useful conceptual comparison to keep handy.&lt;/p&gt;

&lt;h2&gt;
  
  
  What kube-proxy Actually Watches
&lt;/h2&gt;

&lt;p&gt;kube-proxy needs live information about &lt;strong&gt;Services&lt;/strong&gt; and &lt;strong&gt;EndpointSlices&lt;/strong&gt;. Whenever something changes — a Pod is added or removed, a Service is updated, an endpoint changes — the Service dataplane needs to be kept in sync:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;EndpointSlice changes
        ↓
kube-proxy/dataplane notices
        ↓
forwarding state updated
        ↓
new traffic uses current endpoints
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is precisely how Kubernetes handles the constant churn of dynamic Pods without breaking client connectivity.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Services Survive Pod Churn
&lt;/h2&gt;

&lt;p&gt;Suppose Service &lt;code&gt;backend&lt;/code&gt; (&lt;code&gt;10.96.120.50&lt;/code&gt;) initially has Pod A (&lt;code&gt;10.244.1.10&lt;/code&gt;) and Pod B (&lt;code&gt;10.244.2.10&lt;/code&gt;) as backends. Pod A dies, and a new Pod C (&lt;code&gt;10.244.3.10&lt;/code&gt;) appears. The EndpointSlice updates:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;OLD: A, B
NEW: B, C
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But the Service IP itself never changes — it stays &lt;code&gt;10.96.120.50&lt;/code&gt;. The dataplane simply updates its internal backend information, and clients keep using &lt;code&gt;backend&lt;/code&gt; without ever needing to know that a Pod was replaced underneath them. This is one of the single most powerful abstractions in all of Kubernetes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where CNI Fits Into All of This
&lt;/h2&gt;

&lt;p&gt;Combining Level 7 and Level 8: &lt;strong&gt;CNI&lt;/strong&gt; provides the underlying Pod network:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Pod → eth0 → veth → Node → Pod network
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;strong&gt;Service dataplane&lt;/strong&gt; provides Service-level forwarding:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Service IP → backend Pod
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Together:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                    Kubernetes networking

Pod
 | CNI
 ↓
Pod network
 ↓
Service dataplane
 ↓
another Pod
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The exact ordering within the Linux packet path can get more nuanced in practice, but this separation of responsibilities is the key mental model to carry forward.&lt;/p&gt;

&lt;h2&gt;
  
  
  Service vs CNI vs kube-proxy: A Reference Table
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Component&lt;/th&gt;
&lt;th&gt;Main Job&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;CNI/network implementation&lt;/td&gt;
&lt;td&gt;Pod networking&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;IPAM&lt;/td&gt;
&lt;td&gt;Pod IP allocation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Service&lt;/td&gt;
&lt;td&gt;Stable virtual endpoint&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;EndpointSlice&lt;/td&gt;
&lt;td&gt;Backend endpoint information&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;kube-proxy&lt;/td&gt;
&lt;td&gt;Traditional Service dataplane implementation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;iptables&lt;/td&gt;
&lt;td&gt;Linux packet filtering/NAT framework&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;IPVS&lt;/td&gt;
&lt;td&gt;Linux virtual-server load balancing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;eBPF&lt;/td&gt;
&lt;td&gt;Programmable kernel dataplane technology&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Following One Complete Packet
&lt;/h2&gt;

&lt;p&gt;Let's trace one full request end-to-end. We have &lt;code&gt;frontend&lt;/code&gt; (&lt;code&gt;10.244.1.5&lt;/code&gt;), Service &lt;code&gt;backend&lt;/code&gt; (&lt;code&gt;10.96.120.50:80&lt;/code&gt;), and a backend Pod (&lt;code&gt;10.244.2.10:80&lt;/code&gt;). The frontend runs &lt;code&gt;curl http://backend&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1 — DNS:&lt;/strong&gt; &lt;code&gt;backend → 10.96.120.50&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2 — Application sends packet:&lt;/strong&gt; &lt;code&gt;SRC = 10.244.1.5&lt;/code&gt;, &lt;code&gt;DST = 10.96.120.50:80&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3 — Service dataplane:&lt;/strong&gt; either &lt;code&gt;kube-proxy → iptables/IPVS&lt;/code&gt;, or an &lt;code&gt;eBPF dataplane&lt;/code&gt;, takes over.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 4 — Destination translation/selection:&lt;/strong&gt; &lt;code&gt;10.96.120.50:80 → 10.244.2.10:80&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 5 — Pod networking:&lt;/strong&gt; CNI provides the actual route to &lt;code&gt;10.244.2.10&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 6 — Backend receives traffic:&lt;/strong&gt; &lt;code&gt;Frontend → Service → Service dataplane → Backend Pod&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is SNAT?
&lt;/h2&gt;

&lt;p&gt;We've covered DNAT — now meet its counterpart: &lt;strong&gt;SNAT = Source Network Address Translation.&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DNAT → destination changes
SNAT → source changes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For example, &lt;code&gt;SRC = Pod IP, DST = external destination&lt;/code&gt; might become &lt;code&gt;SRC = Node IP, DST = external destination&lt;/code&gt;. This matters specifically when Pods communicate outside the cluster.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why SNAT Is Needed
&lt;/h2&gt;

&lt;p&gt;Suppose Pod &lt;code&gt;10.244.1.10&lt;/code&gt; tries to reach the internet. The external destination generally has no idea how to route return traffic back to &lt;code&gt;10.244.1.10&lt;/code&gt; — that's a private, cluster-internal address. So the networking system may perform SNAT:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;10.244.1.10
      ↓ SNAT
192.168.1.10  (Node IP)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Conceptually: &lt;code&gt;Pod → SNAT → Node IP → Internet&lt;/code&gt;. The exact behavior depends on your specific cluster's networking architecture.&lt;/p&gt;

&lt;h2&gt;
  
  
  DNAT vs SNAT
&lt;/h2&gt;

&lt;p&gt;Worth memorizing permanently:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DNAT — D = Destination
SNAT — S = Source
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example (Service → Pod): &lt;code&gt;10.96.120.50 → DNAT → 10.244.2.10&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Example (Pod → outside): &lt;code&gt;10.244.1.10 → SNAT → Node IP&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Return Traffic Works
&lt;/h2&gt;

&lt;p&gt;This is where &lt;strong&gt;NAT/connection tracking&lt;/strong&gt; becomes essential. Given &lt;code&gt;Client (10.244.1.5) → Service (10.96.120.50) → Backend (10.244.2.10)&lt;/code&gt;, the forward path goes &lt;code&gt;Client → Service IP → DNAT → Backend&lt;/code&gt;. For the response to correctly find its way back, the networking stack tracks the connection state so return traffic can be translated appropriately in reverse:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Forward: Service → Backend
Return:  Backend → Client
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This bookkeeping is handled through connection/NAT state tracking within the Linux networking stack (often referred to as "conntrack").&lt;/p&gt;

&lt;h2&gt;
  
  
  NodePort, Revisited
&lt;/h2&gt;

&lt;p&gt;With a &lt;code&gt;NodePort&lt;/code&gt; Service, given a Node IP of &lt;code&gt;192.168.1.10&lt;/code&gt; and NodePort &lt;code&gt;30080&lt;/code&gt;, external traffic to &lt;code&gt;192.168.1.10:30080&lt;/code&gt; can be forwarded toward the Service's backend Pods:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;External client
      ↓
NodeIP:30080
      ↓
Service dataplane
      ↓
Backend Pod
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The exact mechanics again depend on which dataplane your cluster is running.&lt;/p&gt;

&lt;h2&gt;
  
  
  LoadBalancer, Revisited
&lt;/h2&gt;

&lt;p&gt;With &lt;code&gt;type: LoadBalancer&lt;/code&gt;, the flow typically looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Internet
   ↓
Cloud Load Balancer
   ↓
Node / Service
   ↓
Backend Pods
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both the cloud load balancer &lt;em&gt;and&lt;/em&gt; the Kubernetes Service dataplane participate in the overall traffic path — which is exactly why troubleshooting external traffic often requires checking multiple distinct layers.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Layered Troubleshooting Model
&lt;/h2&gt;

&lt;p&gt;Now that we understand the full stack, we can build a much better troubleshooting model. If &lt;code&gt;curl http://backend&lt;/code&gt; fails, don't immediately blame DNS. Break it down layer by layer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. DNS
   ↓
2. Service
   ↓
3. EndpointSlice
   ↓
4. Service dataplane
   ↓
5. Pod networking
   ↓
6. Application
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 1 — DNS:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nslookup backend
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Does it resolve to the expected Service IP? If &lt;code&gt;backend → 10.96.120.50&lt;/code&gt;, DNS is probably fine.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2 — Service:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get svc backend
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check the ClusterIP, port, and targetPort.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3 — EndpointSlice:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get endpointslices
kubectl describe svc backend
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ask directly: does the Service actually have backend endpoints? If you see &lt;code&gt;Endpoints: &amp;lt;none&amp;gt;&lt;/code&gt;, don't waste time debugging iptables yet — the Service simply has no backends to send traffic to.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 4 — Pod:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get pods &lt;span class="nt"&gt;-o&lt;/span&gt; wide
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Confirm the backend Pods are &lt;code&gt;Running&lt;/code&gt;, &lt;code&gt;Ready&lt;/code&gt;, and have assigned IPs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 5 — Service dataplane:&lt;/strong&gt; Ask whether the Service dataplane is correctly forwarding traffic — investigate kube-proxy, iptables, IPVS, or your eBPF/CNI dataplane as appropriate. This is exactly where Level 8 knowledge pays off.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 6 — CNI:&lt;/strong&gt; If Service forwarding looks correct but the destination Pod still isn't reachable, investigate CNI, routing, the Pod's interface, Node connectivity, and NetworkPolicy.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Production Troubleshooting Tree
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                Request fails
                     |
                     ↓
                  DNS?
                 /     \
               NO       YES
               |         |
           Fix DNS     Service?
                         /   \
                       NO     YES
                       |       |
                  Fix Service  EndpointSlice?
                                /       \
                              NO         YES
                              |           |
                        Fix selectors   Dataplane?
                                         /     \
                                       NO       YES
                                       |         |
                                  kube-proxy/   CNI/
                                  eBPF/etc.    routing/
                                               policy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This structured approach beats randomly running commands and hoping something jumps out.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to Inspect on a Node
&lt;/h2&gt;

&lt;p&gt;For a traditional kube-proxy cluster using iptables, you can inspect:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;iptables-save
&lt;span class="c"&gt;# or&lt;/span&gt;
iptables &lt;span class="nt"&gt;-t&lt;/span&gt; nat &lt;span class="nt"&gt;-S&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These outputs can be extremely large on real clusters — don't be surprised by the volume. For IPVS-based setups, if installed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ipvsadm &lt;span class="nt"&gt;-L&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For eBPF-based implementations, the relevant tooling depends heavily on the specific implementation — Cilium, for example, ships its own observability and status tooling. &lt;strong&gt;Don't run diagnostic commands blindly in production&lt;/strong&gt; — first figure out which dataplane your cluster actually uses.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Do I Know Which Dataplane I'm Using?
&lt;/h2&gt;

&lt;p&gt;Start broad:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get pods &lt;span class="nt"&gt;-A&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Look for names like &lt;code&gt;kube-proxy&lt;/code&gt;, &lt;code&gt;calico&lt;/code&gt;, &lt;code&gt;cilium&lt;/code&gt;, &lt;code&gt;flannel&lt;/code&gt;, or &lt;code&gt;aws-node&lt;/code&gt;. Then:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get daemonsets &lt;span class="nt"&gt;-A&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For example, seeing a &lt;code&gt;kube-proxy&lt;/code&gt; DaemonSet suggests kube-proxy is deployed — but you should still inspect its configuration to determine whether it's actually running in iptables mode, IPVS mode, or something else entirely.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Most Important Conceptual Separation
&lt;/h2&gt;

&lt;p&gt;By now, you should be able to cleanly separate these layers in your head:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;              Kubernetes networking

                 Service
                    |
                    ↓
             Service dataplane
          ┌─────────┼─────────┐
          ↓         ↓         ↓
      iptables     IPVS      eBPF
          \         |         /
           └────────┼────────┘
                    ↓
                 Pod IP
                    |
                    ↓
               CNI network
                    |
                    ↓
                  Pod
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Interview Questions
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Q1. What does kube-proxy do?&lt;/strong&gt;&lt;br&gt;
It traditionally implements Kubernetes Service networking on Nodes by programming a Service dataplane.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q2. Is kube-proxy an HTTP proxy?&lt;/strong&gt;&lt;br&gt;
No — the name is genuinely misleading.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q3. What is a ClusterIP?&lt;/strong&gt;&lt;br&gt;
A stable virtual IP associated with a Kubernetes Service.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q4. How does a ClusterIP actually reach a Pod?&lt;/strong&gt;&lt;br&gt;
Through the Service dataplane — traditionally via iptables/IPVS, or through an alternative dataplane such as eBPF.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q5. What is DNAT?&lt;/strong&gt;&lt;br&gt;
Destination Network Address Translation — conceptually, &lt;code&gt;Service IP → Pod IP&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q6. What is SNAT?&lt;/strong&gt;&lt;br&gt;
Source Network Address Translation — conceptually, &lt;code&gt;Pod IP → Node IP&lt;/code&gt; in some outbound scenarios.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q7. What is IPVS?&lt;/strong&gt;&lt;br&gt;
Linux IP Virtual Server — a kernel-level load-balancing mechanism.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q8. What is eBPF?&lt;/strong&gt;&lt;br&gt;
A Linux kernel technology that allows programmable logic to run in kernel contexts, used by modern networking systems for routing, load balancing, security, and observability.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q9. Can eBPF replace kube-proxy?&lt;/strong&gt;&lt;br&gt;
Yes — some implementations, such as Cilium, can provide full Kubernetes Service functionality without needing kube-proxy at all.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q10. What does EndpointSlice provide?&lt;/strong&gt;&lt;br&gt;
Information about the current backend endpoints associated with a Service.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q11. Is CNI the same as kube-proxy?&lt;/strong&gt;&lt;br&gt;
No. CNI/network implementation handles Pod networking; kube-proxy/service dataplane handles Service forwarding.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q12. What happens if a Service has no EndpointSlices/endpoints?&lt;/strong&gt;&lt;br&gt;
The Service has no backend Pods to send traffic to — regardless of whether the Service dataplane itself is working correctly.&lt;/p&gt;
&lt;h2&gt;
  
  
  Level 8 Mental Model
&lt;/h2&gt;

&lt;p&gt;If you take away only one diagram from this entire article, make it this one:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                  Service
              10.96.120.50:80
                      |
                      ↓
             Service dataplane
                      |
          ┌───────────┼───────────┐
          ↓           ↓           ↓
       iptables      IPVS        eBPF
          └───────────┼───────────┘
                      ↓
                Pod endpoint
                10.244.2.10
                      |
                      ↓
                     CNI
                      |
                      ↓
                    Pod
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the responsibility of each layer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;CNI&lt;/strong&gt; → &lt;em&gt;"How do Pods communicate?"&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Service&lt;/strong&gt; → &lt;em&gt;"What stable endpoint do clients use?"&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;EndpointSlice&lt;/strong&gt; → &lt;em&gt;"Which Pods are backends?"&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;kube-proxy / dataplane&lt;/strong&gt; → &lt;em&gt;"How do Service packets reach those backends?"&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;iptables / IPVS / eBPF&lt;/strong&gt; → &lt;em&gt;"How is that forwarding actually implemented?"&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What's Next: Kubernetes Networking Internals
&lt;/h2&gt;

&lt;p&gt;In &lt;strong&gt;Level 9&lt;/strong&gt;, we'll connect everything into the actual &lt;strong&gt;Linux packet path&lt;/strong&gt; — diving into network namespaces, veth pairs, bridges, routing tables, conntrack, NAT, the kube-proxy/CNI interaction, Node-to-Pod versus Pod-to-Pod traffic, and exactly what happens to a single packet as it moves through a Kubernetes Node.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;The Service dataplane is where Kubernetes networking stops being abstract and becomes real packet manipulation. A ClusterIP is never a physical address a Pod actually owns — it's a rule, enforced by kube-proxy (or an eBPF-based alternative), that rewrites destinations via DNAT and tracks connections so return traffic finds its way home. Whether that enforcement happens through iptables rule chains, IPVS's kernel-level virtual server, or a fully custom eBPF dataplane, the underlying job is the same: turn a stable Service IP into real traffic to a real, currently-healthy Pod.&lt;/p&gt;

&lt;p&gt;The biggest practical takeaway: when Service traffic breaks, work the layers in order — DNS, Service, EndpointSlice, dataplane, then CNI. An empty EndpointSlice will waste hours of your time if you jump straight to debugging iptables rules instead of checking it first.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Enjoyed this deep dive?&lt;/strong&gt; Follow along for Level 9, where we trace a single packet's complete journey through the Linux networking stack inside a real Kubernetes Node. Drop your questions in the comments, and share this with a teammate who still thinks kube-proxy is a literal proxy server. Let's keep building this Kubernetes networking roadmap together. 🚀&lt;/p&gt;

</description>
      <category>infrastructure</category>
      <category>kubernetes</category>
      <category>networking</category>
    </item>
    <item>
      <title>Kubernetes Networking [Level-7: CNI]</title>
      <dc:creator>ADITYA RAJ</dc:creator>
      <pubDate>Sat, 15 Aug 2026 18:16:07 +0000</pubDate>
      <link>https://dev.to/iadiraj/kubernetes-networking-level-7-cni-52n7</link>
      <guid>https://dev.to/iadiraj/kubernetes-networking-level-7-cni-52n7</guid>
      <description>&lt;p&gt;This is &lt;strong&gt;Level 7&lt;/strong&gt; of our Kubernetes networking series — and one of the most important installments so far. Back in Level 1, we learned the shape of Pod networking:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Pod → Network Namespace → eth0 → veth → Node networking
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But we deliberately left one big question unanswered the entire time: &lt;strong&gt;who actually creates all of this?&lt;/strong&gt; The answer is &lt;strong&gt;CNI&lt;/strong&gt;, and this article finally opens that box.&lt;/p&gt;

&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;The Problem: Something Has to Wire the Pod's Network&lt;/li&gt;
&lt;li&gt;What Is CNI?&lt;/li&gt;
&lt;li&gt;Why We Need CNI&lt;/li&gt;
&lt;li&gt;CNI Is Not One Particular Product&lt;/li&gt;
&lt;li&gt;The Pod Creation Flow&lt;/li&gt;
&lt;li&gt;What CNI Is Actually Responsible For&lt;/li&gt;
&lt;li&gt;CNI and IPAM&lt;/li&gt;
&lt;li&gt;Why Pod CIDR Matters&lt;/li&gt;
&lt;li&gt;The veth Pair, Revisited&lt;/li&gt;
&lt;li&gt;What Happens to the Pod's IP&lt;/li&gt;
&lt;li&gt;Who Actually Owns the Pod's eth0?&lt;/li&gt;
&lt;li&gt;CNI Handles Both Creation and Deletion&lt;/li&gt;
&lt;li&gt;CNI's Place in the Kubernetes Stack&lt;/li&gt;
&lt;li&gt;CNI vs Service&lt;/li&gt;
&lt;li&gt;CNI vs DNS&lt;/li&gt;
&lt;li&gt;CNI vs NetworkPolicy&lt;/li&gt;
&lt;li&gt;Four Major Networking Approaches&lt;/li&gt;
&lt;li&gt;Common CNI Implementations&lt;/li&gt;
&lt;li&gt;A Closer Look: Calico, Flannel, and Cilium&lt;/li&gt;
&lt;li&gt;Don't Get Lost in Terminology&lt;/li&gt;
&lt;li&gt;What Happens When a Pod Starts&lt;/li&gt;
&lt;li&gt;What Happens During Cross-Node Communication&lt;/li&gt;
&lt;li&gt;What Happens When CNI Is Broken&lt;/li&gt;
&lt;li&gt;A Kubernetes Networking Troubleshooting Ladder&lt;/li&gt;
&lt;li&gt;Useful Commands for CNI Investigation&lt;/li&gt;
&lt;li&gt;CNI and kubelet&lt;/li&gt;
&lt;li&gt;Pod IP vs Service IP vs Node IP&lt;/li&gt;
&lt;li&gt;The Big Picture&lt;/li&gt;
&lt;li&gt;The Key Mental Model&lt;/li&gt;
&lt;li&gt;Level 7 Checkpoint&lt;/li&gt;
&lt;li&gt;What's Next: kube-proxy, iptables, IPVS, and eBPF&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  The Problem: Something Has to Wire the Pod's Network
&lt;/h2&gt;

&lt;p&gt;Suppose Kubernetes creates a new Pod:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl run nginx &lt;span class="nt"&gt;--image&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;nginx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That Pod needs a network namespace, an &lt;code&gt;eth0&lt;/code&gt; interface, an IP address, routes, and connectivity to every other Pod in the cluster. Kubernetes itself doesn't contain one built-in, universal implementation that directly wires all of this up. Instead, it delegates the job to a standardized mechanism: &lt;strong&gt;CNI — the Container Network Interface.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is CNI?
&lt;/h2&gt;

&lt;p&gt;In the simplest terms:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;CNI is a standard interface for configuring container networking.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Think of it as a contract between the container runtime and whatever networking implementation you've chosen:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Container runtime
       | "I need networking for this Pod"
       ↓
      CNI
       ↓
Network plugin
       ↓
Configure Pod network
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The CNI &lt;em&gt;specification&lt;/em&gt; defines the contract; CNI &lt;em&gt;plugins&lt;/em&gt; are what actually do the networking work.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why We Need CNI
&lt;/h2&gt;

&lt;p&gt;Without any Pod networking, Pods are isolated islands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Pod A       Pod B
  ❌          ❌
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With a working CNI implementation in place, they can actually reach each other:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Pod A ─────────→ Pod B
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Depending on the specific implementation, CNI/network plugins can provide: Pod IPs, Pod network interfaces, routing, general connectivity, and — in some cases — NetworkPolicy enforcement.&lt;/p&gt;

&lt;h2&gt;
  
  
  CNI Is Not One Particular Product
&lt;/h2&gt;

&lt;p&gt;This is a crucial mental correction if you're new to this space: &lt;strong&gt;CNI is not the name of a single networking product.&lt;/strong&gt; It's an interface, specification, and ecosystem. Multiple different implementations can all satisfy the CNI contract, including Calico, Cilium, Flannel, AWS VPC CNI, Azure CNI, and various GKE networking implementations.&lt;/p&gt;

&lt;p&gt;Don't think: &lt;code&gt;CNI = Calico&lt;/code&gt;. Instead think:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CNI
 ↓
standard interface
 ↓
different networking implementations
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The Pod Creation Flow
&lt;/h2&gt;

&lt;p&gt;Let's connect this to everything we've learned. When you run &lt;code&gt;kubectl run nginx --image=nginx&lt;/code&gt;, the high-level flow looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl
   ↓
API Server
   ↓
Scheduler
   ↓
Node selected
   ↓
Container runtime
   ↓
Network setup
   ↓
CNI
   ↓
Pod gets networking
   ↓
Container starts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Zooming into just the networking portion:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Pod
 ↓
Network namespace
 ↓
CNI invoked
 ↓
Create/configure network interface
 ↓
Assign IP
 ↓
Configure routes
 ↓
Connect Pod to node network
 ↓
Pod networking ready
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What CNI Is Actually Responsible For
&lt;/h2&gt;

&lt;p&gt;At a high level, CNI answers five key questions for every Pod:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. What network should this Pod join?&lt;/strong&gt; → the cluster's Pod network.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. What IP should it receive?&lt;/strong&gt; → e.g., &lt;code&gt;10.244.1.15&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. How does the Pod connect to the Node?&lt;/strong&gt; → commonly, a Pod's &lt;code&gt;eth0&lt;/code&gt; connects via a veth pair to the Node.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. How can it reach other Pods?&lt;/strong&gt; → the networking implementation configures the necessary connectivity.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Can traffic be restricted?&lt;/strong&gt; → some (not all) implementations also enforce NetworkPolicy.&lt;/p&gt;

&lt;h2&gt;
  
  
  CNI and IPAM
&lt;/h2&gt;

&lt;p&gt;Here's a term you'll see constantly: &lt;strong&gt;IPAM (IP Address Management)&lt;/strong&gt;. When a Pod needs an IP, IPAM is what allocates it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Pod
 ↓
"I need an IP"
 ↓
IPAM
 ↓
10.244.1.15
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;IPAM allocates addresses from configured pools. For example, given a Pod network of &lt;code&gt;10.244.0.0/16&lt;/code&gt;, a networking implementation might divide it per Node:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Node 1 → 10.244.1.0/24
Node 2 → 10.244.2.0/24
Node 3 → 10.244.3.0/24
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And from there:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Pod A → 10.244.1.10
Pod B → 10.244.1.11
Pod C → 10.244.2.10
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These are illustrative example ranges, not universal defaults — actual ranges vary by cluster and CNI configuration.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Pod CIDR Matters
&lt;/h2&gt;

&lt;p&gt;Recall from Level 2: Pod A (&lt;code&gt;10.244.1.5&lt;/code&gt;) needs to reach Pod B (&lt;code&gt;10.244.2.5&lt;/code&gt;) on a different Node. For that to work, the networking system needs to know that &lt;code&gt;10.244.2.0/24&lt;/code&gt; lives on Node 2. This is exactly where the CNI/networking implementation earns its keep — establishing connectivity &lt;em&gt;between&lt;/em&gt; these per-Node Pod networks.&lt;/p&gt;

&lt;h2&gt;
  
  
  The veth Pair, Revisited
&lt;/h2&gt;

&lt;p&gt;We first saw veth pairs back in Level 0 and Level 1. Now let's understand why CNI specifically cares about them.&lt;/p&gt;

&lt;p&gt;A Pod lives in its own isolated network namespace:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Pod network namespace
┌─────────────────────┐
│ eth0                │
│ 10.244.1.10         │
└─────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But it still needs to connect to the Node. A veth pair — a virtual Ethernet cable — is a common way to bridge that gap:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Pod namespace                    Node
┌──────────────┐                 ┌──────────────┐
│    eth0      │=================│   vethXXXX   │
│              │    veth pair    │              │
└──────────────┘                 └──────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One end lives inside the Pod's namespace; the other lives on the Node. The CNI/network implementation is typically what creates and configures this pairing.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Happens to the Pod's IP
&lt;/h2&gt;

&lt;p&gt;Inside a running Pod, &lt;code&gt;ip addr&lt;/code&gt; might conceptually show:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;eth0
    inet 10.244.1.10/24
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And &lt;code&gt;ip route&lt;/code&gt; will show routes that let the Pod communicate beyond its own local subnet. The exact routing table content depends entirely on which networking implementation configured it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who Actually Owns the Pod's eth0?
&lt;/h2&gt;

&lt;p&gt;A genuinely useful interview question. The interface itself exists inside the Pod's network namespace, but the &lt;em&gt;setup&lt;/em&gt; is performed by the container networking implementation, invoked through CNI. So don't say &lt;em&gt;"the Pod creates &lt;code&gt;eth0&lt;/code&gt;"&lt;/em&gt; — instead think:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Container runtime
       ↓
CNI/network plugin
       ↓
network namespace + interface + IP + routes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  CNI Handles Both Creation and Deletion
&lt;/h2&gt;

&lt;p&gt;CNI's job doesn't stop once a Pod is created:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CREATE POD
    ↓
CNI/network setup
    ↓
network exists
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DELETE POD
    ↓
network cleanup
    ↓
IP released
    ↓
interfaces removed
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This cleanup step matters a lot — without it, you could end up accumulating unused interfaces, unreleased IPs, and stale network state over time. The networking implementation is responsible for tidying all of this up.&lt;/p&gt;

&lt;h2&gt;
  
  
  CNI's Place in the Kubernetes Stack
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Kubernetes
    | schedules/manages Pods
    ↓
Container runtime
    | runs containers
    ↓
CNI/network implementation
    | configures networking
    ↓
Pod network
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Kubernetes handles orchestration (deciding &lt;em&gt;what&lt;/em&gt; should run &lt;em&gt;where&lt;/em&gt;). The networking implementation handles the actual mechanics of wiring that Pod onto the network.&lt;/p&gt;

&lt;h2&gt;
  
  
  CNI vs Service
&lt;/h2&gt;

&lt;p&gt;An important distinction we can now draw crisply:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CNI     → Pod networking (connectivity)
Service → stable way to reach a group of Pods
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Pod A (10.244.1.10) → CNI/networking → Pod B (10.244.2.10)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;versus:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Client → Service IP → Backend Pod
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two entirely different jobs, working at two different layers.&lt;/p&gt;

&lt;h2&gt;
  
  
  CNI vs DNS
&lt;/h2&gt;

&lt;p&gt;Also worth separating clearly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DNS → backend.default.svc.cluster.local → Service IP  (name resolution)
CNI → Pod interface/IP/routes → network connectivity  (Pod networking)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;DNS answers &lt;em&gt;"what IP does this name map to?"&lt;/em&gt; CNI answers &lt;em&gt;"how does a Pod actually get onto the network in the first place?"&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  CNI vs NetworkPolicy
&lt;/h2&gt;

&lt;p&gt;We covered this distinction in Level 6, but it's worth reinforcing here:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;NetworkPolicy       → "What traffic should be allowed?"
Network implementation → "How is Pod networking provided, and (if supported) how are policies enforced?"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Some networking implementations support NetworkPolicy enforcement and some don't — but either way, &lt;strong&gt;CNI ≠ NetworkPolicy&lt;/strong&gt;. They're related but distinct concerns.&lt;/p&gt;

&lt;h2&gt;
  
  
  Four Major Networking Approaches
&lt;/h2&gt;

&lt;p&gt;Now let's introduce the major strategies a CNI implementation can use to actually make Pod networking work.&lt;/p&gt;

&lt;h3&gt;
  
  
  Approach 1 — Routing
&lt;/h3&gt;

&lt;p&gt;Nodes are taught direct routes to each other's Pod networks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Node 1: Pod CIDR = 10.244.1.0/24
Node 2: Pod CIDR = 10.244.2.0/24
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Node 1 simply knows &lt;code&gt;10.244.2.0/24 → Node 2&lt;/code&gt;, so traffic flows: &lt;code&gt;Pod A → Node 1 → Node 2 → Pod B&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Approach 2 — Overlay
&lt;/h3&gt;

&lt;p&gt;A virtual network is built on top of the physical network via encapsulation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Pod packet
    ↓
encapsulate
    ↓
Node 1 → physical network → Node 2
    ↓
decapsulate
    ↓
Pod
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Think of this as "a network inside another network" — the inner packet (&lt;code&gt;Pod A → Pod B&lt;/code&gt;) rides inside an outer packet (&lt;code&gt;Node 1 → Node 2&lt;/code&gt;). &lt;strong&gt;VXLAN&lt;/strong&gt; is a common technology used to implement this approach.&lt;/p&gt;

&lt;h3&gt;
  
  
  Approach 3 — Cloud/VPC Networking
&lt;/h3&gt;

&lt;p&gt;Cloud environments can integrate Pod networking directly with the cloud provider's native network:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Pod → cloud network → VPC/VNet → other resources
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For example, AWS's VPC CNI uses actual AWS networking primitives rather than building a generic overlay on top. The exact implementation varies by cloud provider and configuration.&lt;/p&gt;

&lt;h3&gt;
  
  
  Approach 4 — eBPF-Based Networking
&lt;/h3&gt;

&lt;p&gt;Some modern implementations use &lt;strong&gt;eBPF&lt;/strong&gt; for both networking and policy enforcement:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Pod traffic
    ↓
Linux kernel
    ↓
eBPF programs
    ↓
routing / filtering / load balancing
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Cilium&lt;/strong&gt; is the major example here. We won't go deep into eBPF mechanics yet — that's reserved for Level 8. For now, just recognize that a CNI implementation &lt;em&gt;could&lt;/em&gt; be built on eBPF.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common CNI Implementations
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Implementation&lt;/th&gt;
&lt;th&gt;General Idea&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Calico&lt;/td&gt;
&lt;td&gt;Routing / policy, with multiple dataplane options&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cilium&lt;/td&gt;
&lt;td&gt;eBPF-based networking and security&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Flannel&lt;/td&gt;
&lt;td&gt;Simple Pod networking, commonly overlay-based&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AWS VPC CNI&lt;/td&gt;
&lt;td&gt;Integrates Pods directly with AWS VPC networking&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Azure networking implementations&lt;/td&gt;
&lt;td&gt;Integrate Pods with Azure networking&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Don't try to memorize every implementation detail right now. At this level, the important question to ask about each one is simply: &lt;em&gt;what problem does it solve, and how?&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  A Closer Look: Calico, Flannel, and Cilium
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Calico&lt;/strong&gt; is widely used for both Pod networking &lt;em&gt;and&lt;/em&gt; NetworkPolicy enforcement. It can use routing-based networking and supports multiple dataplane options:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Pod → Calico → network + policy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Flannel&lt;/strong&gt; is known for providing relatively simple Kubernetes Pod networking:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Pod → Flannel → cluster network
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A common Flannel setup uses an overlay like VXLAN — but don't treat "Flannel = VXLAN" as an absolute rule, since configurations can vary.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cilium&lt;/strong&gt; leans heavily on eBPF for networking, security, and observability:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Pod traffic → Linux kernel → eBPF → networking + security + observability
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We'll compare these implementations in more depth once we reach Level 8.&lt;/p&gt;

&lt;h2&gt;
  
  
  Don't Get Lost in Terminology
&lt;/h2&gt;

&lt;p&gt;You'll hear phrases like "CNI plugin," "CNI binary," "CNI configuration," "CNI network," and "CNI IPAM" thrown around. Don't let the terminology overwhelm you. At the learning level, this simplified mental model covers the fundamentals well:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;             CNI
              |
      ┌───────┴────────┐
      ↓                ↓
Network setup        IPAM
      ↓                ↓
interface            IP
routes
connectivity
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The real architecture can get more nuanced in production systems, but this model will serve you well as a foundation.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Happens When a Pod Starts
&lt;/h2&gt;

&lt;p&gt;Putting it all together — suppose Kubernetes schedules Pod A onto Node 1:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                Kubernetes
                    ↓
               Node 1
                    ↓
             Container runtime
                    ↓
            Create Pod namespace
                    ↓
                  CNI
                    |
          ┌─────────┼─────────┐
          ↓         ↓         ↓
        veth       IP       routes
          |         |         |
          └─────────┼─────────┘
                    ↓
               Pod eth0
                    ↓
              Pod networking
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At the end of this sequence, Pod A has a working IP (say, &lt;code&gt;10.244.1.10&lt;/code&gt;) and is ready to communicate.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Happens During Cross-Node Communication
&lt;/h2&gt;

&lt;p&gt;Suppose Pod A (&lt;code&gt;10.244.1.10&lt;/code&gt; on Node 1) needs to reach Pod B (&lt;code&gt;10.244.2.10&lt;/code&gt; on Node 2). The networking implementation provides the actual path:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Pod A → eth0 → veth → Node 1 → networking implementation → Node 2 → veth → eth0 → Pod B
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The exact middle section — routing, overlay, cloud networking, or eBPF — depends entirely on which CNI implementation you're running. This is precisely why the choice of CNI matters so much in real clusters.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Happens When CNI Is Broken
&lt;/h2&gt;

&lt;p&gt;This is where understanding CNI pays off during real troubleshooting. If you see symptoms like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Pod → no IP
Pod → eth0 missing
Pod A ✗ Pod B
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;...you should immediately start thinking: &lt;strong&gt;could this be a CNI/networking problem?&lt;/strong&gt; Common symptoms worth watching for include Pods stuck in &lt;code&gt;ContainerCreating&lt;/code&gt;, Pods with no IP assigned, an unconfigured Pod network namespace, broken Pod-to-Pod connectivity, broken DNS connectivity, or NetworkPolicy simply not being enforced. Not every one of these symptoms is guaranteed to be a CNI issue, but CNI should always be high on your list of suspects.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Kubernetes Networking Troubleshooting Ladder
&lt;/h2&gt;

&lt;p&gt;We can now assemble a genuinely useful troubleshooting sequence, built from everything covered across this series:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Pod exists?
   ↓
Pod has IP?
   ↓
Pod has eth0?
   ↓
Pod has routes?
   ↓
Pod → Pod works?
   ↓
Service works?
   ↓
DNS works?
   ↓
NetworkPolicy works?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;CNI sits right near the bottom of this stack:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CNI → Pod networking → Pod-to-Pod → Services → DNS → Ingress
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If basic Pod networking is broken at the CNI layer, everything built on top of it can fail too — which is exactly why it's worth checking early rather than last.&lt;/p&gt;

&lt;h2&gt;
  
  
  Useful Commands for CNI Investigation
&lt;/h2&gt;

&lt;p&gt;Start broad:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get pods &lt;span class="nt"&gt;-o&lt;/span&gt; wide
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This shows you each Pod's IP and the Node it's running on. Then:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get nodes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Drill into a specific Pod:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; &amp;lt;pod&amp;gt; &lt;span class="nt"&gt;--&lt;/span&gt; ip addr
kubectl &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; &amp;lt;pod&amp;gt; &lt;span class="nt"&gt;--&lt;/span&gt; ip route
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check networking-related Pods across the whole cluster:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get pods &lt;span class="nt"&gt;-A&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In many clusters, CNI components run as DaemonSets — typically one networking agent per Node:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get daemonsets &lt;span class="nt"&gt;-A&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The exact namespace and deployment shape depend heavily on your specific Kubernetes distribution and chosen networking implementation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Look for the CNI
&lt;/h2&gt;

&lt;p&gt;A useful investigative habit:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get pods &lt;span class="nt"&gt;-A&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Look for Pod names containing things like &lt;code&gt;calico-node&lt;/code&gt;, &lt;code&gt;cilium&lt;/code&gt;, &lt;code&gt;kube-flannel&lt;/code&gt;, or &lt;code&gt;aws-node&lt;/code&gt;. These names give you a strong clue about which networking implementation your cluster is running — though don't assume every cluster follows the same naming conventions.&lt;/p&gt;

&lt;h2&gt;
  
  
  CNI and kubelet
&lt;/h2&gt;

&lt;p&gt;One more important relationship: the &lt;strong&gt;kubelet&lt;/strong&gt; manages Pods on a given Node. When a Pod's networking needs to be configured, the container runtime and networking stack invoke the configured CNI mechanism:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubelet
   ↓
container runtime
   ↓
CNI
   ↓
network plugin
   ↓
Pod network
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The precise interaction between the runtime and CNI has evolved across different Kubernetes versions and container runtimes, but this remains the correct conceptual model to hold onto.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pod IP vs Service IP vs Node IP
&lt;/h2&gt;

&lt;p&gt;Let's clarify one more crucial distinction now that IPAM is fresh in mind. Given a Pod network of &lt;code&gt;10.244.0.0/16&lt;/code&gt;, IPAM might allocate:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Pod 1 → 10.244.1.10
Pod 2 → 10.244.1.11
Pod 3 → 10.244.2.10
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When Pod 2 is deleted, &lt;code&gt;10.244.1.11&lt;/code&gt; can eventually return to the available address pool, depending on the specific IPAM implementation. So: &lt;strong&gt;IPAM = who gets which Pod IP, and when it's reclaimed.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;By now you should be able to clearly distinguish three different kinds of IPs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Node IP    → identifies a Node       (e.g., 192.168.1.10)
Pod IP     → identifies a Pod        (e.g., 10.244.1.10)
Service IP → stable virtual endpoint (e.g., 10.96.120.50)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;CNI is primarily concerned with the &lt;strong&gt;Pod IP&lt;/strong&gt; layer — it has nothing to do with creating Service semantics, which is a separate mechanism entirely (covered in Level 3, and revisited more deeply in Level 8).&lt;/p&gt;

&lt;h2&gt;
  
  
  The Big Picture
&lt;/h2&gt;

&lt;p&gt;We've now connected almost the entire series into a single diagram:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                    Kubernetes
                        ↓
                     Node
                        ↓
                 Container runtime
                        ↓
                       CNI
                        |
          ┌─────────────┼─────────────┐
          ↓             ↓             ↓
        veth            IP          routes
          \             |             /
           └────────────┼────────────┘
                        ↓
                       Pod
                        ↓
                     Pod IP
                        ↓
                 Pod-to-Pod network
                        ↓
                     Service
                        ↓
                       DNS
                        ↓
                Ingress / Gateway
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And NetworkPolicy sits across the entire networking path as an overlay of rules:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Pod traffic → NetworkPolicy rules → network implementation → allow / restrict
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The Key Mental Model
&lt;/h2&gt;

&lt;p&gt;If you remember only one diagram from this entire article, make it this one:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                POD
                 | eth0
                 ↓
              veth pair
                 ↓
                NODE
                 ↓
         CNI / networking
                 |
       ┌─────────┼─────────┐
       ↓         ↓         ↓
      IP       routes    connectivity
       |         |         |
       └─────────┼─────────┘
                 ↓
             other Pods
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the single sentence to internalize:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;CNI = "How do Pods get onto the network?"&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Level 7 Checkpoint
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. What does CNI stand for?&lt;/strong&gt;&lt;br&gt;
Container Network Interface.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Is CNI a single product?&lt;/strong&gt;&lt;br&gt;
No — it's a standard/interface/ecosystem used by many different networking implementations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. What does CNI help configure?&lt;/strong&gt;&lt;br&gt;
At a high level: the Pod's network namespace, interface, IP address, routes, and connectivity — and, depending on the implementation, NetworkPolicy enforcement and other capabilities.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. What is IPAM?&lt;/strong&gt;&lt;br&gt;
IP Address Management — the process of allocating IP addresses to Pods.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. What commonly connects a Pod's namespace to the Node?&lt;/strong&gt;&lt;br&gt;
A veth pair is a common mechanism.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6. Is CNI the same as Service?&lt;/strong&gt;&lt;br&gt;
No. CNI provides Pod networking; Service provides stable access to a group of Pods.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;7. Is CNI the same as NetworkPolicy?&lt;/strong&gt;&lt;br&gt;
No. NetworkPolicy defines &lt;em&gt;what&lt;/em&gt; traffic should be allowed; the network implementation provides and (if supported) enforces that behavior.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;8. Name some Kubernetes networking implementations.&lt;/strong&gt;&lt;br&gt;
Calico, Cilium, Flannel, AWS VPC CNI, among others.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;9. What are the major networking approaches?&lt;/strong&gt;&lt;br&gt;
Conceptually: routing, overlay, cloud/VPC networking, and eBPF-based networking.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;10. What happens if CNI networking is broken?&lt;/strong&gt;&lt;br&gt;
Symptoms can include Pods with no IP, Pods with no working interface, broken Pod-to-Pod connectivity, broken DNS connectivity, and cascading failures in higher-level networking.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Next: kube-proxy, iptables, IPVS, and eBPF
&lt;/h2&gt;

&lt;p&gt;In &lt;strong&gt;Level 8&lt;/strong&gt;, we'll finally open the black box behind the Service dataplane and answer:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A Service IP exists. How does it actually become a Pod IP?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We'll cover &lt;code&gt;kube-proxy&lt;/code&gt;, &lt;code&gt;iptables&lt;/code&gt;, &lt;code&gt;IPVS&lt;/code&gt;, and &lt;code&gt;eBPF&lt;/code&gt; — and how Service traffic is genuinely forwarded under the hood. This is where the whole networking picture starts becoming much more concrete.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;CNI is the quiet, foundational layer that makes every other piece of Kubernetes networking possible. It's not a single product but a standardized contract — implemented by tools like Calico, Cilium, and Flannel — for giving every Pod a network namespace, an interface, an IP address, and a path to reach every other Pod in the cluster. Whether that connectivity is achieved through routing, overlays, cloud-native VPC integration, or eBPF depends entirely on which implementation you choose.&lt;/p&gt;

&lt;p&gt;The most valuable habit to take away from this article: when something in Kubernetes networking breaks, don't jump straight to blaming Services or DNS. Walk the ladder from the bottom up — Pod IP, Pod interface, Pod-to-Pod connectivity — because a broken CNI layer can quietly break everything built on top of it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Found this useful?&lt;/strong&gt; Follow along for Level 8, where we finally crack open &lt;code&gt;kube-proxy&lt;/code&gt;, iptables, IPVS, and eBPF to see exactly how a Service IP becomes real Pod traffic. Drop your questions in the comments, and share this with a teammate who still thinks "CNI" and "Calico" are the same thing. Let's keep building this Kubernetes networking roadmap together. 🚀&lt;/p&gt;

</description>
      <category>docker</category>
      <category>containers</category>
      <category>kubernetes</category>
      <category>networking</category>
    </item>
    <item>
      <title>Kubernetes Networking [Level-6: Networking Policy]</title>
      <dc:creator>ADITYA RAJ</dc:creator>
      <pubDate>Sat, 15 Aug 2026 12:38:07 +0000</pubDate>
      <link>https://dev.to/iadiraj/kubernetes-networking-level-6-networking-policy-3ob4</link>
      <guid>https://dev.to/iadiraj/kubernetes-networking-level-6-networking-policy-3ob4</guid>
      <description>&lt;p&gt;This is &lt;strong&gt;Level 6&lt;/strong&gt; of our Kubernetes networking series. So far, we've learned that Kubernetes networking is, by default, remarkably open — any Pod can talk to any other Pod:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Pod A ─────────→ Pod B
Pod C ─────────→ Pod B
Pod D ─────────→ Pod B
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's great for connectivity, but terrible for security. In a real application, you almost never want &lt;em&gt;everything&lt;/em&gt; talking to &lt;em&gt;everything&lt;/em&gt;. This article covers the Kubernetes object designed specifically to fix that: &lt;strong&gt;NetworkPolicy&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;The Problem: Too Much Trust&lt;/li&gt;
&lt;li&gt;The Solution: NetworkPolicy&lt;/li&gt;
&lt;li&gt;Two Directions: Ingress and Egress&lt;/li&gt;
&lt;li&gt;An Easy Way to Remember Ingress vs Egress&lt;/li&gt;
&lt;li&gt;A Simple Scenario&lt;/li&gt;
&lt;li&gt;Your First NetworkPolicy&lt;/li&gt;
&lt;li&gt;Reading the Policy Step by Step&lt;/li&gt;
&lt;li&gt;The Policy Selects the Destination&lt;/li&gt;
&lt;li&gt;What About the Database?&lt;/li&gt;
&lt;li&gt;NetworkPolicy Doesn't Block Everything by Default&lt;/li&gt;
&lt;li&gt;Default Deny&lt;/li&gt;
&lt;li&gt;Why Default Deny Is Useful&lt;/li&gt;
&lt;li&gt;Controlling Egress Traffic&lt;/li&gt;
&lt;li&gt;An Egress Policy Example&lt;/li&gt;
&lt;li&gt;Namespaces Matter More Than You Think&lt;/li&gt;
&lt;li&gt;namespaceSelector&lt;/li&gt;
&lt;li&gt;Combining podSelector and namespaceSelector&lt;/li&gt;
&lt;li&gt;Three Key Selectors: podSelector, namespaceSelector, ipBlock&lt;/li&gt;
&lt;li&gt;Restricting Ports&lt;/li&gt;
&lt;li&gt;A Complete Multi-Tier Example&lt;/li&gt;
&lt;li&gt;NetworkPolicy Is Not an Application Firewall&lt;/li&gt;
&lt;li&gt;NetworkPolicy Doesn't Replace Authentication&lt;/li&gt;
&lt;li&gt;Who Actually Enforces NetworkPolicy?&lt;/li&gt;
&lt;li&gt;Two Common Misconceptions&lt;/li&gt;
&lt;li&gt;Hands-On: Inspecting NetworkPolicies&lt;/li&gt;
&lt;li&gt;Hands-On: Creating an Allow Policy&lt;/li&gt;
&lt;li&gt;Hands-On: The Default-Deny Lab&lt;/li&gt;
&lt;li&gt;A Production Mental Model&lt;/li&gt;
&lt;li&gt;Troubleshooting NetworkPolicy&lt;/li&gt;
&lt;li&gt;The Mental Model to Memorize&lt;/li&gt;
&lt;li&gt;Level 6 Checkpoint&lt;/li&gt;
&lt;li&gt;What's Next: CNI&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  The Problem: Too Much Trust
&lt;/h2&gt;

&lt;p&gt;Imagine a typical three-tier application:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Internet → Frontend → Backend → Database
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ideally, we want a strict set of allowed paths:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Frontend → Backend       ✅
Backend  → Database      ✅
Frontend → Database      ❌
Database ← Internet      ❌
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But by default, Kubernetes doesn't enforce any of this. Without restrictions, every one of these connections is technically possible:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;frontend → backend       ✅
frontend → database      ✅
backend  → database      ✅
backend  → frontend      ✅
database → frontend      ✅
database → backend       ✅
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's usually far too permissive. A compromised frontend Pod could, in principle, connect directly to the database — bypassing the backend entirely. We need a way to explicitly say: &lt;em&gt;this path is allowed, that one isn't.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Solution: NetworkPolicy
&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;NetworkPolicy&lt;/strong&gt; is a Kubernetes object that defines rules controlling network traffic to and from selected Pods. In one sentence:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NetworkPolicy = firewall-like rules for Pod traffic.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The mental model:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;NetworkPolicy
     ↓
Which Pods?
     ↓
What traffic?
     ↓
Allow / restrict
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Two Directions: Ingress and Egress
&lt;/h2&gt;

&lt;p&gt;NetworkPolicy operates along two possible directions — and getting these terms straight is essential.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ingress&lt;/strong&gt; — traffic &lt;em&gt;coming into&lt;/em&gt; a Pod:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Frontend
   | traffic
   ↓
Backend Pod
        ↑
     ingress
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Egress&lt;/strong&gt; — traffic &lt;em&gt;leaving&lt;/em&gt; a Pod:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Backend Pod
    | traffic
    ↓
Database
   ↑
egress from Backend
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  An Easy Way to Remember Ingress vs Egress
&lt;/h2&gt;

&lt;p&gt;Picture yourself standing inside a room:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;INGRESS&lt;/strong&gt; = people coming &lt;strong&gt;IN&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;EGRESS&lt;/strong&gt; = people going &lt;strong&gt;OUT&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For a Pod:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Traffic → Pod  = Ingress
Pod → Traffic  = Egress
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  A Simple Scenario
&lt;/h2&gt;

&lt;p&gt;Suppose we have three Pods: &lt;code&gt;frontend&lt;/code&gt;, &lt;code&gt;backend&lt;/code&gt;, and &lt;code&gt;database&lt;/code&gt;, each with a matching label:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;frontend&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;app=frontend&lt;/span&gt;
&lt;span class="na"&gt;backend&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;  &lt;span class="s"&gt;app=backend&lt;/span&gt;
&lt;span class="na"&gt;database&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;app=database&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We want:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;frontend → backend     ✅
backend  → database    ✅
frontend → database    ❌
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A NetworkPolicy can express this as: &lt;em&gt;"Backend Pods may receive traffic from Frontend Pods."&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Your First NetworkPolicy
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;networking.k8s.io/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;NetworkPolicy&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;backend-allow-frontend&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;podSelector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;backend&lt;/span&gt;

  &lt;span class="na"&gt;policyTypes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;Ingress&lt;/span&gt;

  &lt;span class="na"&gt;ingress&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;podSelector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;frontend&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Don't worry about memorizing this YAML yet — let's walk through exactly what it means.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reading the Policy Step by Step
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Which Pods does the policy apply to?&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;podSelector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;backend&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This means: &lt;em&gt;apply this policy to Pods labeled &lt;code&gt;app: backend&lt;/code&gt;.&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;backend Pod 1  ← selected
backend Pod 2  ← selected

frontend Pod   ← not selected
database Pod   ← not selected
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;What direction is being controlled?&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;policyTypes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;Ingress&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This means: &lt;em&gt;we're controlling traffic coming into the selected backend Pods.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Who is allowed in?&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;ingress&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;podSelector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;frontend&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This means: &lt;em&gt;backend Pods can receive traffic from Pods labeled &lt;code&gt;app: frontend&lt;/code&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;So &lt;code&gt;frontend → backend&lt;/code&gt; is allowed, but anything not explicitly listed (like &lt;code&gt;database → backend&lt;/code&gt;) is not covered by this rule.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Policy Selects the Destination
&lt;/h2&gt;

&lt;p&gt;This point confuses a lot of beginners, so let's be explicit. The top-level &lt;code&gt;podSelector&lt;/code&gt; defines &lt;strong&gt;where the policy applies&lt;/strong&gt; — the destination:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;podSelector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;backend&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;from&lt;/code&gt; block inside &lt;code&gt;ingress&lt;/code&gt; defines &lt;strong&gt;who is allowed to reach it&lt;/strong&gt; — the source:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;podSelector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;frontend&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Visually:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;        NetworkPolicy
              |
              ↓
       ┌─────────────┐
       │   backend   │
       └──────▲──────┘
              |
           allowed
              |
       ┌──────┴──────┐
       │  frontend   │
       └─────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What About the Database?
&lt;/h2&gt;

&lt;p&gt;Suppose we never wrote an explicit allow rule for &lt;code&gt;frontend → database&lt;/code&gt;. Then, once the database Pods become subject to a NetworkPolicy, that path stays blocked:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;frontend → backend     ✅
frontend → database    ❌
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the beginning of &lt;strong&gt;micro-segmentation&lt;/strong&gt;: instead of trusting the entire cluster ("everything can talk to everything"), you deliberately define a small, explicit set of allowed paths — &lt;code&gt;Frontend → Backend&lt;/code&gt;, &lt;code&gt;Backend → Database&lt;/code&gt;, and nothing else.&lt;/p&gt;

&lt;h2&gt;
  
  
  NetworkPolicy Doesn't Block Everything by Default
&lt;/h2&gt;

&lt;p&gt;This is a critical concept: creating &lt;em&gt;one&lt;/em&gt; NetworkPolicy does &lt;strong&gt;not&lt;/strong&gt; mean "everything else in the cluster is now blocked." Whether a Pod becomes restricted depends on whether it's selected by a policy for the relevant direction:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Policy selects backend
       +
Ingress policy exists
       ↓
backend ingress becomes restricted
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once a Pod becomes "isolated" for a direction (ingress or egress), only the explicitly allowed traffic for that direction gets through. This naturally leads to the concept of &lt;strong&gt;default deny&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Default Deny
&lt;/h2&gt;

&lt;p&gt;Suppose you want: &lt;em&gt;"By default, nobody can send traffic to these Pods."&lt;/em&gt; You can express that with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;networking.k8s.io/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;NetworkPolicy&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;default-deny-ingress&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;podSelector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;
  &lt;span class="na"&gt;policyTypes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;Ingress&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, &lt;code&gt;podSelector: {}&lt;/code&gt; (an empty selector) means: &lt;em&gt;select all Pods in this namespace.&lt;/em&gt; Combined with &lt;code&gt;policyTypes: [Ingress]&lt;/code&gt; and &lt;strong&gt;no&lt;/strong&gt; ingress rules at all, the effect is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Any Pod
   |
   X
   ↓
Selected Pods
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nothing is allowed in, for any Pod in the namespace, until you add explicit allow rules.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Default Deny Is Useful
&lt;/h2&gt;

&lt;p&gt;Imagine a production namespace with &lt;code&gt;frontend&lt;/code&gt;, &lt;code&gt;backend&lt;/code&gt;, &lt;code&gt;database&lt;/code&gt;, and &lt;code&gt;cache&lt;/code&gt; Pods. Instead of assuming everything is safe by default:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;frontend → everything
backend  → everything
database → everything
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;...you start from &lt;strong&gt;DENY&lt;/strong&gt;, and explicitly allow only what's actually required:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;frontend → backend       ✅
backend  → database      ✅
backend  → cache         ✅
everything else          ❌
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This "deny by default, allow by exception" approach is a widely used, well-established security strategy — and NetworkPolicy is how you implement it in Kubernetes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Controlling Egress Traffic
&lt;/h2&gt;

&lt;p&gt;So far we've focused on incoming traffic, but you can restrict outgoing traffic too. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Backend → Database                    ✅ allowed
Backend → Random external destination ❌ blocked
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You express this using:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;policyTypes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;Egress&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  An Egress Policy Example
&lt;/h2&gt;

&lt;p&gt;Suppose backend Pods should only be allowed to talk to database Pods:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;networking.k8s.io/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;NetworkPolicy&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;backend-to-database&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;podSelector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;backend&lt;/span&gt;

  &lt;span class="na"&gt;policyTypes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;Egress&lt;/span&gt;

  &lt;span class="na"&gt;egress&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;podSelector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;database&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Read it as: &lt;em&gt;"Select backend Pods, and allow their outgoing traffic to database Pods."&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;backend
   | egress allowed
   ↓
database
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Namespaces Matter More Than You Think
&lt;/h2&gt;

&lt;p&gt;This is one of the most important — and most frequently misunderstood — NetworkPolicy concepts.&lt;/p&gt;

&lt;p&gt;Suppose you have a &lt;code&gt;frontend&lt;/code&gt; Pod (labeled &lt;code&gt;app=frontend&lt;/code&gt;) in the &lt;code&gt;frontend&lt;/code&gt; namespace, and a &lt;code&gt;backend&lt;/code&gt; Pod (labeled &lt;code&gt;app=backend&lt;/code&gt;) in the &lt;code&gt;backend&lt;/code&gt; namespace. If you write:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;podSelector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;frontend&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;...does this mean &lt;em&gt;"any frontend Pod in the entire cluster"&lt;/em&gt;? &lt;strong&gt;No.&lt;/strong&gt; A plain &lt;code&gt;podSelector&lt;/code&gt; in a NetworkPolicy only selects Pods &lt;strong&gt;within the same namespace as the policy itself.&lt;/strong&gt; This is exactly why &lt;code&gt;namespaceSelector&lt;/code&gt; exists.&lt;/p&gt;

&lt;h2&gt;
  
  
  namespaceSelector
&lt;/h2&gt;

&lt;p&gt;Suppose you want: &lt;em&gt;"Allow traffic from Pods in the &lt;code&gt;frontend&lt;/code&gt; namespace."&lt;/em&gt; You'd write:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;namespaceSelector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;frontend&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;frontend namespace
        | allowed
        ↓
backend namespace
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Combining podSelector and namespaceSelector
&lt;/h2&gt;

&lt;p&gt;You can combine both for much more precise targeting:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;namespaceSelector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;frontend&lt;/span&gt;
    &lt;span class="na"&gt;podSelector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;frontend&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This means: &lt;em&gt;"Allow traffic from Pods labeled &lt;code&gt;app: frontend&lt;/code&gt;, but only inside namespaces labeled &lt;code&gt;name: frontend&lt;/code&gt;."&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;namespace
    +
pod label
    ↓
specific source Pods
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Three Key Selectors: podSelector, namespaceSelector, ipBlock
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;podSelector&lt;/code&gt;&lt;/strong&gt; — selects Pods based on labels:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;podSelector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;backend&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;&lt;code&gt;namespaceSelector&lt;/code&gt;&lt;/strong&gt; — selects namespaces based on labels:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;namespaceSelector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;team&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;payments&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;&lt;code&gt;ipBlock&lt;/code&gt;&lt;/strong&gt; — selects IP ranges:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;ipBlock&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;cidr&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;10.0.0.0/8&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is especially useful when communicating with systems outside Kubernetes entirely — for example, an external database at a fixed IP or CIDR range:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Pod
 | allowed
 ↓
10.20.0.0/16
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Restricting Ports
&lt;/h2&gt;

&lt;p&gt;NetworkPolicy can also restrict specific ports. Suppose &lt;code&gt;backend&lt;/code&gt; only listens on TCP &lt;code&gt;8080&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;protocol&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;TCP&lt;/span&gt;
    &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8080&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this in place (assuming the relevant isolation applies):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;frontend → backend:8080     ✅
frontend → backend:22       ❌
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is powerful because you're simultaneously controlling &lt;strong&gt;who&lt;/strong&gt; can connect and &lt;strong&gt;on which port&lt;/strong&gt; — a much finer-grained model than simple Pod-to-Pod allow/deny.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Complete Multi-Tier Example
&lt;/h2&gt;

&lt;p&gt;Suppose we have &lt;code&gt;frontend&lt;/code&gt;, &lt;code&gt;backend&lt;/code&gt;, and &lt;code&gt;database&lt;/code&gt; Pods, each in their own namespace, and we want:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;frontend → backend:8080     ✅
backend  → database:5432    ✅
frontend → database:5432    ❌
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                 ┌───────────────┐
                 │   frontend    │
                 └───────┬───────┘
                         │
                       8080
                         ↓
                 ┌───────────────┐
                 │    backend    │
                 └───────┬───────┘
                         │
                       5432
                         ↓
                 ┌───────────────┐
                 │   database    │
                 └───────────────┘

frontend ────────────────X────────→ database
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is exactly the kind of layered security architecture NetworkPolicy is designed to express.&lt;/p&gt;

&lt;h2&gt;
  
  
  NetworkPolicy Is Not an Application Firewall
&lt;/h2&gt;

&lt;p&gt;An important distinction: NetworkPolicy operates primarily at the &lt;strong&gt;network traffic&lt;/strong&gt; level, not the application layer. It can say:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Allow frontend → backend:8080
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But it generally has no concept of things like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;HTTP: GET /users
HTTP: POST /delete-account
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For that kind of application-layer control, you'd need additional mechanisms like an Ingress/Gateway, an API gateway, a service mesh, or application-level authorization. In short: &lt;strong&gt;NetworkPolicy = network-level access control&lt;/strong&gt;, not HTTP-aware access control.&lt;/p&gt;

&lt;h2&gt;
  
  
  NetworkPolicy Doesn't Replace Authentication
&lt;/h2&gt;

&lt;p&gt;If &lt;code&gt;frontend → backend&lt;/code&gt; is allowed by a NetworkPolicy, that does &lt;strong&gt;not&lt;/strong&gt; mean &lt;em&gt;"the frontend is authenticated."&lt;/em&gt; These are entirely separate security layers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;NetworkPolicy&lt;/strong&gt; answers: &lt;em&gt;can network traffic flow at all?&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Authentication&lt;/strong&gt; answers: &lt;em&gt;who are you?&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Authorization&lt;/strong&gt; answers: &lt;em&gt;are you allowed to perform this specific action?&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Don't confuse network-level permission with identity or permission checks — you typically need all three layered together for real security.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who Actually Enforces NetworkPolicy?
&lt;/h2&gt;

&lt;p&gt;Here's a subtle but critical concept: &lt;strong&gt;a NetworkPolicy object only describes the desired rules — the actual networking implementation has to enforce them.&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;NetworkPolicy
      ↓
rules
      ↓
CNI/network dataplane
      ↓
enforcement
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If your CNI plugin doesn't support NetworkPolicy enforcement, creating a NetworkPolicy object won't magically create a firewall — it'll just sit there, unenforced. This is one of many reasons the choice of CNI plugin matters, which we'll explore properly in Level 7.&lt;/p&gt;

&lt;p&gt;For now, keep the division of responsibility simple:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;NetworkPolicy → "What traffic should be allowed?"
CNI           → "How do I actually enforce that?"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Don't worry yet about whether enforcement happens via iptables, eBPF, or some other mechanism — those details come later.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two Common Misconceptions
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Misconception 1: "NetworkPolicy protects my whole cluster."&lt;/strong&gt;&lt;br&gt;
Not exactly — policies are namespace-scoped objects that select specific Pods. You need to design policies deliberately across every namespace and workload in your architecture; there's no single switch that secures everything at once.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Misconception 2: &lt;code&gt;podSelector: {}&lt;/code&gt; means "no Pods."&lt;/strong&gt;&lt;br&gt;
Actually, the opposite is true — &lt;code&gt;podSelector: {}&lt;/code&gt; means &lt;strong&gt;select all Pods&lt;/strong&gt; in the policy's namespace. This is a very easy mistake to make, and it has real security implications if misunderstood.&lt;/p&gt;
&lt;h2&gt;
  
  
  Hands-On: Inspecting NetworkPolicies
&lt;/h2&gt;

&lt;p&gt;Check what NetworkPolicies exist in your cluster:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get networkpolicy
&lt;span class="c"&gt;# or the shorter alias:&lt;/span&gt;
kubectl get netpol
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inspect one in detail:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl describe networkpolicy &amp;lt;name&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This shows you the Pod selector, policy types, ingress/egress rules, ports, and sources/destinations all in one place.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hands-On: Creating an Allow Policy
&lt;/h2&gt;

&lt;p&gt;Create two labeled Pods:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl run frontend &lt;span class="nt"&gt;--image&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;nginx &lt;span class="nt"&gt;--labels&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;app&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;frontend
kubectl run backend &lt;span class="nt"&gt;--image&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;nginx &lt;span class="nt"&gt;--labels&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;app&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;backend
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Verify their labels:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get pods &lt;span class="nt"&gt;--show-labels&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="s"&gt;frontend   app=frontend&lt;/span&gt;
&lt;span class="s"&gt;backend    app=backend&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now apply a policy selecting &lt;code&gt;backend&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;networking.k8s.io/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;NetworkPolicy&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;backend-policy&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;podSelector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;backend&lt;/span&gt;
  &lt;span class="na"&gt;policyTypes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;Ingress&lt;/span&gt;
  &lt;span class="na"&gt;ingress&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;podSelector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;frontend&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; backend-policy.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The conceptual result: &lt;code&gt;frontend → backend&lt;/code&gt; is allowed, while other sources attempting to reach &lt;code&gt;backend&lt;/code&gt; may be blocked, depending on your cluster's NetworkPolicy implementation and any other policies in effect.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hands-On: The Default-Deny Lab
&lt;/h2&gt;

&lt;p&gt;A great learning exercise is applying a namespace-wide default deny:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;networking.k8s.io/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;NetworkPolicy&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;default-deny&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;podSelector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;
  &lt;span class="na"&gt;policyTypes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;Ingress&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; default-deny.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now every selected Pod is denied ingress traffic by default:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;All selected Pods
      ↑
      |
   DENY by default
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From here, you layer in specific allow policies as needed — the classic pattern:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DEFAULT DENY → ALLOW ONLY WHAT IS REQUIRED
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  A Production Mental Model
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                  Internet
                     |
                     ↓
                 Ingress
                     |
                     ↓
                 Frontend
                     |
                     ↓
                  Backend
                     |
                     ↓
                 Database
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A realistic NetworkPolicy setup might enforce:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Internet → Frontend        allowed at edge
Frontend → Backend:8080    allowed
Backend  → Database:5432   allowed

Frontend → Database        blocked
Database → Frontend        blocked
Random Pod → Database      blocked
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's genuine network segmentation, built entirely out of Kubernetes-native objects.&lt;/p&gt;

&lt;h2&gt;
  
  
  Troubleshooting NetworkPolicy
&lt;/h2&gt;

&lt;p&gt;Suppose your application suddenly can't connect to something it used to reach fine. Don't immediately assume the Service is broken — walk the chain methodically:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Application → DNS → Service → Pod → NetworkPolicy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the Pod was reachable directly before a policy was applied, but not afterward, the NetworkPolicy is the likely suspect. Useful commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get networkpolicy
kubectl describe networkpolicy &amp;lt;name&amp;gt;
kubectl get pods &lt;span class="nt"&gt;--show-labels&lt;/span&gt;
kubectl get namespaces &lt;span class="nt"&gt;--show-labels&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The single biggest troubleshooting mistake: &lt;strong&gt;the selector doesn't match the Pods you think it matches.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Selector Debugging
&lt;/h3&gt;

&lt;p&gt;Suppose your policy says:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;backend&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But your actual Pod is labeled:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="s"&gt;app=back-end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Policy selector: app=backend
                     ↓
                     X
Pod label:       app=back-end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No match — the policy simply isn't selecting the Pod you expected. Always verify with &lt;code&gt;kubectl get pods --show-labels&lt;/code&gt; before assuming something deeper is wrong.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Namespace Mistake
&lt;/h3&gt;

&lt;p&gt;Suppose you have a &lt;code&gt;frontend&lt;/code&gt; Pod in the &lt;code&gt;frontend&lt;/code&gt; namespace and a &lt;code&gt;backend&lt;/code&gt; Pod in the &lt;code&gt;backend&lt;/code&gt; namespace, and you write only:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;podSelector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;frontend&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Remember: &lt;strong&gt;a plain &lt;code&gt;podSelector&lt;/code&gt; in a NetworkPolicy is always namespace-local.&lt;/strong&gt; If you need to allow traffic across namespaces, you need &lt;code&gt;namespaceSelector&lt;/code&gt; combined with &lt;code&gt;podSelector&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Mental Model to Memorize
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;NetworkPolicy
      |
      ↓
Which Pods?
      |
      ↓
Ingress / Egress?
      |
      ↓
From where / To where?
      |
      ↓
Which ports?
      |
      ↓
Allow traffic
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or, compressed even further:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;WHO → WHERE → DIRECTION → PORT → ALLOW
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A useful production security model to keep in your head:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;              Internet
                  |
                  ↓
              Ingress
                  |
                  ↓
             Frontend
                  |
             NetworkPolicy
                  |
                  ↓
              Backend
                  |
             NetworkPolicy
                  |
                  ↓
             Database
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each boundary in your architecture can — and often should — have its own explicit rules.&lt;/p&gt;

&lt;h2&gt;
  
  
  Level 6 Checkpoint
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. What is NetworkPolicy?&lt;/strong&gt;&lt;br&gt;
A Kubernetes API for defining network traffic rules for selected Pods.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. What is ingress?&lt;/strong&gt;&lt;br&gt;
Traffic coming into a Pod — &lt;code&gt;A → Pod&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. What is egress?&lt;/strong&gt;&lt;br&gt;
Traffic going out of a Pod — &lt;code&gt;Pod → B&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. What does &lt;code&gt;podSelector&lt;/code&gt; do?&lt;/strong&gt;&lt;br&gt;
Selects Pods by labels, within the policy's own namespace.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. What does &lt;code&gt;namespaceSelector&lt;/code&gt; do?&lt;/strong&gt;&lt;br&gt;
Selects namespaces by labels.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6. What does &lt;code&gt;ipBlock&lt;/code&gt; do?&lt;/strong&gt;&lt;br&gt;
Selects an IP/CIDR range, typically for traffic to/from outside the cluster.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;7. What is default deny?&lt;/strong&gt;&lt;br&gt;
Start by denying all traffic, then explicitly allow only what's actually required.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;8. Does NetworkPolicy itself implement packet filtering?&lt;/strong&gt;&lt;br&gt;
No — the underlying network implementation (CNI dataplane) must support and enforce it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;9. Does NetworkPolicy provide application authentication?&lt;/strong&gt;&lt;br&gt;
No. &lt;code&gt;NetworkPolicy → network access&lt;/code&gt;, &lt;code&gt;Authentication → identity&lt;/code&gt;, &lt;code&gt;Authorization → permissions&lt;/code&gt; — three separate layers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;10. Does NetworkPolicy understand HTTP URLs?&lt;/strong&gt;&lt;br&gt;
Generally no — it's primarily network-level control, not application-aware.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Next: CNI
&lt;/h2&gt;

&lt;p&gt;In &lt;strong&gt;Level 7&lt;/strong&gt;, we'll finally answer a question we've deliberately postponed since Level 1:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;When Kubernetes creates a Pod, who actually creates its &lt;code&gt;eth0&lt;/code&gt;, its veth pair, its IP address, its routes, and its overall network connectivity?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We'll walk through CNI, CNI plugins, IPAM, veth pairs, bridges/routes/overlays, and popular real-world CNI implementations like Calico, Cilium, and Flannel, along with cloud-native CNIs — while still saving the deepest dataplane internals for Level 8.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;NetworkPolicy is what turns Kubernetes networking from "everything can talk to everything" into a deliberately designed, segmented system. The core ideas are simple once they click: a policy selects a group of Pods, declares a direction (ingress and/or egress), and defines exactly who is allowed to communicate with them and on which ports. Layer in a default-deny policy per namespace, and you've built the foundation of real network security in Kubernetes.&lt;/p&gt;

&lt;p&gt;Just remember the two biggest gotchas: &lt;code&gt;podSelector&lt;/code&gt; is namespace-local unless combined with &lt;code&gt;namespaceSelector&lt;/code&gt;, and NetworkPolicy is only as effective as the CNI plugin enforcing it. Get those two details right, and you'll avoid the vast majority of real-world NetworkPolicy debugging headaches.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Found this useful?&lt;/strong&gt; Follow along for Level 7, where we finally dig into CNI itself — the component quietly responsible for everything we've built on top of it since Level 1. Drop your questions in the comments, and share this with a teammate who's still running a completely flat, unsegmented cluster network. Let's keep building this Kubernetes networking roadmap together. 🚀&lt;/p&gt;

</description>
      <category>docker</category>
      <category>containers</category>
      <category>kubernetes</category>
      <category>networking</category>
    </item>
    <item>
      <title>Kubernetes Networking [Level-5: Ingress/Gateway]</title>
      <dc:creator>ADITYA RAJ</dc:creator>
      <pubDate>Sat, 15 Aug 2026 12:06:46 +0000</pubDate>
      <link>https://dev.to/iadiraj/kubernetes-networking-level-5-ingressgateway-4cbc</link>
      <guid>https://dev.to/iadiraj/kubernetes-networking-level-5-ingressgateway-4cbc</guid>
      <description>&lt;p&gt;This is &lt;strong&gt;Level 5&lt;/strong&gt; of our Kubernetes networking series. So far, we've built up a solid foundation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;LEVEL 1 — Pod networking
LEVEL 2 — Pod-to-Pod communication
LEVEL 3 — Service (a stable internal endpoint)
LEVEL 4 — DNS (service name → Service IP)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But we still have a glaring gap: &lt;strong&gt;how does a real user on the internet actually reach your Kubernetes application?&lt;/strong&gt; That's exactly what this article covers — Ingress, Ingress Controllers, and the newer Gateway API.&lt;/p&gt;

&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;The Problem: The Internet Can't Reach a ClusterIP&lt;/li&gt;
&lt;li&gt;The Basic Solution: Ingress and Gateway API&lt;/li&gt;
&lt;li&gt;What Is Ingress?&lt;/li&gt;
&lt;li&gt;A Routing Example&lt;/li&gt;
&lt;li&gt;Ingress Is Not the Actual Proxy&lt;/li&gt;
&lt;li&gt;A Simple Analogy: Traffic Police&lt;/li&gt;
&lt;li&gt;A Basic Ingress YAML Example&lt;/li&gt;
&lt;li&gt;Breaking Down the Key Fields&lt;/li&gt;
&lt;li&gt;Host-Based Routing&lt;/li&gt;
&lt;li&gt;Path-Based Routing&lt;/li&gt;
&lt;li&gt;Why Not Just Use a LoadBalancer Service for Everything?&lt;/li&gt;
&lt;li&gt;The Complete Traffic Flow&lt;/li&gt;
&lt;li&gt;Where Does DNS Fit In?&lt;/li&gt;
&lt;li&gt;The Ingress Controller&lt;/li&gt;
&lt;li&gt;A Typical Architecture&lt;/li&gt;
&lt;li&gt;Ingress vs Service&lt;/li&gt;
&lt;li&gt;Ingress vs LoadBalancer Service&lt;/li&gt;
&lt;li&gt;HTTPS and TLS Termination&lt;/li&gt;
&lt;li&gt;Why Terminate TLS at the Edge?&lt;/li&gt;
&lt;li&gt;Referencing a TLS Certificate&lt;/li&gt;
&lt;li&gt;Routing Multiple Domains&lt;/li&gt;
&lt;li&gt;The Gateway API&lt;/li&gt;
&lt;li&gt;GatewayClass, Gateway, and HTTPRoute&lt;/li&gt;
&lt;li&gt;Ingress vs Gateway API&lt;/li&gt;
&lt;li&gt;Important Distinctions: Ingress Is Not CNI or Service&lt;/li&gt;
&lt;li&gt;Troubleshooting Ingress Layer by Layer&lt;/li&gt;
&lt;li&gt;Common Ingress Mistakes&lt;/li&gt;
&lt;li&gt;The Complete Kubernetes Networking Picture (Levels 1–5)&lt;/li&gt;
&lt;li&gt;The Mental Model to Memorize&lt;/li&gt;
&lt;li&gt;Level 5 Checkpoint&lt;/li&gt;
&lt;li&gt;What's Next: NetworkPolicy&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  The Problem: The Internet Can't Reach a ClusterIP
&lt;/h2&gt;

&lt;p&gt;Suppose you want users to reach your application at &lt;code&gt;myapp.example.com&lt;/code&gt;. Inside your cluster, you have:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;Service&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;frontend&lt;/span&gt;
&lt;span class="na"&gt;ClusterIP&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;10.96.20.10&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;frontend Service
       ├── Pod 1
       ├── Pod 2
       └── Pod 3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A user on the internet can't simply visit &lt;code&gt;http://10.96.20.10&lt;/code&gt; — that's a &lt;strong&gt;private&lt;/strong&gt; Kubernetes Service IP, invisible outside the cluster. We need something sitting at the edge of the cluster to bridge that gap.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Basic Solution: Ingress and Gateway API
&lt;/h2&gt;

&lt;p&gt;Historically, Kubernetes solved this with &lt;strong&gt;Ingress&lt;/strong&gt;. More recently, Kubernetes introduced a more expressive alternative: the &lt;strong&gt;Gateway API&lt;/strong&gt;. At a high level, both follow the same shape:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Internet
   ↓
Ingress / Gateway
   ↓
Service
   ↓
Pods
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's the core mental model for this entire article.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is Ingress?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Ingress&lt;/strong&gt; is a Kubernetes API object that describes &lt;em&gt;how incoming HTTP/HTTPS traffic should be routed to Services&lt;/em&gt;. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;app.example.com → frontend Service
api.example.com → backend Service
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or path-based:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;example.com/api → api Service
example.com/    → frontend Service
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In short, Ingress lets you declaratively describe HTTP routing rules for your cluster.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Routing Example
&lt;/h2&gt;

&lt;p&gt;Suppose you have a &lt;code&gt;frontend&lt;/code&gt; Service and a &lt;code&gt;backend&lt;/code&gt; Service, and you want:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;app.example.com      → frontend
app.example.com/api  → backend
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can express this entirely through an Ingress object:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                  Internet
                     |
                     ↓
              Ingress Layer
                 /       \
                ↓         ↓
        frontend Service  backend Service
               |              |
             Pods           Pods
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Ingress Is Not the Actual Proxy
&lt;/h2&gt;

&lt;p&gt;This is a critical point that trips up a lot of beginners: &lt;strong&gt;an Ingress object doesn't magically start receiving internet traffic on its own.&lt;/strong&gt; It's just a set of rules. You need an &lt;strong&gt;Ingress Controller&lt;/strong&gt; to actually enforce them — implementations include NGINX, HAProxy, Traefik, and various cloud-provider load balancer integrations.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Ingress            = rules/configuration
Ingress Controller = the component that actually implements those rules
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  A Simple Analogy: Traffic Police
&lt;/h2&gt;

&lt;p&gt;Imagine a large building with a single main entrance from the street:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Internet → Main entrance
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At the entrance, someone asks &lt;em&gt;"where are you going?"&lt;/em&gt; If you say &lt;code&gt;app.example.com&lt;/code&gt;, you're directed to the frontend. If you say &lt;code&gt;api.example.com&lt;/code&gt;, you're directed to the backend.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;Ingress rules&lt;/strong&gt; are the instructions written down. The &lt;strong&gt;Ingress Controller&lt;/strong&gt; is the person actually standing there enforcing them.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Basic Ingress YAML Example
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;networking.k8s.io/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Ingress&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;app-ingress&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;rules&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;app.example.com&lt;/span&gt;
      &lt;span class="na"&gt;http&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/&lt;/span&gt;
            &lt;span class="na"&gt;pathType&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Prefix&lt;/span&gt;
            &lt;span class="na"&gt;backend&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;service&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;frontend&lt;/span&gt;
                &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                  &lt;span class="na"&gt;number&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Read this as: &lt;em&gt;"If the HTTP request is for &lt;code&gt;app.example.com&lt;/code&gt;, send it to the &lt;code&gt;frontend&lt;/code&gt; Service on port 80."&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Breaking Down the Key Fields
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;host&lt;/code&gt;&lt;/strong&gt; — which domain this rule matches:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;app.example.com&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;&lt;code&gt;path&lt;/code&gt;&lt;/strong&gt; — which URL path this rule matches. For example, &lt;code&gt;path: /&lt;/code&gt; with &lt;code&gt;pathType: Prefix&lt;/code&gt; could match &lt;code&gt;/&lt;/code&gt;, &lt;code&gt;/login&lt;/code&gt;, &lt;code&gt;/products&lt;/code&gt;, &lt;code&gt;/about&lt;/code&gt;, and so on, depending on the exact path-matching configuration.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;backend.service&lt;/code&gt;&lt;/strong&gt; — where the matched traffic gets sent:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;backend&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;service&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;frontend&lt;/span&gt;
    &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;number&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So together: &lt;code&gt;app.example.com → frontend Service → Pods&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Host-Based Routing
&lt;/h2&gt;

&lt;p&gt;One of the most useful Ingress features is routing based on hostname. Suppose you have three domains:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;app.example.com
api.example.com
admin.example.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can route each one to a different backend:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;app.example.com   → frontend Service
api.example.com   → backend Service
admin.example.com → admin Service
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A single entry point can serve many completely different applications this way.&lt;/p&gt;

&lt;h2&gt;
  
  
  Path-Based Routing
&lt;/h2&gt;

&lt;p&gt;You can also route based on the URL path rather than the hostname:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;example.com/       → frontend
example.com/api    → backend
example.com/admin  → admin
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                    Ingress
                       |
          ┌────────────┼────────────┐
          ↓            ↓            ↓
         /            /api        /admin
          ↓            ↓            ↓
      frontend       backend      admin
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This pattern is extremely common in real-world Kubernetes setups.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Not Just Use a LoadBalancer Service for Everything?
&lt;/h2&gt;

&lt;p&gt;A fair question: &lt;em&gt;"Why not just create a &lt;code&gt;LoadBalancer&lt;/code&gt; Service for every application?"&lt;/em&gt; You technically can — but imagine you have 50 applications:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;LoadBalancer 1 → App 1
LoadBalancer 2 → App 2
...
LoadBalancer 50 → App 50
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's a lot of external load balancers to manage (and often, a lot of cost). Instead, a single edge layer can route traffic to many applications at once:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                 Internet
                    ↓
             Load Balancer
                    ↓
              Ingress
             /    |    \
            ↓     ↓     ↓
         App1    App2    App3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One entry point, many destinations — far simpler to operate.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Complete Traffic Flow
&lt;/h2&gt;

&lt;p&gt;This is the most important diagram in this article. Suppose a user opens &lt;code&gt;https://app.example.com&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User
 | HTTPS
 ↓
DNS
 | app.example.com → public IP
 ↓
Load Balancer
 ↓
Ingress Controller
 | host = app.example.com
 ↓
frontend Service
 ↓
Endpoint / Pod
 ↓
Application
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice how many layers we've now connected across this entire series:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Internet → DNS → Load Balancer → Ingress → Service → Pod
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Where Does DNS Fit In?
&lt;/h2&gt;

&lt;p&gt;This is a different DNS context than the one we covered in Level 4 — it's worth being precise about the distinction.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;External DNS&lt;/strong&gt; (public internet):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;app.example.com → 203.0.113.50 (public IP / load balancer)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Cluster DNS&lt;/strong&gt; (internal, from Level 4):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;frontend.default.svc.cluster.local → Service IP
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Don't mix these two up — they're separate DNS systems solving separate problems, even though both are technically "DNS."&lt;/p&gt;

&lt;h2&gt;
  
  
  The Ingress Controller
&lt;/h2&gt;

&lt;p&gt;If you create an Ingress object but nothing is actually watching and implementing it, the rules just sit there inert. You need a running &lt;strong&gt;Ingress Controller&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Ingress object
      ↓
Ingress Controller
      ↓
Actual traffic handling
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The controller continuously watches Kubernetes API objects (Ingress resources) and configures its own proxy/load-balancing dataplane to match.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Typical Architecture
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                    Internet
                       |
                       ↓
                Cloud Load Balancer
                       |
                       ↓
              Ingress Controller
                       |
             ┌─────────┼─────────┐
             ↓         ↓         ↓
          Service A Service B Service C
             |         |         |
            Pods      Pods      Pods
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The exact shape of this architecture varies depending on your cloud provider and cluster setup, but this general pattern is extremely common.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ingress vs Service
&lt;/h2&gt;

&lt;p&gt;An important distinction to internalize:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Service&lt;/strong&gt; answers: &lt;em&gt;"How do I reach this group of Pods?"&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Service → Pods
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Ingress&lt;/strong&gt; answers: &lt;em&gt;"How do external HTTP/HTTPS requests get routed to Services?"&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Internet → Ingress → Service → Pods
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In short: &lt;strong&gt;Service is an internal/application endpoint abstraction; Ingress is HTTP/HTTPS edge routing.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Ingress vs LoadBalancer Service
&lt;/h2&gt;

&lt;p&gt;These two aren't competitors — they typically work together:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Internet
   ↓
Cloud Load Balancer
   ↓
Ingress Controller
   ↓
Service
   ↓
Pods
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The cloud load balancer's job is simply to get traffic &lt;em&gt;into&lt;/em&gt; the cluster. Once it arrives, the Ingress Controller decides &lt;em&gt;where within the cluster&lt;/em&gt; that HTTP request should actually go.&lt;/p&gt;

&lt;h2&gt;
  
  
  HTTPS and TLS Termination
&lt;/h2&gt;

&lt;p&gt;Ingress is commonly used to terminate TLS. When a user visits &lt;code&gt;https://app.example.com&lt;/code&gt;, the encrypted connection reaches the Ingress layer first:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Client
   | HTTPS
   ↓
Ingress Controller
   | HTTP or HTTPS
   ↓
Service
   ↓
Pod
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This process — decrypting HTTPS at the edge — is called &lt;strong&gt;TLS termination&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Terminate TLS at the Edge?
&lt;/h2&gt;

&lt;p&gt;Terminating TLS at the Ingress layer centralizes several responsibilities in one place: certificate management, HTTPS handling, HTTP routing, redirects, and both host- and path-based routing. Your application can then simply receive plain HTTP internally, if that fits your security model.&lt;/p&gt;

&lt;p&gt;That said, don't assume Ingress always means "HTTP behind the scenes" — you can also configure TLS to be re-encrypted or passed through all the way to the backend Pod, depending on your architecture and requirements.&lt;/p&gt;

&lt;h2&gt;
  
  
  Referencing a TLS Certificate
&lt;/h2&gt;

&lt;p&gt;An Ingress can reference a Kubernetes TLS Secret directly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;tls&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;hosts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;app.example.com&lt;/span&gt;
    &lt;span class="na"&gt;secretName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;app-tls&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The referenced Secret holds the certificate and private key material the Ingress implementation uses:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Client
   | HTTPS
   ↓
Ingress
   | TLS termination
   ↓
Service
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Routing Multiple Domains
&lt;/h2&gt;

&lt;p&gt;Suppose you're running several distinct applications under different subdomains:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;shop.example.com
api.example.com
admin.example.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A single Ingress layer can route all of them:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                     Ingress
                       |
        ┌──────────────┼──────────────┐
        ↓              ↓              ↓
 shop.example.com api.example.com admin.example.com
        ↓              ↓              ↓
      shop           backend         admin
     Service         Service        Service
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is host-based routing at work again, just applied across an entire portfolio of applications.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Gateway API
&lt;/h2&gt;

&lt;p&gt;Now let's look at the newer Kubernetes networking API: the &lt;strong&gt;Gateway API&lt;/strong&gt;. Think of it as an evolution of Ingress, not something unrelated:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Ingress     → older/simpler HTTP routing API
Gateway API → more expressive, extensible traffic-routing model
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Gateway API introduces a small family of dedicated resources: &lt;code&gt;GatewayClass&lt;/code&gt;, &lt;code&gt;Gateway&lt;/code&gt;, and &lt;code&gt;HTTPRoute&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  GatewayClass, Gateway, and HTTPRoute
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;GatewayClass&lt;/code&gt;&lt;/strong&gt; answers: &lt;em&gt;"What kind of Gateway implementation are we using?"&lt;/em&gt; — essentially, which controller manages Gateways of this class.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;Gateway&lt;/code&gt;&lt;/strong&gt; represents the actual traffic entry point:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Internet → Gateway
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It defines listeners, such as HTTP on port 80 or HTTPS on port 443.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;HTTPRoute&lt;/code&gt;&lt;/strong&gt; describes the routing rules themselves — for example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;app.example.com      → frontend Service
app.example.com/api  → backend Service
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Chained together:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Gateway → HTTPRoute → Service → Pod
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Ingress vs Gateway API
&lt;/h2&gt;

&lt;p&gt;You don't need to memorize every field of either API right now — just understand the high-level difference:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Ingress&lt;/th&gt;
&lt;th&gt;Gateway API&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Maturity&lt;/td&gt;
&lt;td&gt;Older, widely adopted&lt;/td&gt;
&lt;td&gt;Newer, more expressive API family&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scope&lt;/td&gt;
&lt;td&gt;Mainly HTTP/HTTPS routing&lt;/td&gt;
&lt;td&gt;Broader traffic-routing model&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Structure&lt;/td&gt;
&lt;td&gt;Simpler, single object&lt;/td&gt;
&lt;td&gt;More structured (GatewayClass + Gateway + Routes)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A useful mental model:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Ingress:     "Here are my HTTP routing rules."
Gateway API: "Here is my traffic infrastructure, and here are the routes attached to it."
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Gateway API's basic resource relationship looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GatewayClass → Gateway → HTTPRoute → Service → Pods
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You don't need to implement any of this from scratch right now — the goal here is understanding the traffic flow conceptually.&lt;/p&gt;

&lt;h2&gt;
  
  
  Important Distinctions: Ingress Is Not CNI or Service
&lt;/h2&gt;

&lt;p&gt;Two easy things to conflate — worth separating clearly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ingress is not CNI:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CNI     → how Pods get network connectivity
Ingress → how external HTTP/HTTPS traffic is routed to Services
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Ingress is not Service:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Service → stable endpoint → Pods
Ingress → external HTTP/HTTPS → Service
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The full combined chain is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Internet → Ingress → Service → Pod
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Troubleshooting Ingress Layer by Layer
&lt;/h2&gt;

&lt;p&gt;When &lt;code&gt;https://app.example.com&lt;/code&gt; doesn't work, resist the urge to restart things randomly. Instead, work through the chain one layer at a time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Layer 1 — External DNS:&lt;/strong&gt; Does &lt;code&gt;app.example.com&lt;/code&gt; resolve to the expected public IP?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nslookup app.example.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Layer 2 — Load Balancer:&lt;/strong&gt; Can the public IP actually reach your load balancer or entry point?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Layer 3 — Ingress Controller:&lt;/strong&gt; Is it actually running?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get pods &lt;span class="nt"&gt;-A&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Look specifically for your ingress controller's Pods.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Layer 4 — Ingress rules:&lt;/strong&gt; Check the configuration itself.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get ingress
kubectl describe ingress &amp;lt;name&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Verify the &lt;code&gt;host&lt;/code&gt;, &lt;code&gt;path&lt;/code&gt;, backend &lt;code&gt;Service&lt;/code&gt;, and &lt;code&gt;TLS&lt;/code&gt; configuration all match what you expect.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Layer 5 — Service:&lt;/strong&gt; Does the target Service actually exist?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get svc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Layer 6 — Endpoints:&lt;/strong&gt; Does the Service have live backend endpoints?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get endpointslices
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Layer 7 — Pod:&lt;/strong&gt; Is the application actually listening on the expected port?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Service → Pod → Application
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Put together, this gives you a reliable troubleshooting chain:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DNS → Load Balancer → Ingress Controller → Ingress/Gateway rule → Service → Endpoint → Pod → Application
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Common Ingress Mistakes
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Mistake 1 — Wrong hostname:&lt;/strong&gt; The Ingress rule expects &lt;code&gt;api.example.com&lt;/code&gt;, but the user requests &lt;code&gt;app.example.com&lt;/code&gt; — no rule matches.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mistake 2 — Wrong Service name:&lt;/strong&gt; The Ingress points to &lt;code&gt;backend-service&lt;/code&gt;, but the actual Service is named &lt;code&gt;backend&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mistake 3 — Wrong Service port:&lt;/strong&gt; The Ingress specifies port 80, but the Service actually exposes a different port.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mistake 4 — Service has no endpoints:&lt;/strong&gt; The Service &lt;code&gt;backend&lt;/code&gt; exists, but its selector doesn't match any running Pods — traffic reaches the Service and simply has nowhere to go.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mistake 5 — External DNS points to the wrong place:&lt;/strong&gt; &lt;code&gt;app.example.com&lt;/code&gt; resolves to the wrong public IP entirely. In this case, your Kubernetes cluster can be perfectly healthy while users still can't reach the application — the problem never even makes it inside the cluster.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Complete Kubernetes Networking Picture (Levels 1–5)
&lt;/h2&gt;

&lt;p&gt;We can now connect everything we've covered across this series so far:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                           INTERNET
                              |
                              ↓
                         External DNS
                              |
                              ↓
                       Public IP / LB
                              |
                              ↓
                    Ingress / Gateway
                              |
                              ↓
                          Service
                              |
                              ↓
                         Pod IP
                              |
                              ↓
                       Pod networking
                              |
                              ↓
                         Application
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And internally, on the Service side:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Service
   ↓
EndpointSlice
   ├── Pod A
   ├── Pod B
   └── Pod C
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a genuine milestone — you now have a complete, end-to-end mental model from a browser tab all the way down to a running container.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Mental Model to Memorize
&lt;/h2&gt;

&lt;p&gt;Don't try to memorize every YAML field from this article. Instead, memorize the shape and the responsibility of each layer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;External DNS → Public endpoint → Ingress/Gateway → Service → EndpointSlice → Pod
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;DNS&lt;/strong&gt; → &lt;em&gt;"Where is it?"&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ingress/Gateway&lt;/strong&gt; → &lt;em&gt;"Which application should receive this request?"&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Service&lt;/strong&gt; → &lt;em&gt;"Which Pods provide this application?"&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;EndpointSlice&lt;/strong&gt; → &lt;em&gt;"Which endpoints currently exist?"&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pod networking&lt;/strong&gt; → &lt;em&gt;"How does the packet actually reach the Pod?"&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Level 5 Checkpoint
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. What problem does Ingress solve?&lt;/strong&gt;&lt;br&gt;
Routing external HTTP/HTTPS traffic to Kubernetes Services.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Is Ingress itself a proxy?&lt;/strong&gt;&lt;br&gt;
Not necessarily — the Ingress object defines rules; an Ingress Controller is what actually implements them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. What is host-based routing?&lt;/strong&gt;&lt;br&gt;
Routing based on hostname — e.g., &lt;code&gt;app.example.com → frontend&lt;/code&gt;, &lt;code&gt;api.example.com → backend&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. What is path-based routing?&lt;/strong&gt;&lt;br&gt;
Routing based on URL path — e.g., &lt;code&gt;example.com/ → frontend&lt;/code&gt;, &lt;code&gt;example.com/api → backend&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. What is TLS termination?&lt;/strong&gt;&lt;br&gt;
When the edge component (the Ingress Controller) receives HTTPS traffic and handles the TLS connection before forwarding the request onward.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6. Service vs Ingress?&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;Ingress → external HTTP/HTTPS → Service → Pods&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;7. What is the Gateway API?&lt;/strong&gt;&lt;br&gt;
A newer, more expressive Kubernetes API family for configuring traffic infrastructure and the routes attached to it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;8. What are the key Gateway API resources?&lt;/strong&gt;&lt;br&gt;
At this level, remember &lt;code&gt;GatewayClass&lt;/code&gt;, &lt;code&gt;Gateway&lt;/code&gt;, and &lt;code&gt;HTTPRoute&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Next: NetworkPolicy
&lt;/h2&gt;

&lt;p&gt;In &lt;strong&gt;Level 6&lt;/strong&gt;, we'll tackle a very different kind of question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Pods can currently talk to each other freely. What if I &lt;em&gt;don't&lt;/em&gt; want every Pod to be able to talk to every other Pod?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We'll cover allow/deny traffic rules, ingress vs egress policies, selectors, namespaces, CIDR-based rules, default-deny policies, and one crucial caveat: &lt;strong&gt;NetworkPolicy only works when your networking implementation actually supports and enforces it.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Ingress and the Gateway API are what finally connect the outside world to your Kubernetes Services. An Ingress (or Gateway) object is just a declaration of routing intent — host rules, path rules, TLS settings — while an Ingress Controller (or Gateway implementation) is the actual component that turns those rules into working traffic routing. Once you can trace a request all the way from external DNS through the load balancer, the Ingress Controller, the Service, and finally into a Pod, Kubernetes networking stops feeling like a black box.&lt;/p&gt;

&lt;p&gt;The next time something breaks in production, don't guess — walk the chain layer by layer: DNS, load balancer, Ingress Controller, Ingress rule, Service, endpoints, Pod. That habit will save you far more time than randomly restarting components.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Enjoyed this deep dive?&lt;/strong&gt; Follow along for Level 6, where we lock down Pod-to-Pod traffic using NetworkPolicy. Drop your questions in the comments, and share this with a teammate still confused about why their Ingress "isn't working" even though the Pods are healthy. Let's keep building this Kubernetes networking roadmap together. 🚀&lt;/p&gt;

</description>
      <category>networking</category>
      <category>kubernetes</category>
      <category>containers</category>
      <category>linux</category>
    </item>
    <item>
      <title>Kubernetes Networking [Level-4: Services Discovery/DNS]</title>
      <dc:creator>ADITYA RAJ</dc:creator>
      <pubDate>Sat, 15 Aug 2026 11:04:40 +0000</pubDate>
      <link>https://dev.to/iadiraj/kubernetes-networking-level-4-services-discoverydns-3de9</link>
      <guid>https://dev.to/iadiraj/kubernetes-networking-level-4-services-discoverydns-3de9</guid>
      <description>&lt;p&gt;This is &lt;strong&gt;Level 4&lt;/strong&gt; of our Kubernetes networking series. In Level 3, we introduced the Service — a stable virtual IP that solves the problem of ever-changing Pod IPs. But that left one question unanswered:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;How does an application find a Kubernetes Service without hardcoding its IP address?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Instead of applications relying on this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Frontend → 10.96.120.50:80
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;we want something far more human-friendly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Frontend → backend:80
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's exactly what &lt;strong&gt;Service Discovery&lt;/strong&gt; solves, and in Kubernetes, it's built on top of DNS.&lt;/p&gt;

&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;The Problem: Hardcoded IPs Are Fragile&lt;/li&gt;
&lt;li&gt;What Is DNS?&lt;/li&gt;
&lt;li&gt;Who Provides DNS in Kubernetes? CoreDNS&lt;/li&gt;
&lt;li&gt;Where CoreDNS Actually Runs&lt;/li&gt;
&lt;li&gt;How a Pod Knows Where DNS Is&lt;/li&gt;
&lt;li&gt;The Complete DNS Flow&lt;/li&gt;
&lt;li&gt;Why You Can Just Write "backend"&lt;/li&gt;
&lt;li&gt;The Kubernetes Service DNS Name Format&lt;/li&gt;
&lt;li&gt;Why Namespaces Matter for DNS&lt;/li&gt;
&lt;li&gt;Cross-Namespace Service Access&lt;/li&gt;
&lt;li&gt;A Full DNS Name Example&lt;/li&gt;
&lt;li&gt;DNS Doesn't Directly Find the Pod&lt;/li&gt;
&lt;li&gt;DNS and Service Are Different Jobs&lt;/li&gt;
&lt;li&gt;Hands-On: Testing DNS Yourself&lt;/li&gt;
&lt;li&gt;Using nslookup for Debugging&lt;/li&gt;
&lt;li&gt;A Layered Debugging Sequence&lt;/li&gt;
&lt;li&gt;When DNS Works But the App Still Fails&lt;/li&gt;
&lt;li&gt;Headless Services&lt;/li&gt;
&lt;li&gt;Normal Service vs Headless Service&lt;/li&gt;
&lt;li&gt;What About Pod DNS?&lt;/li&gt;
&lt;li&gt;Understanding Search Domains&lt;/li&gt;
&lt;li&gt;The Complete Request, Step by Step&lt;/li&gt;
&lt;li&gt;The Mental Model to Memorize&lt;/li&gt;
&lt;li&gt;Interview Questions&lt;/li&gt;
&lt;li&gt;Level 4 Checkpoint&lt;/li&gt;
&lt;li&gt;What's Next: Ingress and Gateway API&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  The Problem: Hardcoded IPs Are Fragile
&lt;/h2&gt;

&lt;p&gt;Recall our Service from Level 3:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;Service&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;backend&lt;/span&gt;
&lt;span class="na"&gt;ClusterIP&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;10.96.120.50&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We could technically configure the frontend to call &lt;code&gt;http://10.96.120.50:80&lt;/code&gt; directly — but that's brittle. What happens if the Service gets recreated and its ClusterIP changes? The application shouldn't have to care.&lt;/p&gt;

&lt;p&gt;What we really want is to write:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http://backend:80
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Kubernetes makes this possible using &lt;strong&gt;DNS&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is DNS?
&lt;/h2&gt;

&lt;p&gt;At its core, DNS does one simple thing: it &lt;strong&gt;converts names into IP addresses&lt;/strong&gt;. On the public internet, this looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;google.com → IP address
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Kubernetes applies the exact same idea inside the cluster:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;backend → 10.96.120.50
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So the basic flow is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Application
    | "backend"
    ↓
   DNS
    | "10.96.120.50"
    ↓
 Service
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Who Provides DNS in Kubernetes? CoreDNS
&lt;/h2&gt;

&lt;p&gt;Kubernetes clusters typically run &lt;strong&gt;CoreDNS&lt;/strong&gt; — think of it as the cluster's built-in DNS server.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                 Kubernetes Cluster

Frontend Pod
     |
     | DNS query: "backend"
     ↓
 CoreDNS
     |
     | answer: 10.96.120.50
     ↓
 Service
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You don't need to understand CoreDNS internals yet. For now, just remember: &lt;strong&gt;CoreDNS = the Kubernetes cluster's DNS server.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Where CoreDNS Actually Runs
&lt;/h2&gt;

&lt;p&gt;CoreDNS itself runs as regular Pods inside your cluster. Check it out:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get pods &lt;span class="nt"&gt;-n&lt;/span&gt; kube-system
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You'll typically see something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;coredns-xxxxx
coredns-yyyyy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Interestingly, CoreDNS is itself exposed through a Kubernetes Service:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get svc &lt;span class="nt"&gt;-n&lt;/span&gt; kube-system
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You'll likely see a Service named &lt;code&gt;kube-dns&lt;/code&gt; — this name sticks around for historical reasons even when CoreDNS (not the older &lt;code&gt;kube-dns&lt;/code&gt; implementation) is what's actually running behind it.&lt;/p&gt;

&lt;h2&gt;
  
  
  How a Pod Knows Where DNS Is
&lt;/h2&gt;

&lt;p&gt;When Kubernetes creates a Pod, it automatically configures DNS settings inside it. You can inspect this yourself:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; &amp;lt;pod-name&amp;gt; &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="nb"&gt;cat&lt;/span&gt; /etc/resolv.conf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You'll typically see something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight conf"&gt;&lt;code&gt;&lt;span class="n"&gt;nameserver&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;.&lt;span class="m"&gt;96&lt;/span&gt;.&lt;span class="m"&gt;0&lt;/span&gt;.&lt;span class="m"&gt;10&lt;/span&gt;
&lt;span class="n"&gt;search&lt;/span&gt; &lt;span class="n"&gt;default&lt;/span&gt;.&lt;span class="n"&gt;svc&lt;/span&gt;.&lt;span class="n"&gt;cluster&lt;/span&gt;.&lt;span class="n"&gt;local&lt;/span&gt; &lt;span class="n"&gt;svc&lt;/span&gt;.&lt;span class="n"&gt;cluster&lt;/span&gt;.&lt;span class="n"&gt;local&lt;/span&gt; &lt;span class="n"&gt;cluster&lt;/span&gt;.&lt;span class="n"&gt;local&lt;/span&gt;
&lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="n"&gt;ndots&lt;/span&gt;:&lt;span class="m"&gt;5&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The exact IP depends on your cluster, but the key line is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight conf"&gt;&lt;code&gt;&lt;span class="n"&gt;nameserver&lt;/span&gt; &amp;lt;&lt;span class="n"&gt;cluster&lt;/span&gt;-&lt;span class="n"&gt;DNS&lt;/span&gt;-&lt;span class="n"&gt;IP&lt;/span&gt;&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This tells the Pod: &lt;em&gt;"Whenever you need to resolve a name, ask this DNS server."&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Complete DNS Flow
&lt;/h2&gt;

&lt;p&gt;Suppose we have a Frontend Pod and a Service named &lt;code&gt;backend&lt;/code&gt; with ClusterIP &lt;code&gt;10.96.120.50&lt;/code&gt;. The frontend runs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl http://backend
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The application needs to answer: &lt;em&gt;what does &lt;code&gt;backend&lt;/code&gt; actually point to?&lt;/em&gt; Here's the full chain:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Application
     | DNS lookup: backend
     ↓
/etc/resolv.conf
     ↓
CoreDNS
     ↓
10.96.120.50
     ↓
Service
     ↓
Backend Pod
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That entire sequence is &lt;strong&gt;Kubernetes Service Discovery&lt;/strong&gt; in action.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why You Can Just Write "backend"
&lt;/h2&gt;

&lt;p&gt;This works thanks to Kubernetes &lt;strong&gt;DNS search domains&lt;/strong&gt;. If your Pod lives in the &lt;code&gt;default&lt;/code&gt; namespace and your Service is named &lt;code&gt;backend&lt;/code&gt;, a query for just &lt;code&gt;backend&lt;/code&gt; gets expanded automatically through the configured search domains:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;backend
backend.default
backend.default.svc
backend.default.svc.cluster.local
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Eventually, one of these resolves to the Service's full DNS name — which is why you rarely need to type the whole thing out.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Kubernetes Service DNS Name Format
&lt;/h2&gt;

&lt;p&gt;Every Kubernetes Service gets a predictable, standard DNS name:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;service&amp;gt;.&amp;lt;namespace&amp;gt;.svc.&amp;lt;cluster-domain&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The cluster domain is usually &lt;code&gt;cluster.local&lt;/code&gt;. So a Service named &lt;code&gt;backend&lt;/code&gt; in the &lt;code&gt;default&lt;/code&gt; namespace becomes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;backend.default.svc.cluster.local
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Breaking it down:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;backend&lt;/code&gt;&lt;/strong&gt; → the Service name&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;default&lt;/code&gt;&lt;/strong&gt; → the namespace&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;svc&lt;/code&gt;&lt;/strong&gt; → indicates this is a Service&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;cluster.local&lt;/code&gt;&lt;/strong&gt; → the cluster's DNS domain&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Put together, &lt;code&gt;backend.default.svc.cluster.local&lt;/code&gt; unambiguously means &lt;em&gt;"the Service &lt;code&gt;backend&lt;/code&gt; in namespace &lt;code&gt;default&lt;/code&gt;."&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Namespaces Matter for DNS
&lt;/h2&gt;

&lt;p&gt;Imagine two namespaces — &lt;code&gt;default&lt;/code&gt; and &lt;code&gt;production&lt;/code&gt; — both containing a Service named &lt;code&gt;backend&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;    &lt;span class="s"&gt;backend&lt;/span&gt;
&lt;span class="na"&gt;production&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;backend&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So which one does a plain &lt;code&gt;backend&lt;/code&gt; refer to? By default, &lt;strong&gt;a Pod resolves short names relative to its own namespace.&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A Pod in &lt;code&gt;default&lt;/code&gt; resolving &lt;code&gt;backend&lt;/code&gt; effectively means &lt;code&gt;backend.default.svc.cluster.local&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;A Pod in &lt;code&gt;production&lt;/code&gt; resolving &lt;code&gt;backend&lt;/code&gt; effectively means &lt;code&gt;backend.production.svc.cluster.local&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is exactly why namespaces matter for Service discovery — they prevent naming collisions across teams and environments.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cross-Namespace Service Access
&lt;/h2&gt;

&lt;p&gt;Suppose a Frontend Pod living in the &lt;code&gt;frontend&lt;/code&gt; namespace needs to talk to a Backend Service living in the &lt;code&gt;backend&lt;/code&gt; namespace. You'd use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;backend.backend.svc.cluster.local
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice the two different meanings of "backend" here — the first &lt;code&gt;backend&lt;/code&gt; is the &lt;strong&gt;Service name&lt;/strong&gt;, and the second &lt;code&gt;backend&lt;/code&gt; is the &lt;strong&gt;namespace&lt;/strong&gt;. Together they resolve to &lt;em&gt;"the Service named &lt;code&gt;backend&lt;/code&gt;, in the namespace named &lt;code&gt;backend&lt;/code&gt;."&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  A Full DNS Name Example
&lt;/h2&gt;

&lt;p&gt;Let's use a clearer example. Suppose:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;Service&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;   &lt;span class="s"&gt;payments&lt;/span&gt;
&lt;span class="na"&gt;Namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;production&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Its full DNS name is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;payments.production.svc.cluster.local
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A frontend could call it in a few different ways:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl http://payments.production.svc.cluster.local
curl http://payments.production
curl http://payments   &lt;span class="c"&gt;# only if the caller is already in the "production" namespace&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The fully qualified name is always the safest and clearest option, especially across namespaces.&lt;/p&gt;

&lt;h2&gt;
  
  
  DNS Doesn't Directly Find the Pod
&lt;/h2&gt;

&lt;p&gt;Here's a subtle but crucial point. When you resolve &lt;code&gt;backend&lt;/code&gt;, DNS gives you the &lt;strong&gt;Service's ClusterIP&lt;/strong&gt; — not a Pod IP:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;backend → 10.96.120.50
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From there, a completely separate mechanism takes over:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;10.96.120.50
      ↓
Service dataplane
      ↓
Backend Pod
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So the full picture is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DNS → Service IP → Service routing → Pod
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Don't confuse &lt;strong&gt;DNS resolution&lt;/strong&gt; with &lt;strong&gt;Service traffic forwarding&lt;/strong&gt; — they're two distinct steps handled by two distinct systems.&lt;/p&gt;

&lt;h2&gt;
  
  
  DNS and Service Are Different Jobs
&lt;/h2&gt;

&lt;p&gt;This distinction is worth memorizing permanently:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;DNS answers:&lt;/strong&gt; &lt;em&gt;"What IP belongs to this name?"&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;backend → 10.96.120.50
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Service answers:&lt;/strong&gt; &lt;em&gt;"Where should traffic sent to this IP actually go?"&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;10.96.120.50 → Pod A / Pod B / Pod C
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Chained together:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Name → DNS → Service IP → Service dataplane → Pod
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Hands-On: Testing DNS Yourself
&lt;/h2&gt;

&lt;p&gt;Let's verify all of this with a real Pod. Create a simple test Pod:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl run &lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="nt"&gt;--image&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;busybox:1.36 &lt;span class="nt"&gt;--restart&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;Never &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="nb"&gt;sleep &lt;/span&gt;3600
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check it's running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get pod &lt;span class="nb"&gt;test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Shell into it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; &lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inside the Pod, inspect its DNS configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; /etc/resolv.conf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then try resolving the built-in Kubernetes API Service:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nslookup kubernetes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should get back a Service IP. If you created the &lt;code&gt;backend&lt;/code&gt; Service from Level 3, try that too:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nslookup backend
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Using nslookup for Debugging
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;nslookup&lt;/code&gt; is one of the most useful tools for troubleshooting DNS issues:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nslookup backend
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Conceptually, this asks: &lt;em&gt;"What is the IP of &lt;code&gt;backend&lt;/code&gt;?"&lt;/em&gt; — and gets back an answer like &lt;code&gt;10.96.120.50&lt;/code&gt;. Once you have that answer, &lt;code&gt;curl http://backend&lt;/code&gt; is really just using this same resolution behind the scenes.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Layered Debugging Sequence
&lt;/h2&gt;

&lt;p&gt;When &lt;code&gt;curl http://backend&lt;/code&gt; fails, don't immediately blame "the network." Break the problem down layer by layer instead:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1 — Does the Service exist?&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get svc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 2 — Does the Service have live endpoints?&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get endpointslices
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 3 — Does DNS resolve the name?&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nslookup backend
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 4 — Does the resolved Service IP respond?&lt;/strong&gt; Try connecting directly to the IP returned above.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 5 — Can the backend Pod itself be reached?&lt;/strong&gt; Try connecting directly using the Pod's own IP.&lt;/p&gt;

&lt;p&gt;This structured approach cleanly separates a &lt;strong&gt;DNS problem&lt;/strong&gt; from a &lt;strong&gt;Service problem&lt;/strong&gt; from a &lt;strong&gt;Pod networking problem&lt;/strong&gt; — an extremely useful skill for real production debugging.&lt;/p&gt;

&lt;h2&gt;
  
  
  When DNS Works But the App Still Fails
&lt;/h2&gt;

&lt;p&gt;Suppose &lt;code&gt;nslookup backend&lt;/code&gt; correctly returns &lt;code&gt;10.96.120.50&lt;/code&gt; — DNS is clearly working. But &lt;code&gt;curl http://backend&lt;/code&gt; still fails. Where's the problem?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DNS       ✅
  ↓
Service   ❓
  ↓
Endpoint  ❓
  ↓
Pod       ❓
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The key insight: &lt;strong&gt;DNS success does not mean application connectivity is working.&lt;/strong&gt; It only confirms that name resolution succeeded — the actual request still has to travel through the Service dataplane and reach a healthy Pod.&lt;/p&gt;

&lt;h2&gt;
  
  
  Headless Services
&lt;/h2&gt;

&lt;p&gt;Now for an important special case. Normally, a Service gets a ClusterIP:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;backend → 10.96.120.50
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But sometimes you don't want a virtual ClusterIP at all. For that, Kubernetes offers &lt;strong&gt;headless Services&lt;/strong&gt;, created using &lt;code&gt;clusterIP: None&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Service&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;backend&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;clusterIP&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;None&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;backend&lt;/span&gt;
  &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With a headless Service, DNS behaves differently: instead of returning a single virtual IP, it returns the &lt;strong&gt;individual IPs of every matching Pod&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;backend
   ↓
DNS
   ↓
10.244.1.5
10.244.2.7
10.244.2.9
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is especially useful for applications that need to know about individual backend instances directly — common examples include databases, distributed systems, and other stateful applications. We'll revisit this when we cover StatefulSets in a later part of the series.&lt;/p&gt;

&lt;h2&gt;
  
  
  Normal Service vs Headless Service
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Normal Service&lt;/th&gt;
&lt;th&gt;Headless Service&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;ClusterIP&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;code&gt;clusterIP&lt;/code&gt; field&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Virtual IP&lt;/td&gt;
&lt;td&gt;&lt;code&gt;None&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;DNS resolves to&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Service IP&lt;/td&gt;
&lt;td&gt;Individual Pod endpoints&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Typical use&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Normal application access&lt;/td&gt;
&lt;td&gt;Direct endpoint discovery&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Mental picture — &lt;strong&gt;normal Service:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DNS → 10.96.x.x → Service → Pods
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Headless Service:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DNS → Pod A, Pod B, Pod C (directly)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What About Pod DNS?
&lt;/h2&gt;

&lt;p&gt;Kubernetes can also provide DNS names for individual Pods under certain configurations. However, for standard application-to-application communication:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Prefer using a Service over relying on individual Pod DNS names or IPs.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Why? Because Pods are inherently temporary:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Pod A (10.244.1.5) dies → Pod B (10.244.4.9) takes over
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A Service hides all of that churn behind a stable name and IP — exactly the abstraction you want your applications depending on.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding Search Domains
&lt;/h2&gt;

&lt;p&gt;Revisit &lt;code&gt;/etc/resolv.conf&lt;/code&gt; once more:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight conf"&gt;&lt;code&gt;&lt;span class="n"&gt;search&lt;/span&gt; &lt;span class="n"&gt;default&lt;/span&gt;.&lt;span class="n"&gt;svc&lt;/span&gt;.&lt;span class="n"&gt;cluster&lt;/span&gt;.&lt;span class="n"&gt;local&lt;/span&gt; &lt;span class="n"&gt;svc&lt;/span&gt;.&lt;span class="n"&gt;cluster&lt;/span&gt;.&lt;span class="n"&gt;local&lt;/span&gt; &lt;span class="n"&gt;cluster&lt;/span&gt;.&lt;span class="n"&gt;local&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This &lt;code&gt;search&lt;/code&gt; line is what allows short names to "just work." A query for &lt;code&gt;backend&lt;/code&gt; gets automatically expanded through each of these search domains until one of them resolves successfully. This is precisely why Kubernetes applications can conveniently write:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http://backend
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;instead of always spelling out the full:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http://backend.default.svc.cluster.local
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The Complete Request, Step by Step
&lt;/h2&gt;

&lt;p&gt;Let's trace one full request end-to-end. The frontend runs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl http://backend
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 1 — Application asks DNS:&lt;/strong&gt; &lt;em&gt;"What is &lt;code&gt;backend&lt;/code&gt;?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2 — Pod's DNS configuration:&lt;/strong&gt; &lt;code&gt;/etc/resolv.conf&lt;/code&gt; points the query at the cluster's DNS server.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3 — CoreDNS resolves it:&lt;/strong&gt; CoreDNS knows &lt;code&gt;backend.default.svc.cluster.local&lt;/code&gt; maps to &lt;code&gt;10.96.120.50&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 4 — Application receives the IP:&lt;/strong&gt; &lt;code&gt;backend → 10.96.120.50&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 5 — Application sends traffic:&lt;/strong&gt; to &lt;code&gt;10.96.120.50:80&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 6 — Service dataplane takes over:&lt;/strong&gt; traffic gets forwarded to an appropriate backend Pod.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;10.96.120.50 → Pod 1 / Pod 2 / Pod 3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Putting the whole picture together:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌──────────────┐
│ Frontend Pod │
└──────┬───────┘
       │ "backend"
       ↓
┌──────────────┐
│   CoreDNS    │
└──────┬───────┘
       │ 10.96.120.50
       ↓
┌──────────────┐
│   Service    │
└──────┬───────┘
       │
   ┌───┼────┐
   ↓   ↓    ↓
 Pod1 Pod2 Pod3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The Mental Model to Memorize
&lt;/h2&gt;

&lt;p&gt;This entire article boils down to one chain:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Application
    | "backend"
    ↓
   DNS
    | "10.96.120.50"
    ↓
 Service
    | selects backend
    ↓
 EndpointSlice
    ↓
  Pod
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or even more compactly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;NAME → DNS → SERVICE IP → POD
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Interview Questions
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Q1. What is CoreDNS?&lt;/strong&gt;&lt;br&gt;
The DNS server commonly used inside Kubernetes clusters.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q2. Why do we need DNS in Kubernetes?&lt;/strong&gt;&lt;br&gt;
So applications can use stable, human-readable names instead of hardcoding IP addresses that can change.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q3. What is the standard DNS format for a Service?&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;&amp;lt;service&amp;gt;.&amp;lt;namespace&amp;gt;.svc.&amp;lt;cluster-domain&amp;gt;&lt;/code&gt; — for example, &lt;code&gt;backend.default.svc.cluster.local&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q4. What does a Service name usually resolve to?&lt;/strong&gt;&lt;br&gt;
For a normal ClusterIP Service, its virtual ClusterIP.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q5. Does DNS send traffic to the Pod?&lt;/strong&gt;&lt;br&gt;
No — DNS only resolves the name. The Service dataplane handles the actual traffic forwarding afterward.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q6. What is a headless Service?&lt;/strong&gt;&lt;br&gt;
A Service configured with &lt;code&gt;clusterIP: None&lt;/code&gt;. It skips the normal virtual ClusterIP and instead allows DNS-based discovery of individual Pod endpoints.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q7. Where can you check a Pod's DNS configuration?&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;kubectl exec &amp;lt;pod&amp;gt; -- cat /etc/resolv.conf&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q8. How do you test DNS resolution from inside a Pod?&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;kubectl exec -it &amp;lt;pod&amp;gt; -- nslookup backend&lt;/code&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Level 4 Checkpoint
&lt;/h2&gt;

&lt;p&gt;By now, you should be comfortable explaining this entire chain:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;backend
   ↓
CoreDNS
   ↓
10.96.120.50
   ↓
Service
   ↓
EndpointSlice
   ↓
Backend Pod
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And you should be able to clearly state the difference:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DNS     = "name → IP"
Service = "stable IP → backend Pods"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What's Next: Ingress and Gateway API
&lt;/h2&gt;

&lt;p&gt;In &lt;strong&gt;Level 5&lt;/strong&gt;, we'll tackle the next natural question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I have a Service inside Kubernetes. How does a user on the public internet reach my application using a domain like &lt;code&gt;app.example.com&lt;/code&gt;?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We'll cover Ingress, Ingress Controllers, the Gateway API, host/path-based routing, TLS termination, and the full traffic flow from &lt;strong&gt;Internet → Load Balancer → Ingress/Gateway → Service → Pod&lt;/strong&gt; — while still saving the low-level dataplane internals for Level 8.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Service Discovery is what makes Kubernetes applications feel effortless to configure: instead of chasing down ever-changing IP addresses, you just use a name like &lt;code&gt;backend&lt;/code&gt;, and CoreDNS quietly resolves it to a stable Service IP behind the scenes. Understanding that DNS and Service routing are two separate, sequential steps — name resolution first, traffic forwarding second — is the key to debugging connectivity issues quickly and confidently.&lt;/p&gt;

&lt;p&gt;The next time something doesn't connect, resist the urge to guess. Walk the layers: check the Service, check the EndpointSlice, check DNS with &lt;code&gt;nslookup&lt;/code&gt;, then check the Pod itself. That habit alone will save you hours of confused troubleshooting.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Enjoyed this article?&lt;/strong&gt; Follow along for Level 5, where we finally expose these Services to the outside world using Ingress and the Gateway API. Drop your questions in the comments, and share this with a teammate who's still typing raw ClusterIPs into their code. Let's keep building this Kubernetes networking roadmap together. 🚀&lt;/p&gt;

</description>
      <category>docker</category>
      <category>container</category>
      <category>kubernetes</category>
      <category>linux</category>
    </item>
    <item>
      <title>Kubernetes Networking [Level-3: Services]</title>
      <dc:creator>ADITYA RAJ</dc:creator>
      <pubDate>Sat, 15 Aug 2026 10:35:02 +0000</pubDate>
      <link>https://dev.to/iadiraj/kubernetes-networking-level-3-services-5h3</link>
      <guid>https://dev.to/iadiraj/kubernetes-networking-level-3-services-5h3</guid>
      <description>&lt;p&gt;This is &lt;strong&gt;Level 3&lt;/strong&gt; of our Kubernetes networking series. In Level 2, we traced how Pod-to-Pod communication actually works — and ended on a serious problem: &lt;strong&gt;Pod IPs are dynamic and temporary.&lt;/strong&gt; An application can't reliably hardcode a Pod IP if that Pod might be replaced at any moment.&lt;/p&gt;

&lt;p&gt;This article solves that exact problem by introducing one of the most important objects in Kubernetes: the &lt;strong&gt;Service&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;The Problem: Pod IPs Aren't Reliable&lt;/li&gt;
&lt;li&gt;The Solution: Service&lt;/li&gt;
&lt;li&gt;The Core Mental Model&lt;/li&gt;
&lt;li&gt;How a Service Finds Its Pods: Labels and Selectors&lt;/li&gt;
&lt;li&gt;A Minimal Service Example&lt;/li&gt;
&lt;li&gt;port vs targetPort&lt;/li&gt;
&lt;li&gt;What a Service Actually Gives You: ClusterIP&lt;/li&gt;
&lt;li&gt;Visualizing Service Selection&lt;/li&gt;
&lt;li&gt;A Service Does Not Create Pods&lt;/li&gt;
&lt;li&gt;Hands-On: Deploying Backend Pods&lt;/li&gt;
&lt;li&gt;Hands-On: Creating the Service&lt;/li&gt;
&lt;li&gt;Where Does the Traffic Actually Go?&lt;/li&gt;
&lt;li&gt;A Service Isn't a Normal Server&lt;/li&gt;
&lt;li&gt;EndpointSlices: Tracking Live Backends&lt;/li&gt;
&lt;li&gt;What Happens When a Pod Dies&lt;/li&gt;
&lt;li&gt;Kubernetes Service Types&lt;/li&gt;
&lt;li&gt;Service vs Pod vs Deployment&lt;/li&gt;
&lt;li&gt;Services Don't Mean DNS — Yet&lt;/li&gt;
&lt;li&gt;The Complete Picture So Far&lt;/li&gt;
&lt;li&gt;Hands-On Investigation&lt;/li&gt;
&lt;li&gt;How Does the ClusterIP Actually Work?&lt;/li&gt;
&lt;li&gt;Level 3 Checkpoint&lt;/li&gt;
&lt;li&gt;What's Next: Service Discovery and DNS&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  The Problem: Pod IPs Aren't Reliable
&lt;/h2&gt;

&lt;p&gt;Imagine three backend Pods:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;backend-pod-1&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;10.244.1.5&lt;/span&gt;
&lt;span class="na"&gt;backend-pod-2&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;10.244.2.8&lt;/span&gt;
&lt;span class="na"&gt;backend-pod-3&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;10.244.3.2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your frontend wants to call the backend, so it could just call &lt;code&gt;10.244.1.5:8080&lt;/code&gt; directly. But what happens when &lt;code&gt;backend-pod-1&lt;/code&gt; crashes? Kubernetes creates a replacement — say, &lt;code&gt;backend-pod-4&lt;/code&gt; at &lt;code&gt;10.244.4.9&lt;/code&gt; — and the old IP is simply gone.&lt;/p&gt;

&lt;p&gt;That means this is a fragile design:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Frontend → Pod IP
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We need something more stable than a raw Pod IP.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Solution: Service
&lt;/h2&gt;

&lt;p&gt;Kubernetes solves this with a &lt;strong&gt;Service&lt;/strong&gt; — think of it as a stable front door for a group of Pods.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                 Service
              10.96.0.10
                   |
        ┌──────────┼──────────┐
        ↓          ↓          ↓
      Pod 1      Pod 2      Pod 3
   10.244.1.5 10.244.2.8 10.244.3.2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The frontend never needs to know individual Pod IPs — it just talks to &lt;code&gt;10.96.0.10&lt;/code&gt;, and the Service takes care of routing traffic to an appropriate backend Pod.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Core Mental Model
&lt;/h2&gt;

&lt;p&gt;This is the single most important idea in this article:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Pod IP     → temporary
Service IP → stable
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pods can come and go freely. The Service gives applications a consistent, stable endpoint regardless of what's happening underneath.&lt;/p&gt;

&lt;h2&gt;
  
  
  How a Service Finds Its Pods: Labels and Selectors
&lt;/h2&gt;

&lt;p&gt;A Service doesn't magically know which Pods belong to it — it uses &lt;strong&gt;labels&lt;/strong&gt; and &lt;strong&gt;selectors&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Suppose your Pods are labeled:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;backend&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then your Service can declare:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;backend&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Which effectively means: &lt;em&gt;"Send traffic to any Pod labeled &lt;code&gt;app: backend&lt;/code&gt;."&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  A Minimal Service Example
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Service&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;backend&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;backend&lt;/span&gt;
  &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;
      &lt;span class="na"&gt;targetPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8080&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Don't worry about every field yet — focus on two things:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;backend&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;
&lt;span class="na"&gt;targetPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8080&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  port vs targetPort
&lt;/h2&gt;

&lt;p&gt;This distinction trips up a lot of beginners, so let's be precise.&lt;/p&gt;

&lt;p&gt;Suppose the Service listens on &lt;code&gt;port: 80&lt;/code&gt;, but the Pod's container actually listens on &lt;code&gt;8080&lt;/code&gt;. The flow looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Client
  |
  | :80
  ↓
Service
  |
  | :8080
  ↓
Pod
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In short:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;port&lt;/code&gt;&lt;/strong&gt; → the port exposed by the &lt;em&gt;Service&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;targetPort&lt;/code&gt;&lt;/strong&gt; → the port the traffic is forwarded to &lt;em&gt;on the Pod&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So this configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;
    &lt;span class="na"&gt;targetPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8080&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;means: &lt;em&gt;Service &lt;code&gt;:80&lt;/code&gt; forwards to Pod &lt;code&gt;:8080&lt;/code&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What a Service Actually Gives You: ClusterIP
&lt;/h2&gt;

&lt;p&gt;A standard Kubernetes Service is assigned a stable virtual IP called a &lt;strong&gt;ClusterIP&lt;/strong&gt;. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;Service&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;backend&lt;/span&gt;
&lt;span class="na"&gt;ClusterIP&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;10.96.0.10&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Frontend Pod
     |
     | 10.96.0.10:80
     ↓
  Service
     |
     ↓
Backend Pod
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Important nuance: the Service IP isn't a network interface living inside some specific Pod. It's a &lt;strong&gt;virtual IP&lt;/strong&gt; handled entirely by the Kubernetes networking dataplane — we'll unpack exactly how that works in Level 8.&lt;/p&gt;

&lt;h2&gt;
  
  
  Visualizing Service Selection
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                 Service
              backend:80
              10.96.0.10
                   |
           selector: app=backend
                   |
        ┌──────────┼──────────┐
        ↓          ↓          ↓
      Pod A      Pod B      Pod C
    app=backend app=backend app=backend
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Any Pod that doesn't match the selector is simply excluded:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                 Service
                    |
        ┌───────────┼───────────┐
        ↓           ↓           ↓
     backend      backend     backend
        ✓           ✓           ✓

     frontend
        ✗
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  A Service Does Not Create Pods
&lt;/h2&gt;

&lt;p&gt;This is a very common point of confusion. &lt;strong&gt;A Service never creates or manages Pods.&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Deployment → creates/manages Pods
Service    → provides stable networking to those Pods
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Put another way:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Deployment&lt;/strong&gt; says: &lt;em&gt;"I need 3 backend Pods running."&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Service&lt;/strong&gt; says: &lt;em&gt;"Give me a stable way to reach those backend Pods."&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They solve two entirely different problems and are designed to work together.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hands-On: Deploying Backend Pods
&lt;/h2&gt;

&lt;p&gt;For real, learnable infrastructure, a &lt;strong&gt;Deployment&lt;/strong&gt; is a much better way to create backend Pods than creating them manually:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deployment&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;backend&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;replicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;backend&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;backend&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx&lt;/span&gt;
          &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx&lt;/span&gt;
          &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;containerPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Apply it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; backend.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check the results:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get pods &lt;span class="nt"&gt;-o&lt;/span&gt; wide
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;NAME                       IP
backend-xxxxx-aaa          10.244.1.5
backend-xxxxx-bbb          10.244.2.7
backend-xxxxx-ccc          10.244.2.9
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your actual Pod names and IPs will differ — that's expected.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hands-On: Creating the Service
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Service&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;backend&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;backend&lt;/span&gt;
  &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;
      &lt;span class="na"&gt;targetPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Apply it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; backend-service.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get svc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;NAME      TYPE        CLUSTER-IP     PORT(S)
backend   ClusterIP   10.96.120.50   80/TCP
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That &lt;code&gt;10.96.120.50&lt;/code&gt; is your Service's ClusterIP.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where Does the Traffic Actually Go?
&lt;/h2&gt;

&lt;p&gt;Suppose the frontend sends a request to &lt;code&gt;10.96.120.50:80&lt;/code&gt;. The Service currently has three backend Pods:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;10.244.1.5:80
10.244.2.7:80
10.244.2.9:80
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Conceptually:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Frontend
   |
   | 10.96.120.50:80
   ↓
Service
   |
   ├────→ 10.244.1.5:80
   ├────→ 10.244.2.7:80
   └────→ 10.244.2.9:80
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Traffic gets distributed among the currently available backend endpoints. We'll cover the exact packet-processing mechanism (kube-proxy, iptables, IPVS, eBPF) in Level 8.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Service Isn't a Normal Server
&lt;/h2&gt;

&lt;p&gt;It's tempting to imagine &lt;code&gt;10.96.120.50&lt;/code&gt; as some machine sitting somewhere with its own network interface — but that's usually the wrong mental model. Think of it instead as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Service = stable virtual endpoint + rules for reaching backend Pods
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So &lt;code&gt;10.96.120.50&lt;/code&gt; is a &lt;strong&gt;virtual&lt;/strong&gt; Service IP, not a physical destination.&lt;/p&gt;

&lt;h2&gt;
  
  
  EndpointSlices: Tracking Live Backends
&lt;/h2&gt;

&lt;p&gt;If a Service selects Pod A, Pod B, and Pod C, Kubernetes needs a way to track the actual current backend endpoints. Modern Kubernetes does this using &lt;strong&gt;EndpointSlices&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Service
   ↓
EndpointSlice
   ├── Pod A IP
   ├── Pod B IP
   └── Pod C IP
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check them with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get endpointslices
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl describe endpointslice &amp;lt;name&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Service gives you a stable identity; the EndpointSlice reflects the current, real-time set of backend Pods.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Happens When a Pod Dies
&lt;/h2&gt;

&lt;p&gt;Suppose the Service currently has Pod A, Pod B, and Pod C as backends, and Pod B crashes. Kubernetes detects this and removes it from the available backends:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Before:
Service
 ├── A
 ├── B
 └── C

After:
Service
 ├── A
 └── C
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A replacement Pod (Pod D) may appear shortly after:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Service
 ├── A
 ├── C
 └── D
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Crucially, &lt;strong&gt;the frontend doesn't need to change anything&lt;/strong&gt; — it keeps using the Service name or ClusterIP (&lt;code&gt;backend&lt;/code&gt; / &lt;code&gt;10.96.120.50&lt;/code&gt;) the entire time. This self-healing stability is the whole point of the Service abstraction.&lt;/p&gt;

&lt;h2&gt;
  
  
  Kubernetes Service Types
&lt;/h2&gt;

&lt;p&gt;Kubernetes offers several Service types, each solving a different exposure problem.&lt;/p&gt;

&lt;h3&gt;
  
  
  ClusterIP
&lt;/h3&gt;

&lt;p&gt;The default type — provides a stable internal endpoint used for communication &lt;em&gt;within&lt;/em&gt; the cluster:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ClusterIP&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Pod A → Service → Pod B
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  NodePort
&lt;/h3&gt;

&lt;p&gt;Exposes the Service on a fixed port across every Node in the cluster:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;NodePort&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Client
   |
   ↓
Node IP :30080
   |
   ↓
Service
   |
   ↓
Pod
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For example, if a Node's IP is &lt;code&gt;192.168.1.10&lt;/code&gt; and the NodePort is &lt;code&gt;30080&lt;/code&gt;, you can reach the Service via &lt;code&gt;192.168.1.10:30080&lt;/code&gt;, and Kubernetes forwards that traffic to the backend Pods.&lt;/p&gt;

&lt;h3&gt;
  
  
  LoadBalancer
&lt;/h3&gt;

&lt;p&gt;Common in cloud environments, this type provisions an external load balancer that routes into your Service:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;LoadBalancer&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Internet
    |
    ↓
Public IP
    |
    ↓
Load Balancer
    |
    ↓
Service
    |
    ├──→ Pod
    ├──→ Pod
    └──→ Pod
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The exact provisioning mechanism depends on your cloud provider or Kubernetes environment.&lt;/p&gt;

&lt;h3&gt;
  
  
  ExternalName
&lt;/h3&gt;

&lt;p&gt;A special type that doesn't select Pods at all — instead, it provides a DNS alias pointing to an external hostname:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ExternalName&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Kubernetes Service name → external.example.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This one is less central to networking fundamentals, but useful to know exists.&lt;/p&gt;

&lt;h3&gt;
  
  
  Quick Reference
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Basic Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;ClusterIP&lt;/td&gt;
&lt;td&gt;Internal stable endpoint&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NodePort&lt;/td&gt;
&lt;td&gt;Expose through a Node port&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;LoadBalancer&lt;/td&gt;
&lt;td&gt;External/cloud load balancer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ExternalName&lt;/td&gt;
&lt;td&gt;DNS alias to an external service&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;For now, focus most of your attention on &lt;strong&gt;ClusterIP&lt;/strong&gt; — everything else builds on the same underlying concept.&lt;/p&gt;

&lt;h2&gt;
  
  
  Service vs Pod vs Deployment
&lt;/h2&gt;

&lt;p&gt;Two classic interview questions, answered cleanly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Service vs Pod:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Pod     → runs the application, has a Pod IP
Service → stable networking endpoint, selects backend Pods
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In short: &lt;code&gt;Pod = workload&lt;/code&gt;, &lt;code&gt;Service = networking abstraction&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Service vs Deployment:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Deployment → manages the desired number of Pods
Service    → provides stable access to those Pods
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Deployment
    |
    ├── Pod A
    ├── Pod B
    └── Pod C
          ↑
          |
       Service
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Services Don't Mean DNS — Yet
&lt;/h2&gt;

&lt;p&gt;You might be wondering: &lt;em&gt;"If I have a Service called &lt;code&gt;backend&lt;/code&gt;, can I just use the name &lt;code&gt;backend&lt;/code&gt; instead of its IP?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Yes — eventually. But that's a separate mechanism (DNS), covered in the next article. At this level, focus purely on:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Service → stable virtual endpoint
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In Level 4, we'll add the missing piece:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Service name → DNS → Service IP
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Don't conflate the two just yet — understanding them separately will make DNS click much faster later.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Complete Picture So Far
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                    Kubernetes Cluster

        ┌─────────────────────────────────┐
        │          Service                │
        │       10.96.120.50:80           │
        │              │                  │
        │       ┌──────┼──────┐           │
        │       ↓      ↓      ↓           │
        │     Pod A  Pod B  Pod C         │
        │      │       │       │          │
        │   10.244.x 10.244.x 10.244.x    │
        └─────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The application talks to the &lt;strong&gt;Service&lt;/strong&gt;, never directly to individually changing Pod IPs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hands-On Investigation
&lt;/h2&gt;

&lt;p&gt;Try tracing the full chain yourself:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get pods &lt;span class="nt"&gt;-o&lt;/span&gt; wide
kubectl get svc
kubectl describe svc backend
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Look specifically for the &lt;code&gt;Selector:&lt;/code&gt; field in the output — e.g., &lt;code&gt;Selector: app=backend&lt;/code&gt;. Then check:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get endpointslices
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You're now able to see the entire chain in action:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Service → Selector → EndpointSlice → Pod IPs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  How Does the ClusterIP Actually Work?
&lt;/h2&gt;

&lt;p&gt;At this point you might reasonably ask: &lt;em&gt;"Okay, but HOW does &lt;code&gt;10.96.120.50&lt;/code&gt; actually become &lt;code&gt;10.244.1.5&lt;/code&gt;?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Great question — and the answer is that something running on every Kubernetes Node has to implement that traffic forwarding and load-balancing behavior. Historically, this has been the job of &lt;strong&gt;kube-proxy&lt;/strong&gt;, using mechanisms like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;iptables&lt;/li&gt;
&lt;li&gt;IPVS&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Modern clusters can also implement this using &lt;strong&gt;eBPF&lt;/strong&gt;. We're deliberately not diving into these internals yet — that's reserved for &lt;strong&gt;Level 8&lt;/strong&gt;. For now, just remember the abstraction:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Service IP → Service dataplane → Backend Pod
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Level 3 Checkpoint
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Why do we need a Service?&lt;/strong&gt;&lt;br&gt;
→ Because Pod IPs are dynamic and temporary.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. What does a Service provide?&lt;/strong&gt;&lt;br&gt;
→ A stable virtual endpoint/IP for accessing a group of Pods.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. How does a Service find its Pods?&lt;/strong&gt;&lt;br&gt;
→ Using a selector, typically based on labels.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. What is a ClusterIP?&lt;/strong&gt;&lt;br&gt;
→ The stable virtual IP of a Service, normally used for internal cluster access.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. What is &lt;code&gt;port&lt;/code&gt;?&lt;/strong&gt;&lt;br&gt;
→ The port exposed by the Service itself.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6. What is &lt;code&gt;targetPort&lt;/code&gt;?&lt;/strong&gt;&lt;br&gt;
→ The port on the backend Pod/container that actually receives the traffic.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;7. Does a Service create Pods?&lt;/strong&gt;&lt;br&gt;
→ No. A Deployment manages Pods; a Service provides networking to them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;8. What tracks the current backend endpoints?&lt;/strong&gt;&lt;br&gt;
→ EndpointSlices.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;9. Does Pod-to-Pod communication require a Service?&lt;/strong&gt;&lt;br&gt;
→ No — Pods can always communicate directly via Pod IPs. A Service is useful when you don't want to depend on individual, changing Pod IPs.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Next: Service Discovery and DNS
&lt;/h2&gt;

&lt;p&gt;In &lt;strong&gt;Level 4&lt;/strong&gt;, we'll answer the natural follow-up question this article left open:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;How does &lt;code&gt;backend:80&lt;/code&gt; magically turn into a Service IP like &lt;code&gt;10.96.120.50&lt;/code&gt;?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We'll cover CoreDNS, DNS records, Service names, namespaces, FQDNs, and Pod DNS — without jumping ahead into the Level 8 dataplane internals.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Services are the answer to one of the most fundamental problems in Kubernetes: Pods are ephemeral, but applications need something stable to talk to. By giving a group of Pods a single, unchanging virtual IP — and continuously tracking the live backend set via EndpointSlices — Kubernetes lets you scale, crash, and replace Pods freely without ever breaking the applications that depend on them.&lt;/p&gt;

&lt;p&gt;The mental model to hold onto: &lt;strong&gt;Pods are workloads with temporary IPs; Services are stable networking abstractions in front of them.&lt;/strong&gt; Everything else — ClusterIP, NodePort, LoadBalancer, selectors — is just a variation on that one idea.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Found this helpful?&lt;/strong&gt; Follow along for Level 4, where we connect Service names to DNS and finally explain how &lt;code&gt;backend&lt;/code&gt; resolves into a real IP address. Drop your questions below, and share this with a teammate who still isn't sure why Services and Deployments are two separate objects. Let's keep building this Kubernetes networking roadmap together. 🚀&lt;/p&gt;

</description>
      <category>docker</category>
      <category>kubernetes</category>
      <category>linux</category>
      <category>containers</category>
    </item>
    <item>
      <title>Kubernetes Networking [Level-2: Pod-to-Pod Communication]</title>
      <dc:creator>ADITYA RAJ</dc:creator>
      <pubDate>Sat, 15 Aug 2026 10:20:11 +0000</pubDate>
      <link>https://dev.to/iadiraj/kubernetes-networking-level-2-pod-to-pod-communication-3fkh</link>
      <guid>https://dev.to/iadiraj/kubernetes-networking-level-2-pod-to-pod-communication-3fkh</guid>
      <description>&lt;p&gt;This is &lt;strong&gt;Level 2&lt;/strong&gt; of our Kubernetes networking series. In Level 0, we covered core Linux networking primitives, and in Level 1, we learned how a Pod gets its own network namespace, &lt;code&gt;eth0&lt;/code&gt; interface, and IP address.&lt;/p&gt;

&lt;p&gt;Now it's time to answer one of the most important questions in Kubernetes networking:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;How does Pod A actually communicate with Pod B?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We'll start with the simplest possible case and work our way up to a full hop-by-hop trace of cross-node Pod traffic — including routing, overlay networking, VXLAN, and BGP.&lt;/p&gt;

&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Our Scenario&lt;/li&gt;
&lt;li&gt;The Kubernetes Networking Expectation&lt;/li&gt;
&lt;li&gt;First Case: Same-Node Communication&lt;/li&gt;
&lt;li&gt;How Pod A Knows Where to Send the Packet&lt;/li&gt;
&lt;li&gt;Crossing the Node Boundary&lt;/li&gt;
&lt;li&gt;The Node Routing Table&lt;/li&gt;
&lt;li&gt;Who Creates These Routes?&lt;/li&gt;
&lt;li&gt;Two Major Approaches: Routing vs Overlay&lt;/li&gt;
&lt;li&gt;Overlay Networking: A Simple Analogy&lt;/li&gt;
&lt;li&gt;Why We Need Encapsulation&lt;/li&gt;
&lt;li&gt;VXLAN in a Nutshell&lt;/li&gt;
&lt;li&gt;Routing Without an Overlay&lt;/li&gt;
&lt;li&gt;Why BGP Shows Up Here&lt;/li&gt;
&lt;li&gt;The Complete Cross-Node Packet Journey&lt;/li&gt;
&lt;li&gt;Pod IP vs Node IP&lt;/li&gt;
&lt;li&gt;Why You Can't Just Use Pod IPs on the Internet&lt;/li&gt;
&lt;li&gt;Kubernetes Doesn't Mandate an Overlay&lt;/li&gt;
&lt;li&gt;Same-Node vs Cross-Node: A Quick Reference&lt;/li&gt;
&lt;li&gt;The Big Problem We've Just Created&lt;/li&gt;
&lt;li&gt;What's Next: Kubernetes Services&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Our Scenario
&lt;/h2&gt;

&lt;p&gt;Let's set up a concrete example. We have two Pods:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Pod A
IP: 10.244.1.5
Node: node-1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Pod B
IP: 10.244.2.5
Node: node-2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Visually:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;              Kubernetes Cluster

   Node 1                              Node 2
┌───────────────┐                  ┌───────────────┐
│ Pod A         │                  │ Pod B         │
│ 10.244.1.5    │                  │ 10.244.2.5    │
└───────┬───────┘                  └───────▲───────┘
        │                                  │
        └──────────── Network ─────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pod A wants to send traffic to Pod B: &lt;code&gt;10.244.1.5 → 10.244.2.5&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Kubernetes Networking Expectation
&lt;/h2&gt;

&lt;p&gt;Kubernetes enforces an important networking model:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Every Pod should be able to communicate with every other Pod, without anyone needing to manually manage routes for each Pod.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Ideally, from the application's point of view:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Pod A (10.244.1.5) → HTTP → Pod B (10.244.2.5)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The application shouldn't need to know:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Is Pod B on Node 1 or Node 2?&lt;/li&gt;
&lt;li&gt;Is the traffic going over VXLAN?&lt;/li&gt;
&lt;li&gt;Is it using BGP?&lt;/li&gt;
&lt;li&gt;Is it using eBPF?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All of that complexity belongs to the networking layer, not the application.&lt;/p&gt;

&lt;h2&gt;
  
  
  First Case: Same-Node Communication
&lt;/h2&gt;

&lt;p&gt;Let's start with the easier scenario: both Pods live on the same Node.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Node 1
Pod A: 10.244.1.5
Pod B: 10.244.1.6
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Conceptually, traffic flows like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Pod A
  ↓
eth0
  ↓
veth
  ↓
Node networking
  ↓
veth
  ↓
eth0
  ↓
Pod B
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The exact implementation depends on the CNI plugin, but the core idea holds:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Pod A → Node networking → Pod B
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  How Pod A Knows Where to Send the Packet
&lt;/h2&gt;

&lt;p&gt;Remember &lt;code&gt;ip route&lt;/code&gt; from Level 0? Every Pod has its own routing table. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;default via 10.244.1.1 dev eth0
10.244.1.0/24 dev eth0
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When Pod A wants to reach &lt;code&gt;10.244.1.6&lt;/code&gt;, Linux checks: &lt;em&gt;do I have a route for this?&lt;/em&gt; Yes — it falls within &lt;code&gt;10.244.1.0/24&lt;/code&gt;. So Linux sends the packet out through &lt;code&gt;eth0&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Crossing the Node Boundary
&lt;/h2&gt;

&lt;p&gt;Now the interesting case: Pod A and Pod B are on &lt;strong&gt;different&lt;/strong&gt; Nodes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Pod A (10.244.1.5) on Node 1
              ↓
Pod B (10.244.2.5) on Node 2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pod A sends a packet with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Source:      10.244.1.5
Destination: 10.244.2.5
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The packet leaves the Pod through &lt;code&gt;eth0&lt;/code&gt;, crosses the veth pair, and lands on Node 1's networking stack. Now Node 1 has to answer a critical question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Where is 10.244.2.5?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The Node Routing Table
&lt;/h2&gt;

&lt;p&gt;Node 1 needs to know how to reach the Pod network living on Node 2. Conceptually, it might have a routing table like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;10.244.1.0/24 → local
10.244.2.0/24 → Node 2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In plain terms:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;10.244.1.x → my local Pods
10.244.2.x → Pods on Node 2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So the flow becomes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Pod A → Node 1 → Route → Node 2 → Pod B
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the fundamental shape of all cross-node Pod traffic in Kubernetes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who Creates These Routes?
&lt;/h2&gt;

&lt;p&gt;This is exactly where the &lt;strong&gt;CNI implementation&lt;/strong&gt; becomes important. Different networking plugins solve this problem differently, using mechanisms such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Routing&lt;/li&gt;
&lt;li&gt;Overlay networking&lt;/li&gt;
&lt;li&gt;VXLAN&lt;/li&gt;
&lt;li&gt;Geneve&lt;/li&gt;
&lt;li&gt;BGP&lt;/li&gt;
&lt;li&gt;Cloud-native routing&lt;/li&gt;
&lt;li&gt;eBPF&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We'll dig into specific CNI implementations properly in Level 7. For now, just remember: &lt;strong&gt;CNI's job is to make sure the network knows how to reach every Pod IP.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Two Major Approaches: Routing vs Overlay
&lt;/h2&gt;

&lt;p&gt;There are two broad strategies Kubernetes networking implementations use to make cross-node Pod traffic work.&lt;/p&gt;

&lt;h3&gt;
  
  
  Approach 1 — Routing
&lt;/h3&gt;

&lt;p&gt;The underlying physical (or cloud) network is taught how to reach each Pod network directly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Pod A → Node 1 → Router → Node 2 → Pod B
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Approach 2 — Overlay
&lt;/h3&gt;

&lt;p&gt;The Pod's packet gets &lt;strong&gt;encapsulated&lt;/strong&gt; inside another packet addressed between Nodes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Original packet:
10.244.1.5 → 10.244.2.5

        ↓ encapsulation

Outer packet:
Node1-IP → Node2-IP
    |
    | carries
    ↓
10.244.1.5 → 10.244.2.5
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We'll explore both approaches in more depth below.&lt;/p&gt;

&lt;h2&gt;
  
  
  Overlay Networking: A Simple Analogy
&lt;/h2&gt;

&lt;p&gt;Imagine sending a letter between two buildings, but the postal system only understands building addresses — not individual recipients. So you put your letter (addressed to a specific person) inside an outer envelope addressed to the building itself:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Outer envelope: Node 1 → Node 2
Inside:         Pod A → Pod B
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's essentially what packet encapsulation does:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Outer packet
┌──────────────────────────────┐
│ Node 1 → Node 2              │
│                              │
│   Inner packet               │
│   Pod A → Pod B              │
└──────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Why We Need Encapsulation
&lt;/h2&gt;

&lt;p&gt;Suppose the physical network only knows about Node IPs, like &lt;code&gt;192.168.1.10&lt;/code&gt; and &lt;code&gt;192.168.1.20&lt;/code&gt; — it has no idea what &lt;code&gt;10.244.1.5&lt;/code&gt; or &lt;code&gt;10.244.2.5&lt;/code&gt; even are. The physical network understands &lt;em&gt;Nodes&lt;/em&gt;, not &lt;em&gt;Pods&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;So the trick is to communicate at the level the network &lt;em&gt;does&lt;/em&gt; understand (Node to Node), while carrying the Pod-level conversation inside:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Node 1 (192.168.1.10) → Node 2 (192.168.1.20)
       carries
Pod A (10.244.1.5) → Pod B (10.244.2.5)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  VXLAN in a Nutshell
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;VXLAN&lt;/strong&gt; is one of the most common technologies used to implement overlay networking. You don't need to master every detail yet — just the high-level flow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Pod packet (10.244.1.5 → 10.244.2.5)
       ↓
VXLAN encapsulation
       ↓
Node 1 → Node 2
       ↓
VXLAN decapsulation
       ↓
Pod B
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or more generally:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Pod → Overlay → Node → Network → Node → Overlay → Pod
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Routing Without an Overlay
&lt;/h2&gt;

&lt;p&gt;An alternative approach is to make the underlying network itself understand Pod networks directly — no encapsulation required.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Node 1 — Pod CIDR: 10.244.1.0/24
Node 2 — Pod CIDR: 10.244.2.0/24
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the network knows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;10.244.1.0/24 → Node 1
10.244.2.0/24 → Node 2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;...then traffic can be routed directly, with no wrapping/unwrapping step:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Pod A → Node 1 → Router → Node 2 → Pod B
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Why BGP Shows Up Here
&lt;/h2&gt;

&lt;p&gt;You'll eventually run into &lt;strong&gt;BGP (Border Gateway Protocol)&lt;/strong&gt; in Kubernetes networking discussions — don't let the name intimidate you. At a high level, BGP is simply a protocol for &lt;strong&gt;distributing routes&lt;/strong&gt; across the network.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Node 1 announces: "10.244.1.0/24 is reachable through me"
Node 2 announces: "10.244.2.0/24 is reachable through me"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once these routes propagate, the network can route Pod traffic directly — no overlay needed. Some CNI implementations use BGP specifically for this purpose.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Complete Cross-Node Packet Journey
&lt;/h2&gt;

&lt;p&gt;Let's trace a full request from Pod A (&lt;code&gt;10.244.1.5&lt;/code&gt;) to Pod B (&lt;code&gt;10.244.2.5&lt;/code&gt;) step by step.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1 — Application:&lt;/strong&gt; Pod A's application sends &lt;code&gt;GET /api&lt;/code&gt; to &lt;code&gt;10.244.2.5:8080&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2 — Pod network namespace:&lt;/strong&gt; Linux sees source &lt;code&gt;10.244.1.5&lt;/code&gt;, destination &lt;code&gt;10.244.2.5&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3 — Pod eth0:&lt;/strong&gt; The packet leaves the Pod via &lt;code&gt;eth0&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 4 — veth:&lt;/strong&gt; The packet crosses the veth pair from the Pod namespace into the Node namespace.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 5 — Node routing:&lt;/strong&gt; Node 1 asks &lt;em&gt;"where is 10.244.2.5?"&lt;/em&gt; and finds that &lt;code&gt;10.244.2.0/24 → Node 2&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 6 — Cross-node network:&lt;/strong&gt; Depending on the CNI implementation, this hop uses routing, an overlay, eBPF, or cloud-native networking.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 7 — Node 2:&lt;/strong&gt; The packet arrives and Node 2 determines that &lt;code&gt;10.244.2.5&lt;/code&gt; belongs to Pod B.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 8 — Pod B:&lt;/strong&gt; The packet travels &lt;code&gt;Node 2 → veth → Pod B network namespace → eth0 → application&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Putting it all together:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Pod A (10.244.1.5)
   ↓
eth0 → veth → Node 1
   ↓
Routing / Overlay / eBPF
   ↓
Node 2 → veth → eth0
   ↓
Pod B (10.244.2.5)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Pod IP vs Node IP
&lt;/h2&gt;

&lt;p&gt;This distinction trips up a lot of people, so let's be explicit. Suppose:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Node 1: 192.168.1.10 → Pod A: 10.244.1.5
Node 2: 192.168.1.20 → Pod B: 10.244.2.5
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These live in two entirely separate networks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Node network: 192.168.1.0/24
Pod network:  10.244.0.0/16
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;A Pod's IP is not the same as, or derived from, its Node's IP.&lt;/strong&gt; Keep this mental separation clear — it will save you a lot of confusion later.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why You Can't Just Use Pod IPs on the Internet
&lt;/h2&gt;

&lt;p&gt;A private Pod IP like &lt;code&gt;10.244.1.5&lt;/code&gt; isn't reachable directly from the public internet. Instead, traffic typically flows like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Internet
   ↓
Load Balancer / Ingress
   ↓
Kubernetes
   ↓
Service
   ↓
Pod
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is precisely why Kubernetes has dedicated abstractions — &lt;strong&gt;Services&lt;/strong&gt;, &lt;strong&gt;Ingress&lt;/strong&gt;, and &lt;strong&gt;Gateway API&lt;/strong&gt; — which we'll cover soon.&lt;/p&gt;

&lt;h2&gt;
  
  
  Kubernetes Doesn't Mandate an Overlay
&lt;/h2&gt;

&lt;p&gt;Here's an important point, especially if you're prepping for interviews: it's a common misconception that &lt;em&gt;"Kubernetes networking uses an overlay network."&lt;/em&gt; &lt;strong&gt;That's not universally true.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Kubernetes defines a &lt;em&gt;networking model&lt;/em&gt; (every Pod can reach every other Pod by IP), but it doesn't dictate &lt;em&gt;how&lt;/em&gt; that model is implemented:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Kubernetes networking model
           |
     ┌─────┼─────┐
     ↓     ↓     ↓
 Routing Overlay eBPF
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The specific CNI plugin you choose determines the actual implementation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Same-Node vs Cross-Node: A Quick Reference
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Traffic&lt;/th&gt;
&lt;th&gt;What Happens Conceptually&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Pod → Pod, same Node&lt;/td&gt;
&lt;td&gt;Node-local networking&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pod → Pod, different Nodes&lt;/td&gt;
&lt;td&gt;Cross-node routing/overlay/dataplane&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pod → Internet&lt;/td&gt;
&lt;td&gt;Node/network egress path&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Internet → Pod&lt;/td&gt;
&lt;td&gt;Usually LoadBalancer/Ingress/Gateway + Service&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pod → Service&lt;/td&gt;
&lt;td&gt;Service dataplane selects a backend Pod&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;That last row is exactly the problem we tackle next.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Big Problem We've Just Created
&lt;/h2&gt;

&lt;p&gt;So far, &lt;code&gt;Pod A → Pod B&lt;/code&gt; works fine. But there's a serious practical problem lurking here.&lt;/p&gt;

&lt;p&gt;Suppose we have three backend Pods:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Backend Pod 1: 10.244.1.5
Backend Pod 2: 10.244.2.5
Backend Pod 3: 10.244.3.5
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The frontend needs to call the backend — but &lt;strong&gt;which IP should it use?&lt;/strong&gt; And what happens when Backend Pod 1 dies and Kubernetes replaces it with a brand-new Pod at a brand-new IP, say &lt;code&gt;10.244.4.8&lt;/code&gt;?&lt;/p&gt;

&lt;p&gt;We clearly don't want applications hardcoding or tracking individual Pod IPs.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Problem
&lt;/h3&gt;

&lt;p&gt;Pod IPs are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Dynamic&lt;/li&gt;
&lt;li&gt;Temporary&lt;/li&gt;
&lt;li&gt;Tied to individual Pod lifecycles&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Applications shouldn't have to manage any of that.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Solution
&lt;/h3&gt;

&lt;p&gt;A &lt;strong&gt;Kubernetes Service&lt;/strong&gt; — a stable abstraction sitting in front of a changing set of Pods:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Frontend
   ↓
Service
   ├──→ Pod 1
   ├──→ Pod 2
   └──→ Pod 3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What's Next: Kubernetes Services
&lt;/h2&gt;

&lt;p&gt;In &lt;strong&gt;Level 3&lt;/strong&gt;, we'll build up Services from first principles, starting with the exact question this article ends on:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Why can't I simply use a Pod IP?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;From there, we'll progressively cover:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;What is a Service?
       ↓
ClusterIP
       ↓
Selectors
       ↓
Endpoints / EndpointSlices
       ↓
How Service traffic actually reaches Pods
       ↓
Service types: NodePort, LoadBalancer, ExternalName
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We'll then trace a complete request:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Frontend Pod → Service IP → Kubernetes dataplane → Backend Pod
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's where components like &lt;code&gt;kube-proxy&lt;/code&gt;, iptables, IPVS, and eBPF will finally start making sense — though we'll save their deep internals for Level 8, right on schedule with the rest of this roadmap.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Pod-to-Pod communication is the connective tissue of Kubernetes networking. Same-node traffic is fairly straightforward — it stays within the Node's networking stack via veth pairs. Cross-node traffic is where things get interesting: the network needs a way to route or encapsulate Pod IPs that it may not natively understand, whether through direct routing, VXLAN-based overlays, or BGP-distributed routes.&lt;/p&gt;

&lt;p&gt;The most important takeaway is this: Kubernetes defines &lt;em&gt;what&lt;/em&gt; should happen (any Pod can reach any other Pod by IP), not &lt;em&gt;how&lt;/em&gt; — that's the CNI plugin's job. And because Pod IPs are inherently unstable, we need a better abstraction for talking to a group of Pods reliably. That abstraction is the &lt;strong&gt;Service&lt;/strong&gt;, and it's exactly where we're headed next.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Enjoyed this deep dive?&lt;/strong&gt; Follow along for Level 3, where we build Kubernetes Services from the ground up and trace a real request from a frontend Pod all the way to a backend Pod. Drop your questions in the comments, and share this with a teammate still wondering why their Pod IP keeps changing. Let's keep demystifying Kubernetes networking together. 🚀&lt;/p&gt;

</description>
      <category>docker</category>
      <category>linux</category>
      <category>kubernetes</category>
      <category>networking</category>
    </item>
    <item>
      <title>Kubernetes Networking [Level-1: Pod Networking]</title>
      <dc:creator>ADITYA RAJ</dc:creator>
      <pubDate>Sat, 15 Aug 2026 06:30:00 +0000</pubDate>
      <link>https://dev.to/iadiraj/kubernetes-networking-level-1-pod-networking-3agp</link>
      <guid>https://dev.to/iadiraj/kubernetes-networking-level-1-pod-networking-3agp</guid>
      <description>&lt;p&gt;This is &lt;strong&gt;Level 1&lt;/strong&gt; of our Kubernetes networking series. In Level 0, we built a foundation of core Linux networking concepts — IP addresses, ports, network namespaces, veth pairs, and bridges. Now it's time to connect that foundation directly to Kubernetes.&lt;/p&gt;

&lt;p&gt;The central question for this article is deceptively simple:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;When Kubernetes creates a Pod, how does that Pod actually get a network interface and an IP address?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;By the end of this guide, you'll be able to trace the full journey — from &lt;code&gt;kubectl run&lt;/code&gt; to a running Pod with a working &lt;code&gt;eth0&lt;/code&gt; — and understand exactly which component is responsible for each step.&lt;/p&gt;

&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;The Problem Kubernetes Has&lt;/li&gt;
&lt;li&gt;The Solution: CNI&lt;/li&gt;
&lt;li&gt;Every Pod Gets Its Own Network Namespace&lt;/li&gt;
&lt;li&gt;Inspecting the Pod's eth0&lt;/li&gt;
&lt;li&gt;Where Does eth0 Connect? The veth Pair&lt;/li&gt;
&lt;li&gt;Why We Need the veth Pair&lt;/li&gt;
&lt;li&gt;Multiple Pods on One Node&lt;/li&gt;
&lt;li&gt;Where Does the Pod IP Come From?&lt;/li&gt;
&lt;li&gt;Understanding Pod CIDR&lt;/li&gt;
&lt;li&gt;Node CIDR vs Pod CIDR&lt;/li&gt;
&lt;li&gt;The Complete Pod Networking Stack&lt;/li&gt;
&lt;li&gt;What Happens When a Pod Is Created&lt;/li&gt;
&lt;li&gt;The Pause Container: Kubernetes' Hidden Detail&lt;/li&gt;
&lt;li&gt;Multiple Containers, One Network Namespace&lt;/li&gt;
&lt;li&gt;Port Collisions Inside a Pod&lt;/li&gt;
&lt;li&gt;Pod-to-Pod Communication (Same Node)&lt;/li&gt;
&lt;li&gt;Pods on Different Nodes&lt;/li&gt;
&lt;li&gt;The Kubernetes Networking Model&lt;/li&gt;
&lt;li&gt;What CNI Actually Does: A Preview&lt;/li&gt;
&lt;li&gt;Hands-On: Inspecting a Real Pod&lt;/li&gt;
&lt;li&gt;Level 1 Mental Model&lt;/li&gt;
&lt;li&gt;Level 1 Checkpoint&lt;/li&gt;
&lt;li&gt;What's Next: Pod-to-Pod Communication&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  The Problem Kubernetes Has
&lt;/h2&gt;

&lt;p&gt;Picture a bare Kubernetes Node with no Pods running yet:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Node
┌─────────────────────────────────────┐
│        Kubernetes Node              │
│              ???                    │
└─────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now Kubernetes wants to run a Pod:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Pod
┌─────────────────┐
│ nginx           │
│ eth0            │
│ 10.244.1.5      │
└─────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here's the catch: &lt;strong&gt;who creates &lt;code&gt;eth0&lt;/code&gt;?&lt;/strong&gt; Who assigns the Pod its IP, &lt;code&gt;10.244.1.5&lt;/code&gt;? And who connects that interface to the Node's network?&lt;/p&gt;

&lt;p&gt;Linux doesn't do any of this automatically just because Kubernetes decided to create a Pod. We need a dedicated networking component to make it happen.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Solution: CNI
&lt;/h2&gt;

&lt;p&gt;This is where the &lt;strong&gt;Container Network Interface (CNI)&lt;/strong&gt; comes in. Think of CNI as:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The component responsible for connecting a newly created Pod to the network.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Simplified, the flow looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Kubernetes
    | "I created a Pod."
    ↓
Container Runtime
    | "Pod needs networking."
    ↓
CNI
    ├── Create network namespace
    ├── Create veth pair
    ├── Put one side inside the Pod
    ├── Connect the other side to the Node
    ├── Assign an IP
    └── Configure routes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We'll go much deeper into CNI implementations later in this series (Level 7). For now, just remember its role: &lt;strong&gt;CNI is what gives Pods networking.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Every Pod Gets Its Own Network Namespace
&lt;/h2&gt;

&lt;p&gt;Remember network namespaces from Level 0? A Kubernetes Pod gets its own network namespace, giving it an isolated networking environment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Node
┌─────────────────────────────────────────┐
│   Pod Network Namespace                 │
│   ┌───────────────────────────────┐     │
│   │   eth0                        │     │
│   │   10.244.1.5                  │     │
│   └───────────────────────────────┘     │
└─────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This isolation is exactly what allows dozens of Pods to run on the same Node without their networking colliding.&lt;/p&gt;

&lt;h2&gt;
  
  
  Inspecting the Pod's eth0
&lt;/h2&gt;

&lt;p&gt;Inside a running Pod, running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ip addr
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;typically shows something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1: lo
2: eth0@if123
    inet 10.244.1.5/24
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The important takeaway: the Pod has its own network interface (&lt;code&gt;eth0&lt;/code&gt;) and its own IP address (&lt;code&gt;10.244.1.5&lt;/code&gt;).&lt;/p&gt;

&lt;h2&gt;
  
  
  Where Does eth0 Connect? The veth Pair
&lt;/h2&gt;

&lt;p&gt;This is where our Level 0 knowledge pays off. A Pod's &lt;code&gt;eth0&lt;/code&gt; is typically connected to the Node using a &lt;strong&gt;veth pair&lt;/strong&gt; — the same mechanism we covered earlier.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                 Kubernetes Node
┌─────────────────────────────────────────────┐
│  Pod namespace                              │
│  ┌────────────────────┐                     │
│  │ eth0               │                     │
│  │ 10.244.1.5         │                     │
│  └─────────┬──────────┘                     │
│            │                                │
│          veth                               │
│            ║                                │
│          veth                               │
│            │                                │
│            ↓                                │
│       Node network                          │
└─────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Think of it as a virtual cable: one end (&lt;code&gt;eth0&lt;/code&gt;) lives inside the Pod, and the other end (&lt;code&gt;veth&lt;/code&gt;) lives on the Node.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why We Need the veth Pair
&lt;/h2&gt;

&lt;p&gt;The Pod is isolated inside its own network namespace, which means it has no natural connection to the Node's namespace:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Pod namespace
     |
     | ???
     |
Node namespace
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The veth pair bridges that gap:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Pod namespace
     |
   eth0
     |
   veth
     ║
   veth
     |
Node namespace
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In short, the veth pair is the virtual cable that connects an isolated Pod to the rest of the Node's networking stack.&lt;/p&gt;

&lt;h2&gt;
  
  
  Multiple Pods on One Node
&lt;/h2&gt;

&lt;p&gt;Now imagine three Pods running on the same Node:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Pod A → 10.244.1.5
Pod B → 10.244.1.6
Pod C → 10.244.1.7
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Conceptually, the Node might look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                    Node
┌────────────────────────────────────────────┐
│ Pod A (10.244.1.5)                         │
│    │                                       │
│   veth ───────────┐                        │
│                    ↓                       │
│                 Bridge                     │
│                    ↑                       │
│   veth ───────────┘                        │
│    │                                       │
│ Pod B (10.244.1.6)                         │
│                                            │
│ Pod C (10.244.1.7)                         │
└────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The exact implementation varies by CNI plugin, but the mental model stays consistent:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Pod → eth0 → veth → Node networking
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Where Does the Pod IP Come From?
&lt;/h2&gt;

&lt;p&gt;Who decided Pod A should get &lt;code&gt;10.244.1.5&lt;/code&gt;? The networking implementation allocates IPs from a defined address range.&lt;/p&gt;

&lt;p&gt;For example, a cluster might use a Pod CIDR of &lt;code&gt;10.244.0.0/16&lt;/code&gt;, split into smaller ranges per Node:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Node 1: 10.244.1.0/24
Node 2: 10.244.2.0/24
Node 3: 10.244.3.0/24
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So on Node 1:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Pod A → 10.244.1.5
Pod B → 10.244.1.6
Pod C → 10.244.1.7
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is just one example architecture — different CNIs and cluster configurations allocate ranges differently, so don't memorize these exact numbers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding Pod CIDR
&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;Pod CIDR&lt;/strong&gt; is the IP address range allocated for all Pods in the cluster. For example, &lt;code&gt;10.244.0.0/16&lt;/code&gt; represents a large address space reserved specifically for Pod IPs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Cluster
└── Pod Network
       ├── 10.244.1.x
       ├── 10.244.2.x
       ├── 10.244.3.x
       └── ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Again, actual ranges vary by cluster and CNI plugin — what matters is understanding the concept.&lt;/p&gt;

&lt;h2&gt;
  
  
  Node CIDR vs Pod CIDR
&lt;/h2&gt;

&lt;p&gt;This distinction trips up a lot of beginners. Consider:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Node IP: 192.168.1.10
Pod IP:  10.244.1.5
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These belong to &lt;strong&gt;entirely different networks&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Node Network: 192.168.1.0/24
       ↓
Pod Network:  10.244.0.0/16
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Don't assume a Pod's IP belongs to the same subnet as its Node's IP — in most Kubernetes setups, it doesn't. This is one of the key ideas that unlocks the rest of Kubernetes networking.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Complete Pod Networking Stack
&lt;/h2&gt;

&lt;p&gt;Putting it all together:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                     Kubernetes Node
┌───────────────────────────────────────────────┐
│  Pod Network Namespace                        │
│  ┌───────────────────────────┐                │
│  │ Container                 │                │
│  │ Application               │                │
│  │     ↓                     │                │
│  │   eth0 (10.244.1.5)       │                │
│  └────────────┬──────────────┘                │
│               │                               │
│             veth                              │
│               ║                               │
│             veth                              │
│               │                               │
│               ↓                               │
│        Node networking                        │
│               │                               │
│               ↓                               │
│         Physical NIC                          │
└───────────────┼───────────────────────────────┘
                ↓
             Network
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What Happens When a Pod Is Created
&lt;/h2&gt;

&lt;p&gt;Let's walk through the sequence triggered by:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl run nginx &lt;span class="nt"&gt;--image&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;nginx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Kubernetes receives the request.&lt;/li&gt;
&lt;li&gt;The Pod gets scheduled onto a Node.&lt;/li&gt;
&lt;li&gt;The container runtime prepares the Pod.&lt;/li&gt;
&lt;li&gt;Networking gets configured:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Pod created
    ↓
Network namespace created
    ↓
CNI called
    ↓
veth pair created
    ↓
Pod gets eth0
    ↓
IP assigned
    ↓
Routes configured
    ↓
Pod networking ready
    ↓
Container starts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This sequence is one of the most important things to internalize in this article.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Pause Container: Kubernetes' Hidden Detail
&lt;/h2&gt;

&lt;p&gt;Here's a subtlety many tutorials skip: Kubernetes doesn't give every &lt;em&gt;container&lt;/em&gt; its own network namespace — it gives every &lt;em&gt;Pod&lt;/em&gt; one shared namespace, owned by a special &lt;strong&gt;pause container&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Pod
┌─────────────────────────────────┐
│  Pause container                │
│       └── Pod network namespace │
│                                 │
│  nginx container                │
│  sidecar container              │
└─────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every container in the Pod shares the Pod's:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;network namespace&lt;/li&gt;
&lt;li&gt;IP address&lt;/li&gt;
&lt;li&gt;network interfaces&lt;/li&gt;
&lt;li&gt;ports&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Multiple Containers, One Network Namespace
&lt;/h2&gt;

&lt;p&gt;Consider a Pod with three containers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Pod
┌────────────────────────────────────┐
│  Container A                       │
│  Container B                       │
│  Container C                       │
│                                    │
│  Shared network namespace          │
│  eth0 → 10.244.1.5                 │
└────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All three containers share &lt;code&gt;10.244.1.5&lt;/code&gt; and can talk to each other over &lt;code&gt;localhost&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Container A → localhost:8080 → Container B
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;...provided Container B is actually listening on that port.&lt;/p&gt;

&lt;h2&gt;
  
  
  Port Collisions Inside a Pod
&lt;/h2&gt;

&lt;p&gt;Because containers in a Pod share a network namespace, this can happen:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Container A → :8080
Container B → :8080   ❌
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a real conflict — two processes can't simultaneously own &lt;code&gt;10.244.1.5:8080&lt;/code&gt;. This is a great example of why understanding raw Linux networking (from Level 0) directly explains real Kubernetes behavior.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pod-to-Pod Communication (Same Node)
&lt;/h2&gt;

&lt;p&gt;Now suppose Pod A (&lt;code&gt;10.244.1.5&lt;/code&gt;) and Pod B (&lt;code&gt;10.244.1.6&lt;/code&gt;) are on the &lt;strong&gt;same&lt;/strong&gt; Node:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Pod A (10.244.1.5)
    ↓
  veth
    ↓
Node networking
    ↓
  veth
    ↓
Pod B (10.244.1.6)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The exact mechanism depends on the CNI plugin in use — we'll dig into specific implementations in Level 2 and Level 7.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pods on Different Nodes
&lt;/h2&gt;

&lt;p&gt;Here's where things get genuinely interesting. Consider two Pods on two different Nodes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Node 1                         Node 2
Pod A: 10.244.1.5              Pod B: 10.244.2.5
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pod A wants to reach Pod B directly by IP:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌──────────── Node 1 ────────────┐
│ Pod A (10.244.1.5)             │
└──────────────┬─────────────────┘
               │
               │ Network
               │
┌──────────────▼─────────────────┐
│ Node 2                         │
│ Pod B (10.244.2.5)             │
└────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This raises a critical question: &lt;strong&gt;how does traffic from Pod A reach a Pod IP living on a completely different machine?&lt;/strong&gt; That question is exactly where Level 2 of this series picks up.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Kubernetes Networking Model
&lt;/h2&gt;

&lt;p&gt;Kubernetes enforces an important networking guarantee:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Pod A → (direct Pod IP) → Pod B
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pods must be able to communicate across Nodes &lt;strong&gt;without the application needing to know or care which Node they're running on.&lt;/strong&gt; The underlying networking implementation is responsible for making this transparent, typically using one of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Overlay networking&lt;/li&gt;
&lt;li&gt;Routing-based networking&lt;/li&gt;
&lt;li&gt;Encapsulation (e.g., VXLAN)&lt;/li&gt;
&lt;li&gt;Cloud-native networking&lt;/li&gt;
&lt;li&gt;eBPF-based networking&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We'll explore each of these approaches later in the series.&lt;/p&gt;

&lt;h2&gt;
  
  
  What CNI Actually Does: A Preview
&lt;/h2&gt;

&lt;p&gt;By now you have a much clearer picture of what "CNI" really means. When a Pod is created, the CNI plugin handles:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CNI
 ├── Network namespace
 ├── veth pair
 ├── Pod interface
 ├── IP address
 ├── Routes
 └── Connectivity
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Don't worry about specific CNI implementations yet — that's reserved for Level 7. For now: &lt;strong&gt;CNI is the mechanism that gives Pods networking.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Hands-On: Inspecting a Real Pod
&lt;/h2&gt;

&lt;p&gt;Let's verify everything we've learned with real commands.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Create a Pod:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl run nginx &lt;span class="nt"&gt;--image&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;nginx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Check its IP and Node:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get pod &lt;span class="nt"&gt;-o&lt;/span&gt; wide
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;NAME    READY   STATUS    IP            NODE
nginx   1/1     Running   10.244.1.5    node-1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You now have a direct mapping: &lt;strong&gt;Pod name → Pod IP → Node.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Check the interface inside the Pod:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; nginx &lt;span class="nt"&gt;--&lt;/span&gt; ip addr
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;lo
eth0@if...
    inet 10.244.1.5/...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This confirms the chain: &lt;strong&gt;Pod → network namespace → eth0 → Pod IP.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Check the Pod's routing table:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; nginx &lt;span class="nt"&gt;--&lt;/span&gt; ip route
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;default via ...
10.244.1.0/24 dev eth0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The exact output depends on your CNI plugin, but the key question the routing table answers is always the same: &lt;em&gt;where does the Pod send traffic when it wants to reach something?&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; At this point you might come across implementation-specific interfaces like &lt;code&gt;docker0&lt;/code&gt;, &lt;code&gt;cni0&lt;/code&gt;, &lt;code&gt;flannel.1&lt;/code&gt;, &lt;code&gt;vxlan.calico&lt;/code&gt;, &lt;code&gt;cilium_host&lt;/code&gt;, or &lt;code&gt;cilium_net&lt;/code&gt;. Don't let these confuse you — they're all specific implementations of the same abstraction: &lt;code&gt;Pod → namespace → eth0 → veth → Node networking → CNI&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Level 1 Mental Model
&lt;/h2&gt;

&lt;p&gt;You should now be able to visualize a Node running multiple Pods like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                    NODE
┌────────────────────────────────────────────┐
│  Pod A                                     │
│  ┌─────────────────────────────┐           │
│  │ Network Namespace           │           │
│  │ eth0 (10.244.1.5)           │           │
│  └─────────────┬───────────────┘           │
│                │                           │
│              veth                          │
│                ║                           │
│                ↓                           │
│         Node networking                    │
│                                            │
│  Pod B                                     │
│  ┌─────────────────────────────┐           │
│  │ Network Namespace           │           │
│  │ eth0 (10.244.1.6)           │           │
│  └─────────────┬───────────────┘           │
│                │                           │
│              veth                          │
│                ║                           │
│                ↓                           │
│         Node networking                    │
└────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The core chain to remember:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Pod → Network Namespace → eth0 → veth pair → Node networking → CNI
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And two important corollaries:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Each Pod gets its own IP.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Containers within the same Pod share that Pod's network namespace, IP, and can talk to each other via &lt;code&gt;localhost&lt;/code&gt;.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The fundamental communication model in Kubernetes is simply:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Pod A → Pod IP → Pod B
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Level 1 Checkpoint
&lt;/h2&gt;

&lt;p&gt;Before moving to Level 2, make sure these all make sense to you:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q1. Who gives a Pod its networking?&lt;/strong&gt;&lt;br&gt;
→ The CNI (networking implementation).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q2. Does a Pod have its own IP?&lt;/strong&gt;&lt;br&gt;
→ Yes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q3. Does each container in a Pod get its own IP?&lt;/strong&gt;&lt;br&gt;
→ No — containers in the same Pod share the Pod's network namespace and IP address.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q4. What connects the Pod's network namespace to the Node?&lt;/strong&gt;&lt;br&gt;
→ Commonly, a veth pair.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q5. Where does &lt;code&gt;eth0&lt;/code&gt; exist?&lt;/strong&gt;&lt;br&gt;
→ Inside the Pod's network namespace.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q6. Why do we need CNI at all?&lt;/strong&gt;&lt;br&gt;
→ Kubernetes needs a networking implementation to create and configure Pod networking and provide connectivity between Pods.&lt;/p&gt;
&lt;h2&gt;
  
  
  What's Next: Pod-to-Pod Communication
&lt;/h2&gt;

&lt;p&gt;In &lt;strong&gt;Level 2&lt;/strong&gt;, we'll tackle the most important networking question in this series so far:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Pod A has &lt;code&gt;10.244.1.5&lt;/code&gt;. Pod B has &lt;code&gt;10.244.2.5&lt;/code&gt;. They're on different Nodes. How does a packet actually travel from A to B?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We'll trace the packet hop by hop:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Pod A → eth0 → veth → Node 1 → routing → CNI network → Node 2 → veth → Pod B
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;...and compare same-node versus cross-node Pod communication in detail.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Pod networking is where Kubernetes and Linux networking truly meet. Every Pod gets its own network namespace and &lt;code&gt;eth0&lt;/code&gt; interface, connected to the Node via a veth pair, with an IP address allocated from the cluster's Pod CIDR — all orchestrated by the CNI plugin. Containers within a Pod share that networking environment entirely, which is why they can talk to each other over &lt;code&gt;localhost&lt;/code&gt; but must be careful about port collisions.&lt;/p&gt;

&lt;p&gt;The best way to cement these concepts is to try it yourself: spin up a Pod, run &lt;code&gt;kubectl get pod -o wide&lt;/code&gt;, then &lt;code&gt;kubectl exec&lt;/code&gt; in and inspect &lt;code&gt;ip addr&lt;/code&gt; and &lt;code&gt;ip route&lt;/code&gt;. Seeing the abstraction match real output is what makes the model stick.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Found this useful?&lt;/strong&gt; Follow along for Level 2, where we trace a packet's full hop-by-hop journey between Pods on different Nodes. Drop a comment with your questions, and share this with someone still mixing up Pod CIDR and Node CIDR — let's keep demystifying Kubernetes networking together. 🚀&lt;/p&gt;

</description>
      <category>devops</category>
      <category>kubernetes</category>
      <category>networking</category>
      <category>linux</category>
    </item>
    <item>
      <title>Kubernetes Networking [Level-0: Linux Networking Basics for Kubernetes]</title>
      <dc:creator>ADITYA RAJ</dc:creator>
      <pubDate>Sat, 15 Aug 2026 06:30:00 +0000</pubDate>
      <link>https://dev.to/iadiraj/kubernetes-networking-level-0-linux-networking-basics-for-kubernetes-3429</link>
      <guid>https://dev.to/iadiraj/kubernetes-networking-level-0-linux-networking-basics-for-kubernetes-3429</guid>
      <description>&lt;p&gt;If you've ever opened a Kubernetes networking doc and seen words like &lt;strong&gt;CNI&lt;/strong&gt;, &lt;strong&gt;veth&lt;/strong&gt;, &lt;strong&gt;network namespace&lt;/strong&gt;, &lt;strong&gt;bridge&lt;/strong&gt;, &lt;strong&gt;iptables&lt;/strong&gt;, or &lt;strong&gt;eBPF&lt;/strong&gt; and felt completely lost — you're not alone. The truth is, none of these concepts are Kubernetes-specific. They're all built directly on top of &lt;strong&gt;Linux networking primitives&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This guide is "Level 0" of a Kubernetes networking series. Before we touch a single Kubernetes manifest, we're going to build a rock-solid mental model of how Linux moves packets around — because once you understand that, Kubernetes networking stops feeling like magic and starts feeling like Lego blocks snapping together.&lt;/p&gt;

&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;What Problem Does Networking Solve?&lt;/li&gt;
&lt;li&gt;IP Addresses: Identifying a Machine&lt;/li&gt;
&lt;li&gt;Ports: Identifying an Application&lt;/li&gt;
&lt;li&gt;Network Interfaces&lt;/li&gt;
&lt;li&gt;Loopback and localhost&lt;/li&gt;
&lt;li&gt;Network Namespaces&lt;/li&gt;
&lt;li&gt;Why Namespaces Matter&lt;/li&gt;
&lt;li&gt;veth Pairs: Virtual Network Cables&lt;/li&gt;
&lt;li&gt;Linux Bridges: Virtual Switches&lt;/li&gt;
&lt;li&gt;Routing Tables&lt;/li&gt;
&lt;li&gt;Default Gateway&lt;/li&gt;
&lt;li&gt;NAT: Network Address Translation&lt;/li&gt;
&lt;li&gt;The Full Packet Journey&lt;/li&gt;
&lt;li&gt;Essential Linux Networking Commands&lt;/li&gt;
&lt;li&gt;Putting It All Together: A Mental Model&lt;/li&gt;
&lt;li&gt;Level 0 Checkpoint&lt;/li&gt;
&lt;li&gt;What's Next: Pod Networking&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  What Problem Does Networking Solve?
&lt;/h2&gt;

&lt;p&gt;At its core, networking answers one simple question: &lt;strong&gt;how does data get from one machine to another?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Imagine two computers on a network:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Computer A                         Computer B
10.0.0.10                          10.0.0.20

   Application  ─────────────────→  Application
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Application A wants to send data to Application B. Networking is the set of rules and mechanisms that make this possible — and everything in this article builds toward answering that question in increasingly precise ways.&lt;/p&gt;

&lt;h2&gt;
  
  
  IP Addresses: Identifying a Machine
&lt;/h2&gt;

&lt;p&gt;An &lt;strong&gt;IP address&lt;/strong&gt; identifies a network endpoint — think of it as a machine's postal address.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Person
  ↓
House address
  ↓
10.0.0.10
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you want to send traffic to a specific machine, you address it using its IP:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Destination = 10.0.0.10
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Ports: Identifying an Application
&lt;/h2&gt;

&lt;p&gt;A single machine usually runs many applications at once. So how does traffic know &lt;em&gt;which&lt;/em&gt; application to reach? That's what &lt;strong&gt;ports&lt;/strong&gt; are for.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;10.0.0.10

22     → SSH
80     → HTTP
443    → HTTPS
8080   → Application
5432   → PostgreSQL
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In short:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;IP&lt;/strong&gt; = which machine?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Port&lt;/strong&gt; = which application on that machine?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, &lt;code&gt;10.0.0.10:8080&lt;/code&gt; means: &lt;em&gt;send traffic to machine 10.0.0.10, on port 8080.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Network Interfaces
&lt;/h2&gt;

&lt;p&gt;A computer needs a "door" through which network traffic enters and leaves. That door is called a &lt;strong&gt;network interface&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;On Linux, you can list interfaces with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ip addr
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You'll typically see names like &lt;code&gt;lo&lt;/code&gt;, &lt;code&gt;eth0&lt;/code&gt;, or on modern systems, &lt;code&gt;ens5&lt;/code&gt; or &lt;code&gt;enp0s3&lt;/code&gt;. Don't worry about the naming conventions yet — just know that every interface is a gateway between an application and the outside network.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Application
     |
     ↓
Network stack
     |
     ↓
   eth0
     |
     ↓
   Network
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Loopback and localhost
&lt;/h2&gt;

&lt;p&gt;You'll frequently encounter this address:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;127.0.0.1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the &lt;strong&gt;loopback address&lt;/strong&gt; — it always means "this machine, talking to itself."&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Application A
     |
     ↓
127.0.0.1
     |
     ↓
Same machine
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl http://127.0.0.1:8080
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This tells your machine: &lt;em&gt;connect to port 8080 on myself.&lt;/em&gt; The hostname &lt;code&gt;localhost&lt;/code&gt; typically resolves to this same address.&lt;/p&gt;

&lt;h2&gt;
  
  
  Network Namespaces
&lt;/h2&gt;

&lt;p&gt;Now we reach a concept that is &lt;strong&gt;critical&lt;/strong&gt; for understanding Kubernetes: &lt;strong&gt;network namespaces&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Linux lets you create fully isolated networking environments on a single machine. Each one can have its own interfaces, IP addresses, routing table, and firewall rules.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Linux Machine

┌──────────────────────────────┐
│ Network Namespace A          │
│ IP: 10.0.0.10                │
└──────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can spin up another, completely isolated from the first:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Linux Machine

┌──────────────────────────────┐
│ Namespace A                  │
│ IP: 10.0.0.10                │
│                              │
│ Namespace B                  │
│ IP: 10.0.0.20                │
└──────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This concept becomes essential once we talk about Kubernetes &lt;strong&gt;Pods&lt;/strong&gt; — each Pod gets its own network namespace.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Namespaces Matter
&lt;/h2&gt;

&lt;p&gt;Imagine two applications that both want to bind to port &lt;code&gt;8080&lt;/code&gt; on the same machine:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Machine

Application A → :8080
Application B → :8080   ❌
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Without isolation, this fails — two processes can't bind the same host IP/port combination.&lt;/p&gt;

&lt;p&gt;But give each application its own network namespace, and the conflict disappears:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Namespace A → 10.0.0.10:8080
Namespace B → 10.0.0.20:8080
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both can happily use port &lt;code&gt;8080&lt;/code&gt; because they live in separate network environments. This is the foundational idea behind &lt;strong&gt;containers&lt;/strong&gt; — and by extension, Kubernetes Pods.&lt;/p&gt;

&lt;h2&gt;
  
  
  veth Pairs: Virtual Network Cables
&lt;/h2&gt;

&lt;p&gt;Isolated namespaces are only useful if we can also &lt;strong&gt;connect&lt;/strong&gt; them. Linux provides a mechanism called a &lt;strong&gt;veth pair&lt;/strong&gt; for exactly this purpose.&lt;/p&gt;

&lt;p&gt;Think of a veth pair as a virtual network cable with two ends — anything that goes in one end comes out the other.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Namespace A                    Host

   eth0
    |
  veth-A  ═══════════════  veth-B
                              |
                           Host network
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One end lives inside a namespace; the other end lives on the host (or in another namespace). This is exactly how a container's network interface gets connected to the outside world.&lt;/p&gt;

&lt;h2&gt;
  
  
  Linux Bridges: Virtual Switches
&lt;/h2&gt;

&lt;p&gt;Once you have multiple namespaces, you need a way to connect all of them together — not just in pairs. That's where a &lt;strong&gt;Linux bridge&lt;/strong&gt; comes in.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;             Linux Bridge
           ┌──────────────┐
           │    bridge    │
           └─┬────┬────┬──┘
             │    │    │
             ↓    ↓    ↓
            A     B    C
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A helpful mental model: &lt;strong&gt;a bridge is essentially a virtual Layer-2 switch.&lt;/strong&gt; Each namespace connects to the bridge via its own veth pair, and the bridge forwards traffic between them just like a physical switch would.&lt;/p&gt;

&lt;h2&gt;
  
  
  Routing Tables
&lt;/h2&gt;

&lt;p&gt;Now suppose you have two separate networks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Network A: 10.0.1.0/24
Network B: 10.0.2.0/24
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A machine on Network A wants to reach &lt;code&gt;10.0.2.10&lt;/code&gt;. How does Linux decide where to send that packet? It consults its &lt;strong&gt;routing table&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;You can inspect it with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ip route
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;10.0.1.0/24 dev eth0
10.0.2.0/24 via 10.0.1.1
default via 10.0.1.1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Read each line as: &lt;em&gt;for this destination network, send traffic here.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Default Gateway
&lt;/h2&gt;

&lt;p&gt;What if your machine wants to reach an address it has no specific route for — like &lt;code&gt;8.8.8.8&lt;/code&gt;? It falls back to the &lt;strong&gt;default route&lt;/strong&gt;, also known as the &lt;strong&gt;default gateway&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;default via 10.0.0.1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This simply means: &lt;em&gt;"If I don't know where else to send this traffic, send it to 10.0.0.1."&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Your machine (10.0.0.10)
     |
     ↓
Gateway (10.0.0.1)
     |
     ↓
Internet
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  NAT: Network Address Translation
&lt;/h2&gt;

&lt;p&gt;Here's another crucial concept. Suppose your private network is &lt;code&gt;10.0.0.0/24&lt;/code&gt;, and your machine is &lt;code&gt;10.0.0.10&lt;/code&gt;. The public internet has no idea how to route traffic back to a private address like that directly.&lt;/p&gt;

&lt;p&gt;To solve this, a router performs &lt;strong&gt;NAT (Network Address Translation)&lt;/strong&gt; — rewriting private addresses into a public one (and remembering the mapping so return traffic gets routed correctly).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Private network
10.0.0.10
     |
     | NAT
     ↓
Public IP
     |
     ↓
Internet
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;10.0.0.10:50000  →  203.x.x.x:40000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;NAT will come up again and again once we start discussing Kubernetes traffic flows like Pod → Internet, Node → Internet, and Service → Pod.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Full Packet Journey
&lt;/h2&gt;

&lt;p&gt;Let's connect all the dots. Suppose Application A (&lt;code&gt;10.0.0.10&lt;/code&gt;) wants to talk to Application B (&lt;code&gt;10.0.0.20&lt;/code&gt;). The simplified journey looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Application A
      ↓
Socket
      ↓
TCP/IP stack
      ↓
Routing decision
      ↓
Network interface
      ↓
Network
      ↓
Network interface
      ↓
TCP/IP stack
      ↓
Application B
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This flow — socket, stack, routing decision, interface, network, and back again — is the foundation for everything else you'll learn about Kubernetes networking.&lt;/p&gt;

&lt;h2&gt;
  
  
  Essential Linux Networking Commands
&lt;/h2&gt;

&lt;p&gt;You don't need to memorize hundreds of commands. These few will get you very far:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# See interfaces and IP addresses&lt;/span&gt;
ip addr        &lt;span class="c"&gt;# or: ip a&lt;/span&gt;

&lt;span class="c"&gt;# See the routing table&lt;/span&gt;
ip route

&lt;span class="c"&gt;# See interfaces briefly&lt;/span&gt;
ip &lt;span class="nb"&gt;link&lt;/span&gt;

&lt;span class="c"&gt;# Test basic connectivity&lt;/span&gt;
ping &amp;lt;IP&amp;gt;

&lt;span class="c"&gt;# Test an application/service&lt;/span&gt;
curl http://&amp;lt;IP&amp;gt;:&amp;lt;PORT&amp;gt;

&lt;span class="c"&gt;# See listening ports&lt;/span&gt;
ss &lt;span class="nt"&gt;-lntp&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These commands will become your go-to Kubernetes networking debugging toolkit later on — get comfortable with them now.&lt;/p&gt;

&lt;h2&gt;
  
  
  Putting It All Together: A Mental Model
&lt;/h2&gt;

&lt;p&gt;Keep this picture in your head as your baseline model of a single Linux machine:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                 Linux Machine
┌────────────────────────────────────────┐
│ Application                            │
│      ↓                                 │
│ Socket                                 │
│      ↓                                 │
│ Network Stack                          │
│      ↓                                 │
│ Routing Table                          │
│      ↓                                 │
│ Network Interface                      │
└──────┼─────────────────────────────────┘
       ↓
     Network
       ↓
   Other machine
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now layer in network namespaces:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Linux Machine
│
├── Network Namespace A → eth0
├── Network Namespace B → eth0
└── Host Network Namespace → eth0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Connect them with veth pairs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Namespace A
    |
   eth0
    |
  veth
    ║
  veth
    |
  Host
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And tie them together with a bridge:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   Namespace A       Namespace B
        |                 |
        └───────┬─────────┘
             ┌───────┐
             │Bridge │
             └───────┘
                 |
              Network
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This exact combination — &lt;strong&gt;namespace + veth + bridge + routing&lt;/strong&gt; — is what Kubernetes uses under the hood to give every Pod its own network identity.&lt;/p&gt;

&lt;h2&gt;
  
  
  Level 0 Checkpoint
&lt;/h2&gt;

&lt;p&gt;Before moving on to Pod networking, make sure you can explain each of these in plain, simple language:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;IP address&lt;/li&gt;
&lt;li&gt;Port&lt;/li&gt;
&lt;li&gt;Network interface&lt;/li&gt;
&lt;li&gt;Loopback&lt;/li&gt;
&lt;li&gt;Network namespace&lt;/li&gt;
&lt;li&gt;veth pair&lt;/li&gt;
&lt;li&gt;Linux bridge&lt;/li&gt;
&lt;li&gt;Routing table&lt;/li&gt;
&lt;li&gt;Default gateway&lt;/li&gt;
&lt;li&gt;NAT&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And most importantly, internalize this relationship:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Network Namespace + veth + bridge + routing → Network connectivity
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If that equation makes sense to you, you're ready for the next level.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Next: Pod Networking
&lt;/h2&gt;

&lt;p&gt;In the next part of this series (Level 1), we'll take everything covered here and answer the first real Kubernetes networking question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;When Kubernetes creates a Pod, where does the Pod's network actually come from?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We'll trace the full path:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl run nginx
       ↓
Kubernetes creates Pod
       ↓
Network namespace
       ↓
veth pair
       ↓
Pod eth0
       ↓
Pod IP
       ↓
Node network
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's the exact point where Linux networking transforms into Kubernetes networking.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Kubernetes networking can feel intimidating, but it's really just a clever composition of well-known Linux primitives: IP addresses, ports, network namespaces, veth pairs, bridges, routing tables, and NAT. Once these concepts click, terms like CNI, iptables, and eBPF stop being buzzwords and start being tools you understand at a mechanical level.&lt;/p&gt;

&lt;p&gt;Take the time to run the commands in this article on your own Linux machine (or a cheap VM) — &lt;code&gt;ip addr&lt;/code&gt;, &lt;code&gt;ip route&lt;/code&gt;, &lt;code&gt;ss -lntp&lt;/code&gt; — and get a feel for what your own system's networking actually looks like. That hands-on intuition is what makes the next level, Pod networking, click into place effortlessly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Enjoyed this breakdown?&lt;/strong&gt; If you're following along with this Kubernetes networking series, drop a comment, follow for Level 1 on Pod Networking, and share this with a teammate who's still afraid of &lt;code&gt;iptables&lt;/code&gt;. Let's demystify Kubernetes networking together, one Linux primitive at a time. 🚀&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>linux</category>
      <category>networking</category>
      <category>devops</category>
    </item>
  </channel>
</rss>
