Warrior, this is one of the most important Kubernetes chapters.
If you understand Kubernetes networking properly, the architecture of real applications becomes much easier.
Our goal today is to understand this complete request flow:
Browser
↓
Internet
↓
Load Balancer / Ingress
↓
Service
↓
Pod
↓
ContainerBut before that, we need to understand how Pods communicate.
Imagine we have:
Node A
└── Pod A
Node B
└── Pod BPod A needs to communicate with Pod B.
Pod A ───────────> Pod BKubernetes needs to provide networking between them.
The Kubernetes networking model expects that:
The exact implementation is handled by the cluster's networking solution.
Suppose:
Pod A → 10.244.1.10
Pod B → 10.244.1.11
Pod C → 10.244.2.10Conceptually:
Kubernetes Cluster
┌──────────────────────────────┐
│ │
│ Pod A │
│ 10.244.1.10 │
│ │ │
│ │ │
│ ▼ │
│ Pod B │
│ 10.244.1.11 │
│ │
└──────────────────────────────┘Pods can communicate using these IPs.
But there is a problem.
Suppose:
Pod A
10.244.1.10gets deleted.
Deployment creates a replacement:
New Pod A
10.244.1.25The IP changed.
Therefore, this is a bad architecture:
Frontend
↓
10.244.1.10because tomorrow that Pod might have:
10.244.1.25This is exactly why we learned Services.
Instead of:
Frontend
↓
Pod IPwe use:
Frontend
↓
Service
↓
PodFor example:
backend-servicecould point to:
Pod A
Pod B
Pod CArchitecture:
backend-service
│
┌──────────┼──────────┐
▼ ▼ ▼
Pod A Pod B Pod CPods can come and go.
The Service remains stable.
A useful mental model:
┌─────────────────────────────┐
│ External Network │
│ Internet │
└──────────────┬──────────────┘
│
Ingress / LB
│
┌──────────────▼──────────────┐
│ Kubernetes Network │
│ │
│ Service │
│ │ │
│ ▼ │
│ Pods │
│ │ │
│ Containers │
└─────────────────────────────┘Let's break it down.
Inside a Pod:
Pod
│
├── Container A
│
└── Container BContainers in the same Pod share the Pod network namespace.
Therefore they can communicate through:
localhostFor example:
Container A
│
│ localhost:8080
▼
Container BIf Container A listens on:
8080another container in the same Pod can potentially access:
http://localhost:8080localhost Is Pod-Local#Suppose:
Pod A
├── frontend
└── sidecarThey can use:
localhostto communicate.
But:
Pod Acannot use:
localhostto reach:
Pod Bbecause they have different network namespaces.
So:
Same Pod
↓
localhostwhile:
Different Pods
↓
Pod IP / Service DNSSuppose:
frontend Pod
10.244.1.10and:
backend Pod
10.244.2.20The frontend needs to call backend.
Conceptually:
Frontend Pod
10.244.1.10
│
│ network
▼
Backend Pod
10.244.2.20Kubernetes networking handles routing between Pods, including when they are on different nodes.
Imagine:
Node 1
┌──────────────────┐
│ Frontend Pod │
│ 10.244.1.10 │
└──────────────────┘
│
│
▼
Cluster
│
▼
Node 2
┌──────────────────┐
│ Backend Pod │
│ 10.244.2.20 │
└──────────────────┘The Kubernetes networking implementation provides the connectivity.
The actual mechanism depends on the cluster's CNI/network plugin.
CNI stands for:
Container Network Interface
CNI is a standard used for configuring networking for containers.
Kubernetes itself defines the networking model, while a CNI implementation provides the actual networking functionality.
Examples include:
Calico
Cilium
Flannel
AWS VPC CNI
Azure CNI
Google networking implementationsDifferent Kubernetes environments can use different networking implementations.
Without networking:
Pod A ❌ Pod BWith a CNI:
Pod A ─────────── Pod BThe CNI can handle things such as:
Now let's return to Services.
Suppose:
backend-servicehas:
ClusterIP = 10.96.10.50and selects:
Pod A → 10.244.1.10
Pod B → 10.244.1.11
Pod C → 10.244.2.20Then:
Frontend
│
▼
10.96.10.50
│
├──────> Pod A
├──────> Pod B
└──────> Pod CThe Service provides a stable endpoint.
The default Service type is:
ClusterIPExample:
apiVersion: v1
kind: Service
metadata:
name: backend-service
spec:
selector:
app: backend
ports:
- port: 80
targetPort: 3000Kubernetes assigns a ClusterIP.
For example:
10.96.10.50This Service is normally accessible inside the cluster.
You don't normally want your application hardcoding:
10.96.10.50Instead use DNS.
Inside the cluster:
backend-servicecan resolve to the Service.
For cross-namespace access:
backend-service.productionAnd fully qualified:
backend-service.production.svc.cluster.localKubernetes normally provides DNS through a cluster DNS service, commonly CoreDNS.
Conceptually:
Application
│
│ backend-service
▼
CoreDNS
│
▼
Service IP
│
▼
Backend PodsSo your Node.js code can do:
fetch("http://backend-service/api/users");instead of:
fetch("http://10.96.10.50/api/users");The general fully qualified format is:
<service>.<namespace>.svc.cluster.localExample:
backend-service.production.svc.cluster.localBreakdown:
backend-service
↓
Service name
production
↓
Namespace
svc
↓
Service domain
cluster.local
↓
Cluster DNS domainNow suppose you want access from outside the cluster.
You can use:
NodePortExample:
apiVersion: v1
kind: Service
metadata:
name: backend-service
spec:
type: NodePort
selector:
app: backend
ports:
- port: 80
targetPort: 3000
nodePort: 30080Now:
Client
↓
Node IP:30080
↓
Service
↓
Pod:3000This is a very common interview question.
Suppose:
ports:
- port: 80
targetPort: 3000
nodePort: 30080port#80The Service listens on this port.
targetPort#3000The application Pod receives traffic on this port.
nodePort#30080The Kubernetes nodes expose this port for NodePort access.
So:
Client
↓
NodeIP:30080
↓
Service:80
↓
Pod:3000In cloud Kubernetes, you commonly use:
type: LoadBalancerExample:
apiVersion: v1
kind: Service
metadata:
name: backend-service
spec:
type: LoadBalancer
selector:
app: backend
ports:
- port: 80
targetPort: 3000A cloud provider can provision an external load balancer.
Conceptually:
Internet
│
▼
Cloud Load Balancer
│
▼
Kubernetes Service
│
▼
PodsInternet
↓
Node IP:30080
↓
Service
↓
PodsInternet
↓
Cloud Load Balancer
↓
Service
↓
PodsLoadBalancer is generally more convenient for external cloud exposure, though exact architecture varies.
Here's where things become powerful.
Suppose you have:
frontend-service
backend-service
admin-serviceYou don't necessarily want:
frontend.example.com → separate LB
backend.example.com → separate LB
admin.example.com → separate LBInstead, an Ingress can route HTTP/HTTPS traffic:
Internet
│
▼
Ingress
/ | \
/ | \
▼ ▼ ▼
frontend backend admin
Service Service ServiceWe'll study Ingress deeply in Chapter 12.
Let's say the user opens:
https://example.com/api/usersA typical architecture could look like:
Browser
│
│ HTTPS
▼
Cloud Load Balancer
│
▼
Ingress Controller
│
│ /api
▼
backend-service
│
▼
Backend Pod
│
▼
Node.js containerInside Node.js:
GET /api/usersmight query:
PostgreSQL Service
│
▼
PostgreSQL PodSo:
Browser
↓
Load Balancer
↓
Ingress
↓
Service
↓
Node.js Pod
↓
Postgres Service
↓
Postgres Pod
↓
Persistent StorageThat's a real Kubernetes application architecture.
Put everything together:
INTERNET
│
▼
Cloud Load Balancer
│
▼
Ingress Controller
│
┌─────────────┴─────────────┐
│ │
▼ ▼
frontend-service backend-service
│ │
┌─────┼─────┐ ┌─────┼─────┐
▼ ▼ ▼ ▼ ▼ ▼
Pod A Pod B Pod C Pod A Pod B Pod C
│
│
▼
postgres-service
│
▼
PostgreSQL Pod
│
▼
PVC
│
▼
Persistent StorageThis is the architecture you should start visualizing when you think "Kubernetes application."
You learned about kube-proxy in Chapter 3.
Now you can understand why it exists.
kube-proxy is traditionally responsible for implementing Service networking behavior on nodes, often using mechanisms such as iptables or IPVS depending on configuration.
Conceptually:
Client Pod
│
▼
Service IP
│
▼
Service networking rules
│
▼
Backend PodModern Kubernetes networking implementations can vary, and some environments use eBPF-based datapaths such as Cilium that can change how these functions are implemented.
The important beginner mental model is:
Service provides the stable abstraction; the cluster networking implementation handles how traffic reaches the selected Pods.
Remember:
Service
↓
PodsHow does Kubernetes know which Pods belong to the Service?
Through the Service selector.
For example:
selector:
app: backendIf Pods have:
labels:
app: backendthey become Service backends.
Kubernetes represents these backend addresses using EndpointSlices.
You can inspect them:
kubectl get endpointslicesor:
kubectl get endpointslices -l kubernetes.io/service-name=backend-serviceConceptually:
Service
│
▼
EndpointSlice
│
├── Pod A IP
├── Pod B IP
└── Pod C IPThis connects to Chapter 5.
Suppose:
Pod A → Ready
Pod B → Not Ready
Pod C → ReadyThe Service should normally route traffic only to ready endpoints.
So:
Service
│
├── Pod A ✅
├── Pod B ❌
└── Pod C ✅This is one reason readiness probes are so important.
Without readiness checks, Kubernetes could send traffic to an application that isn't ready to handle requests.
By default, depending on the cluster/network implementation and configuration, workloads may be able to communicate broadly.
You can introduce:
NetworkPolicyto control allowed traffic.
For example:
frontend → backend ✅
backend → postgres ✅
frontend → postgres ❌Conceptually:
Frontend
│
├──────────> Backend ✅
│
└──────────> Postgres ❌
Backend
│
└──────────> Postgres ✅This is a major security topic.
We'll study it in Chapter 20.
Don't confuse:
Podand:
ServiceRuns the application.
Pod
└── ContainerProvides a stable networking endpoint for selected Pods.
Service
↓
PodsSo:
Pod = workload
Service = networking abstraction
Another common interview question.
Routes traffic to Pods.
Service
↓
PodsProvides HTTP/HTTPS routing rules to Services.
Ingress
↓
Services
↓
PodsSo:
Ingress
↓
Service
↓
Pod| Type | Typical purpose |
|---|---|
| ClusterIP | Internal cluster communication |
| NodePort | Expose through node port |
| LoadBalancer | External cloud load balancer |
| ExternalName | DNS alias to an external service |
Most applications heavily use:
ClusterIPinternally.
External access is often handled by:
Ingress + Load Balanceror another gateway/load-balancing architecture.
Create a backend:
kubectl create deployment backend \
--image=nginxExpose it:
kubectl expose deployment backend \
--port=80 \
--target-port=80Check:
kubectl get svcYou'll see something like:
NAME TYPE CLUSTER-IP
backend ClusterIP 10.96.x.xNow:
kubectl get endpointslicesYou should see the backend endpoints.
Run a temporary Pod:
kubectl run curl \
--image=curlimages/curl \
-it \
--rm \
-- shInside it:
curl http://backendThe request:
curl Pod
↓
backend Service
↓
backend Pod
↓
nginxThis is an excellent practical exercise.
When networking doesn't work, use:
Check Pods:
kubectl get pods -o wideCheck Service:
kubectl get svcCheck Service details:
kubectl describe svc backendCheck EndpointSlices:
kubectl get endpointslicesTest DNS:
nslookup backendfrom a suitable debugging Pod.
Test HTTP:
curl http://backendThis gives you a basic networking troubleshooting workflow.
You run:
kubectl get endpointslicesand discover no backend addresses.
Possible reason:
Service selector
≠
Pod labelsFor example:
Service:
selector:
app: backendPod:
labels:
app: apiThey don't match.
Therefore:
Service
❌
PodtargetPort#Application listens on:
3000but Service says:
targetPort: 8080Then:
Service
↓
8080
❌
Application
↓
3000Connection fails.
This is a very common Node.js/Docker issue.
Suppose your Node.js application does:
app.listen(3000, "127.0.0.1");Inside the container, it's only listening on loopback.
Better for a containerized server:
app.listen(3000, "0.0.0.0");or:
app.listen(3000);depending on the framework/runtime behavior.
Why?
Because Kubernetes needs to reach the application's network interface through the Pod network.
Memorize this:
INTERNET
│
▼
Load Balancer
│
▼
Ingress
│
▼
Service
│
┌──────┼──────┐
▼ ▼ ▼
Pod Pod Pod
│
▼
ContainerFor internal communication:
Frontend Pod
│
│ DNS
▼
backend-service
│
▼
Backend PodFor database:
Backend Pod
│
│ DNS
▼
postgres-service
│
▼
PostgreSQL Pod
│
▼
PVC
│
▼
Persistent StorageUnder the standard Kubernetes networking model, yes, each Pod gets a unique cluster IP.
No.
Pods are ephemeral, so their IPs can change.
Use a Service for stable access.
Through the cluster networking model, typically using Pod IPs or Services.
Through Kubernetes DNS.
Example:
backend-serviceContainer Network Interface, a standard for configuring container networking. Kubernetes clusters use a CNI implementation to provide Pod networking.
The stable virtual IP assigned to a Service for internal cluster access.
port and targetPort?#port
↓
Service port
targetPort
↓
Application/Pod portExample:
Service:80
↓
Pod:3000A Service type that exposes the Service through a port on each node, typically from the configured NodePort range.
A Service type that can integrate with a cloud provider to provision an external load balancer.
Because Pod IPs are ephemeral while Services provide a stable endpoint and service discovery.
Pod
↓
Has IP
↓
IP can change
↓
Service
↓
Stable endpoint
↓
DNS
↓
Service discoveryExternal traffic:
Internet
↓
Load Balancer
↓
Ingress
↓
Service
↓
Pod
↓
ContainerInternal traffic:
Pod A
↓
Service DNS
↓
Service
↓
Pod BAnd:
Same Pod
↓
localhost
Different Pods
↓
Pod IP / Service
Different namespaces
↓
Service.namespaceIf you remember only one diagram from this chapter, remember this:
USER
│
▼
INTERNET
│
▼
┌───────────────┐
│ Load Balancer │
└───────┬───────┘
│
▼
┌───────────────┐
│ Ingress │
└───────┬───────┘
│
HTTP routing
│
┌────────────┴────────────┐
▼ ▼
frontend-service backend-service
│ │
┌────┼────┐ ┌────┼────┐
▼ ▼ ▼ ▼ ▼ ▼
Pod Pod Pod Pod Pod Pod
│
▼
postgres-service
│
▼
PostgreSQL Pod
│
▼
PVC
│
▼
Persistent StorageYou now have the core Kubernetes architecture from application → storage → networking.
We'll go deep into:
Ingress
Ingress Controller
Host-based routing
Path-based routing
HTTP vs HTTPS
TLS certificates
Domains
Multiple Services behind one entry pointAnd we'll build an architecture like:
https://example.com → Next.js
https://example.com/api → Node.js
https://admin.example.com → Admin Appwith Kubernetes YAML.
Mark it as complete to track your mastery.