Pods, deployments, services & ingress
Now we meet the actual Kubernetes objects you'll work with every day. They build on each other in a clean ladder: a pod is the smallest unit that runs your container; a deployment keeps the right number of pods alive and updates them safely; a service gives those pods a stable network identity; and an ingress lets the outside world reach them over HTTP. Learn these four and you can deploy a real application to Kubernetes.
Pods: the smallest unit Kubernetes runs
You might expect Kubernetes to run containers directly. It doesn't quite — it runs pods. A pod is the smallest deployable unit in Kubernetes: a wrapper around one container (occasionally a few tightly-coupled containers that must live together). Those containers share the pod's network address and storage, so they behave like processes on the same little machine.
For most purposes, you can think "one pod = one running instance of my app." When you want 5 copies of your app, you want 5 pods.
The critical thing to internalize: pods are disposable and ephemeral. They're created and destroyed constantly — killed when they crash, evicted when a node is busy, replaced on every update. A pod can vanish at any moment, and its replacement gets a new network address. You almost never create pods directly or rely on a specific pod sticking around. Instead, you let higher-level objects manage them — which is exactly why deployments and services exist.
Deployments: keep N healthy pods, update them safely
A deployment is the object you actually write to run your app. You declare, among other things: which image to run and how many copies (replicas) you want. The deployment's job is to make that true and keep it true.
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
spec:
replicas: 5 # I want 5 pods running, always
selector:
matchLabels: { app: my-app }
template:
metadata:
labels: { app: my-app }
spec:
containers:
- name: my-app
image: my-app:1.4.0 # the immutable image tag from the last lesson
Read it as: "Always keep 5 pods running my-app:1.4.0." This single declaration buys you the three big wins from the orchestration lesson:
- Self-healing. If a pod crashes or a node dies and a pod disappears, the deployment notices the count dropped below 5 and creates a replacement automatically. You declared 5; it relentlessly maintains 5.
- Scaling. Want 20 pods for a traffic spike? Change
replicas: 5toreplicas: 20and re-apply. Kubernetes adds 15 pods. Scale back down the same way. - Rolling updates and rollbacks. Change the image to
my-app:1.4.1and re-apply, and the deployment performs a rolling update: it gradually replaces old pods with new ones, a few at a time, keeping the app available throughout. If the new version is broken, you roll back to the previous image and it reverses the process — instantly, because images are immutable (last lesson).
This is the declarative, desired-state model again: you never script "kill pod 3, start a new one." You declare the end state (5 pods of this image) and the deployment continuously reconciles reality to match — through crashes, scaling, and updates alike.
Services: a stable name for moving pods
Here's the problem deployments create: pods are disposable and their addresses keep changing. So how does another part of your system — or a load balancer — reliably reach "the app" when the specific pods behind it are a constantly shifting set?
A service solves this. A service is a stable, unchanging network address and name that always routes to the current set of healthy pods behind it. The pods come and go; the service stays put. It also load-balances across them, spreading requests over whatever pods are alive right now.
This is Kubernetes' built-in service discovery: other components just talk to the service name my-app, and Kubernetes handles routing to live pods. The shifting pods behind it are invisible. (Notice how this mirrors the load balancer from Chapter 2's networking — same idea, now inside the cluster.)
Ingress: letting the outside world in over HTTP
A service gives stable networking inside the cluster, but how do real users on the internet reach your app by URL? That's ingress. An ingress is an object that defines HTTP routing rules from outside the cluster to your services — for example, "send myapp.com/api to the api service and myapp.com/ to the web service." It's the cluster's smart HTTP front door, typically handling things like TLS (HTTPS) too.
The ladder, assembled
Put the four together and you have a complete, production-shaped path from a user's browser to your code:
Ingress routes the user's HTTP request to the right Service, which load-balances it to a healthy Pod, which is one of several kept alive and up-to-date by a Deployment.
You write the deployment (what to run, how many), the service (stable name), and the ingress (external routing), and Kubernetes maintains the whole arrangement — healing, scaling, and updating — without you touching individual pods.
:::tip You rarely touch pods directly A beginner mistake is trying to manage pods by hand. Don't. You declare deployments (and services and ingresses); Kubernetes manages the pods for you. If you find yourself manually creating or babysitting pods, step back — the higher-level objects exist precisely so you don't have to. This is durable Kubernetes hygiene. :::
Why it matters
Four objects build on each other to run an app on Kubernetes. A pod is the smallest unit (≈ one running app instance) and is deliberately disposable. A deployment declares which image and how many replicas, then continuously reconciles reality to match — giving you self-healing, easy scaling, and safe rolling updates/rollbacks for free. A service provides a stable name and load-balancing in front of the ever-changing pods (built-in service discovery), and an ingress routes outside HTTP traffic to the right service. You declare the desired arrangement; Kubernetes maintains it. Two practical needs remain before an app is production-ready: feeding it configuration and secrets, and understanding the cluster's brain that makes all this reconciliation happen.
Next: Config & secrets →