<?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-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>
