Skip to content

Phase 2: Pods, Deployments, Services ​

Time: weeks 1-2. Goal: the holy trinity. This is 70% of day-to-day k8s.

Pod ​

The smallest deployable unit. A Pod wraps one or more containers that share a network namespace and volumes - they see each other on localhost.

  • Why a wrapper instead of bare containers: sidecars (log shippers, proxies) need to live next to the main container.
  • You almost never create bare Pods directly. No controller watches them, so they don't survive node failures or deletion.
  • Know the lifecycle states: Pending, Running, Succeeded, Failed - and restartPolicy.

Deployment ​

Your docker compose service equivalent, but with superpowers.

  • Declares "N replicas of this pod template must exist". A ReplicaSet underneath enforces the count.
  • Rolling updates: change the image tag, k8s replaces pods gradually.
  • Rollbacks: kubectl rollout undo deployment/<name>.

The self-healing demo that makes k8s click:

bash
kubectl create deployment web --image=nginx --replicas=3
kubectl get pods -w
# in another terminal: kill one
kubectl delete pod <one-of-them>
# watch it resurrect

Service ​

Pods are mortal and their IPs change. A Service gives a stable virtual IP and DNS name in front of a moving set of pods.

  • ClusterIP (default): internal only, like compose service names.
  • NodePort: opens a port on every node. Mostly for local testing.
  • LoadBalancer: provisions a cloud load balancer. Costs money per service.

How a Service finds its pods: label selectors. The Service selects app: web, every pod with that label gets traffic. Labels are the duct tape of all of k8s - internalize this. Nothing is linked by name; everything is linked by label.

Cluster DNS ​

Every Service gets a DNS name: my-service.my-namespace.svc.cluster.local. Within the same namespace, apps just use http://my-service. This is why compose-style inter-service URLs often survive migration unchanged.

Namespaces ​

Lightweight isolation, like compose project names. Use them to separate apps or environments on one cluster.

YAML anatomy ​

Every manifest has the same four top-level fields:

yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web
spec:
  # the resource-specific part

Use kubectl explain deployment.spec (and deeper, e.g. deployment.spec.template.spec.containers) instead of googling field names.

Exercise ​

Full playbook with solutions, expected output, and a load-balancing demo: Lab 2.

Take the traefik/whoami image and, by hand, no copy-paste:

  1. Write a Deployment with 3 replicas.
  2. Write a ClusterIP Service in front of it.
  3. kubectl apply both, port-forward to the Service, verify.
  4. Do a rolling update to a new image tag, watch with kubectl rollout status.
  5. Roll it back with kubectl rollout undo.

Checkpoint ​

  • You can explain Pod vs ReplicaSet vs Deployment and why the layers exist.
  • You can explain how a Service knows which pods to send traffic to.
  • You wrote a working Deployment + Service from a blank file.

Next: Phase 3: Configuration and State

A VineLab lab. Released under the MIT License.