Title: Lecture 7 — Deployments, Services, and Configuration in Kubernetes
Course: AIINFRA 101: Applied Infrastructure & Containerization > Section: Week 07 — Kubernetes Workloads: Deployments, Services, Config

📖 Lecture — Deployments, Services, and Configuration in Kubernetes

Last week you met the Pod — the smallest deployable unit in Kubernetes. This week we build on top of that foundation with the three objects you'll use constantly in real work: the Deployment, the Service, and configuration objects (ConfigMaps and Secrets).

From Pods to Deployments

A common misconception coming out of Week 7 is that Pods and Deployments are interchangeable. They are not. A bare Pod is just a running instance of your container — if the node it's on dies, or the container crashes and Kubernetes gives up retrying, that Pod is gone for good. Nobody notices, and nobody brings it back. A Deployment is a higher-level controller that sits above your Pods and manages them for you. You describe a desired state — "I want 2 replicas of this Pod template running" — and the Deployment creates and manages a ReplicaSet, which is the object actually responsible for making sure that exact number of Pods exists at all times. If a Pod dies, the ReplicaSet notices the count has dropped below desired and creates a replacement. If you change the Pod template (say, a new container image tag), the Deployment creates a new ReplicaSet and orchestrates a rolling update between the old and new ReplicaSets, rather than you having to delete and recreate Pods by hand. This is the core reason Deployments exist: automatic recovery and safe, versioned updates, layered on top of the Pod concept you already know.

Exposing Pods with a Service

Pods are ephemeral — they get new IP addresses every time they're recreated. If your frontend had to track individual Pod IPs, it would break constantly. A Service solves this by giving a group of Pods (selected by matching labels) one stable endpoint that load-balances traffic across whichever Pods currently match that selector.

Service type | Reachable from | Typical use
ClusterIP (default) | Inside the cluster only | Internal service-to-service traffic, e.g., a backend API called by a frontend
NodePort | Any node's IP, on a fixed high port | Quick dev/test access, or as a building block under a LoadBalancer
LoadBalancer | The public internet, via a cloud provider's load balancer | Production external access in a cloud environment

The Service never talks to Pods by name — it continuously watches for Pods whose labels match its selector and routes traffic to them. This is why label consistency between your Deployment's Pod template and your Service's selector matters so much: a typo in a label silently breaks the connection.

Configuration with ConfigMaps and Secrets

Hard-coding configuration into a container image means rebuilding the image every time a value changes. ConfigMaps solve this by storing non-confidential key-value configuration data (up to 1 MiB) as a separate object that Pods consume via environment variables, command-line arguments, or mounted volume files. Secrets work the same way structurally, for confidential data like API keys or database passwords — but a critical fact to internalize: Secrets are only base64-encoded, not encrypted, in etcd by default in older Kubernetes versions. Base64 is an encoding, not encryption — anyone with etcd access can trivially decode it. Treat Secrets as access-controlled, not as cryptographically protected, unless you've enabled encryption at rest. Here's a misconception worth correcting early: if a Pod references a ConfigMap or Secret that doesn't exist yet, the container does not start with empty/default values and log a warning. It blocks entirely. You'll see the Pod stuck in Pending (if the reference is a mounted volume) or cycling through CrashLoopBackOff (if the app itself fails on missing env vars). This is a configuration error on your part, not a bug in your application — always check kubectl describe pod first.

Rolling Updates vs. Recreate

The default Deployment update strategy is RollingUpdate: old Pods are gradually replaced by new ones, controlled by maxSurge (how many extra Pods can exist temporarily above the desired count) and maxUnavailable (how many Pods can be down at once). This avoids downtime but means old and new versions run side by side briefly. The Recreate strategy instead kills all old Pods before creating any new ones — it causes downtime, but guarantees you never have two versions running simultaneously, which matters if your versions are incompatible with each other (e.g., a breaking database schema change).

Resource Requests Matter

Finally, always set resource requests on your Pods. Without them, the scheduler has no basis for calculating node utilization and can't make informed placement decisions — leading to nodes that are quietly over-subscribed (causing evictions and throttling) or under-subscribed (wasting capacity). This becomes especially important once you're scheduling GPU-aware workloads later in this course.

One More Misconception: Readiness vs. Liveness Probes

It's tempting to copy-paste the same probe definition for both readiness and liveness checks. Don't. A readiness probe tells the Service "don't send this Pod traffic yet" — appropriate for a backend that's just slow to warm up. A liveness probe tells Kubernetes "kill and restart this container." If you reuse a strict readiness-style check as your liveness probe, a temporarily slow (but otherwise healthy) Pod gets killed and restarted, which under load can cascade into a restart loop that makes the slowness worse, not better.