Services and Ingress: how traffic reaches a pod
Your Deployment is running pods — but pods are disposable, each with its own IP that changes when the pod is replaced. So how does anything reach your app reliably, and how do the replicas share traffic? The answer is a Service, which gives the pods one stable address and load-balances across them. And to expose the app to the outside world by hostname, you use an Ingress. This lesson is how traffic reaches a pod, verified against a live cluster.
The problem: pods are moving targets
You have two greetings pods, each with its own IP, and those IPs change every time a pod is replaced (a crash, a deploy, a reschedule). So nothing can rely on a pod's IP — by the time you use it, the pod may be gone. And you have two pods; traffic should spread across both. You need a stable front door that (a) does not change when pods do, and (b) balances traffic across the current healthy pods. That is exactly a Service.
A Service: one stable address
A Service is an object that gives a set of pods a single, stable address and load-balances across them. It finds its pods the same way the Deployment does — by label selector. Here is the greetings Service, verified on a live cluster:
apiVersion: v1
kind: Service
metadata:
name: greetings
spec:
type: ClusterIP
selector:
app: greetings # route to every pod with this label
ports:
- port: 80 # the Service listens on port 80
targetPort: 3000 # and forwards to the pods' container port 3000
The key line is selector: app: greetings — the same label the Deployment puts on its pods (the labels
lesson). So the Service automatically routes to whatever pods currently have that label — two now, three if you
scale up, a fresh one after a pod is replaced. You never update the Service when pods change; the selector
keeps it current. The Service gets a stable ClusterIP and a DNS name (greetings), and anything in the
cluster can reach the app at greetings regardless of which pods exist. This is the Compose "reach a service
by name" idea (the containers module), now at cluster scale.
Verify it by port-forwarding the Service and hitting it:
kubectl port-forward service/greetings 8080:80
curl localhost:8080/ # -> {"message":"Namaste from greetings-...","visits":null}
The response comes from one of the pods behind the Service — reached through the stable Service address, not a pod IP.
Service types: who can reach it
A Service has a type that decides how far its reach extends:
ClusterIP(the default) — reachable only inside the cluster. This is right for internal services (an API that only other pods call, a database) — and, as the security pattern from the containers module, most services should be ClusterIP, exposed to the world only through a controlled front door.NodePort— opens a port on every node; a simple way to reach a service from outside, mostly for dev/ testing.LoadBalancer— on a cloud, provisions a real cloud load balancer with a public IP in front of the Service. This is how a service gets a public address on EKS/GKE/AKS.
The default and most common is ClusterIP — internal. Getting outside traffic in is usually done not with a LoadBalancer per service, but with an Ingress.
Ingress: the front door for HTTP
Giving every public service its own cloud load balancer is expensive and clumsy. An Ingress is a smarter front door: one entry point that routes HTTP(S) traffic by hostname and path to different Services inside the cluster.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: greetings
spec:
rules:
- host: greetings.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: greetings # route this host/path to the greetings Service
port:
number: 80
An Ingress lets you say "greetings.example.com → the greetings Service; api.example.com → the api Service"
— many public hostnames through one load balancer, with HTTPS/TLS terminated there (the networking module's
TLS, handled at the ingress). An Ingress controller (nginx-ingress, or the cloud's) does the actual
routing; you declare the rules. For a foundation, the mental model is what matters: traffic comes in through
an Ingress, which routes by hostname/path to Services, which load-balance across pods. That is the full path
from the internet to your container.
The full traffic path
Put the pieces together — this is how a real request reaches your app on Kubernetes:
Internet → Ingress (routes by host/path, terminates TLS) → Service (stable address, load-balances) → Pod (one replica running your container).
Each layer solves one problem: the Ingress gives you one public front door with hostnames and HTTPS; the
Service gives a stable internal address and load-balancing over changing pods; the pod runs the code. And they
are all wired by labels — the Service finds pods by label, so the whole path self-updates as pods come and
go. Internally, one pod reaches another service simply by its Service name (greetings), exactly as with
Compose.
Check your work
The problem: pods have changing IPs and there are several — nothing can target a pod IP, and traffic should spread across replicas. Need a stable front door that load-balances.
A Service gives a set of pods one stable address (ClusterIP + DNS name) and load-balances, finding its
pods by label selector (the same label the Deployment sets) — so it self-updates as pods change; you
never edit it when pods come/go. port (Service) → targetPort (container). Reached in-cluster by name
(greetings), like Compose.
Service types: ClusterIP (internal only — default; right for most services, per the security pattern),
NodePort (a port on every node — dev/test), LoadBalancer (a real cloud LB with a public IP on EKS/GKE/AKS).
Ingress = the HTTP(S) front door: one entry point routing by hostname/path to Services, terminating TLS, via an ingress controller. Many public hosts through one load balancer.
Full path: Internet → Ingress (host/path routing, TLS) → Service (stable address, load-balance) → Pod. Wired by labels, so it self-updates.
Practice
- Explain why you cannot rely on a pod's IP and how a Service solves it.
- Write a ClusterIP Service for the greetings pods; apply it and port-forward to reach the app.
- Explain how the Service finds its pods, and why you never edit it when pods are replaced.
- Compare ClusterIP, NodePort and LoadBalancer and say when each is appropriate.
- Write an Ingress rule routing a hostname to the greetings Service and explain what an ingress controller does.
- Draw the full traffic path from the internet to a pod, naming what each layer provides.
Official documentation
- Kubernetes — Service — Stable addresses and load-balancing over pods.
- Kubernetes — Ingress — HTTP(S) routing by host and path.
- Kubernetes — Ingress controllers — What actually fulfils an Ingress.
Next: ConfigMaps, Secrets and environment configuration.
Stuck on this lesson?
Being stuck is part of it — but being stuck alone for three days is not. Our internship programme pairs this curriculum with code review and one-to-one help from working developers, and it is free.
About the internship