Your Deployment from Chapter 5 is running Pods. But there's a problem: Pods are ephemeral. When a Pod crashes and is replaced, it gets a new IP address. Your application clients can't track these constant changes.
Enter Services. A Service is a stable, virtual IP address that routes to a dynamic set of Pods. It's like a phone number that rings to whoever happens to be on duty today—not tied to one person, but always available.
In this chapter, you'll understand why Services are necessary, learn the three main Service types, and master the mechanism that makes it all work: label selectors.
In Docker (Module 6), a container had a stable network identity. You'd run a container, learn its IP, and talk to it.
Kubernetes is different. Pods are designed to be replaced:
When this Pod crashes and Kubernetes restarts it, a new Pod takes its place. But the new Pod gets a new IP address. The old IP becomes invalid.
Imagine your frontend application tries to talk to your backend:
If the backend Pod gets replaced (it will), 10.0.2.45 no longer exists. The request fails.
This is unacceptable in production. You need a stable address that routes to the current set of healthy backend Pods, regardless of which specific Pods are running.
Enter Services.
A Service is a Kubernetes abstraction that provides:
Think of a Service like a phone number. The number stays the same, but the person who answers might change. Call the same number and get connected to whoever is currently on duty.
A Service uses label selectors to determine which Pods receive traffic. Here's the mechanism:
When you apply this Service:
Your frontend Pod now talks to:
Even when backend Pods crash and restart, the Service name and IP stay constant. Kubernetes automatically updates the endpoints.
Kubernetes offers three main Service types. Choose based on your access pattern.
Use when: Pods need to talk to other Pods within the cluster.
Characteristics:
Example traffic flow:
Use when: You need external clients to access your application (development/testing).
Characteristics:
Example traffic flow:
Use when: You need production-grade external access with load balancing.
Characteristics:
Example traffic flow:
Label selectors are the mechanism that connects Services to Pods. They're critical to understand because misconfigured selectors cause Services to have zero endpoints.
When you define a Service selector, Kubernetes continuously asks: "Which Pods match these labels?"
This Service routes traffic to Pods labeled both app: web and version: v1.
Pod 1: Matches the selector
Pod 2: Does NOT match
Pod 3: Does NOT match
The Service routes to Pod 1 only. Pods 2 and 3 are ignored.
You'll create a Deployment, then expose it via different Service types. Start with your Docker Desktop Kubernetes cluster running.
Create a file called web-deployment.yaml:
Apply it:
Output:
Verify Pods are running with labels displayed:
Output:
Notice each Pod has the label app=web (the key label the Service will use). Get their IP addresses:
Output:
Each Pod has a unique IP: 10.244.0.3, 10.244.0.4, 10.244.0.5. If a Pod crashes, Kubernetes replaces it with a new Pod at a new IP. This is why Services matter—they provide stable routing regardless of which Pod IPs are currently active.
Create web-service-clusterip.yaml:
Apply it:
Output:
Inspect the Service:
Output:
The Service has a stable virtual IP: 10.96.0.234. This IP never changes, even if Pods are replaced.
Launch a temporary Pod inside the cluster to test internal access:
From inside the Pod, curl the Service:
Output:
Success! The Service routed your request to one of the backend Pods. Try it again:
Same output. Kubernetes load-balanced across Pods transparently. You didn't need to know which specific Pod answered—the Service handled it.
Exit the test Pod:
Update web-service-clusterip.yaml:
Apply the update:
Output:
Verify the change:
Output:
The Service now listens on node port 30007. With Docker Desktop, access the Service via localhost:
Output:
Success! External traffic now reaches your Deployment through the NodePort Service.
Your Pods don't need to know the Service IP address. Kubernetes provides automatic DNS discovery.
Every Service gets a DNS name in the format:
For the web-service in the default namespace:
Within the same namespace, you can shorten it to:
Launch a test Pod and resolve the DNS name:
From inside the Pod, install curl and bind-tools (for DNS utilities), then test DNS resolution:
Output:
Kubernetes DNS returned the Service's virtual IP. Your application can connect without hardcoding IPs. Test it:
Output:
The request succeeded! Kubernetes DNS resolved web-service to the virtual IP, and the Service routed to a backend Pod.
You can also use the full DNS name from different namespaces:
Output:
Both work. Kubernetes DNS resolves either form to the virtual IP. Exit the test Pod:
The most common Service problem: a Service has no endpoints. This happens when the label selector doesn't match any Pods.
Create a Deployment with app: backend:
Apply it:
Output:
Now create a Service with the wrong selector:
Apply it:
Output:
Check the Service endpoints:
Output:
No endpoints! The Service exists but routes to nothing. Any traffic sent to this Service fails because there's no Pod to handle it.
Update the Service with the correct selector:
Apply the fix:
Output:
Check endpoints again:
Output:
Now the Service has 2 endpoints (the 2 backend Pods). Traffic will route correctly.
When a Service has no endpoints, follow this systematic check:
Output:
Output:
Output:
Now the Service has endpoints. Traffic will route correctly to the backend Pods.
Challenge: You have a FastAPI agent running in Kubernetes (from Module 6 containerization). Expose it so:
You'll describe the requirements, and you and AI will iterate on the Service configuration.
Setup:
Part 1: Internal Access Requirement
Tell AI: "I need a Service that lets other Pods access my agent at port 8000. The agent Deployment has label app: agent."
Record AI's Service specification for internal access.
Part 2: Evaluate Internal Design
Review AI's response:
Ask yourself: What would you change to make this better?
Part 3: External Access Requirement
Tell AI: "Now I also need external clients to test the agent. Should I convert to NodePort or LoadBalancer? I'm testing locally with Docker Desktop Kubernetes."
Note AI's reasoning about the choice.
Part 4: Design Validation
Ask AI: "Show me the complete Service YAML for external testing access on Docker Desktop Kubernetes."
Apply the YAML to your cluster:
Test external access:
Part 5: Reflection
Compare your initial understanding to what emerged:
These questions activate your reasoning for future Service design decisions in production environments.
You built a kubernetes-deployment skill in Chapter 0. Test and improve it based on what you learned.
Ask yourself:
If you found gaps: