Devops

Kubernetes Pods and Deployments

·2 min read

Kubernetes has a reputation for complexity that's only half-deserved. The complexity is mostly in operating a cluster, not in using one. From a developer's perspective, k8s is a small set of YAML resource types and a control loop that keeps the cluster matching what you declared. Once you internalize the loop, the rest follows.

The control loop, in one sentence

You write desired state (YAML); controllers compare desired state to observed state and act to make them match.

Pod: the smallest deployable unit

A pod is one or more containers sharing a network namespace and (usually) a couple of volumes. You almost never create raw pods — you let a higher-level resource manage them. But understanding the pod is the foundation.

apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  containers:
  - name: nginx
    image: nginx:1.27-alpine
    ports:
    - containerPort: 80
    resources:
      requests: { cpu: 50m, memory: 64Mi }
      limits:   { cpu: 200m, memory: 128Mi }

Deployment: manage pods at scale

Deployments wrap a ReplicaSet which manages a set of identical pods. You specify how many replicas you want; the controller scales up or down to match.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: web
spec:
  replicas: 3
  selector:
    matchLabels: { app: web }
  strategy:
    type: RollingUpdate
    rollingUpdate: { maxSurge: 1, maxUnavailable: 0 }
  template:
    metadata:
      labels: { app: web }
    spec:
      containers:
      - name: web
        image: ghcr.io/myorg/web:v1.2.3
        readinessProbe:
          httpGet: { path: /healthz, port: 8080 }
        livenessProbe:
          httpGet: { path: /healthz, port: 8080 }
          initialDelaySeconds: 10

Roll out by changing image: and applying. Rolling update keeps capacity up during the change.

Service: stable network identity

Pods come and go; their IPs change. A Service is a stable virtual IP that load-balances across all pods matching a label selector.

apiVersion: v1
kind: Service
metadata:
  name: web
spec:
  selector: { app: web }
  ports:
  - port: 80
    targetPort: 8080
  type: ClusterIP    # internal only; use LoadBalancer for external

ConfigMap and Secret

apiVersion: v1
kind: ConfigMap
metadata: { name: web-config }
data:
  LOG_LEVEL: info
  CACHE_TTL: "300"
---
apiVersion: v1
kind: Secret
metadata: { name: web-secrets }
type: Opaque
stringData:
  DATABASE_URL: postgres://...

What kubectl gives you

kubectl apply -f deployment.yaml
kubectl get pods -l app=web
kubectl describe pod web-7f9c-abcde      # events, conditions, why it's not ready
kubectl logs -f web-7f9c-abcde -c web
kubectl exec -it web-7f9c-abcde -- sh
kubectl port-forward svc/web 8080:80
kubectl rollout status deploy/web
kubectl rollout undo deploy/web

When k8s isn't worth it

If you have one server and three services, docker-compose is fine. If you have ten servers and you'd otherwise be writing scripts to keep them in sync, k8s is paying for itself. The break-even is somewhere between "small" and "annoying to operate by hand."

Related