Kubernetes
An API running in one container is easy to keep track of. Once it runs across several machines, somebody has to decide where each copy goes, replace failed instances, and route traffic away from ones that are starting up. A deployment now involves coordinating a fleet, rather than restarting one process.
Google had been dealing with container fleets through its internal Borg system. It released Kubernetes in 2014 to bring that experience outside its own infrastructure. The useful shift is that you describe what should be running, and controllers keep comparing that description with what is actually running.
For the API, that description might be three replicas of the same image. A Deployment manages their replacement, and the scheduler finds nodes with room for their Pods. A Service provides a stable destination as those Pods come and go.
Save the following as orders.yaml. It assumes an existing orders namespace and your own application image serving /health/ready on port 8000:
apiVersion: apps/v1
kind: Deployment
metadata:
name: orders
spec:
replicas: 3
selector:
matchLabels:
app: orders
template:
metadata:
labels:
app: orders
spec:
containers:
- name: api
image: registry.example.test/orders:release-42
ports:
- containerPort: 8000
readinessProbe:
httpGet:
path: /health/ready
port: 8000
resources:
requests:
cpu: 100m
memory: 128Mi
---
apiVersion: v1
kind: Service
metadata:
name: orders
spec:
selector:
app: orders
ports:
- port: 80
targetPort: 8000The labels connect the pieces: the Deployment manages Pods marked app: orders, and the Service sends traffic to matching, ready Pods. Requests arrive at Service port 80 and reach container port 8000. The CPU and memory requests help the scheduler choose a node.
With a configured context pointing to the intended cluster, compare the manifest with the running resources, apply it, and watch the rollout:
kubectl config get-contexts
kubectl --context staging-cluster -n orders diff -f orders.yaml
kubectl --context staging-cluster -n orders apply -f orders.yaml
kubectl --context staging-cluster -n orders rollout status deployment/orders
kubectl --context staging-cluster -n orders get deploy,pods,svc -o wide
kubectl --context staging-cluster -n orders get events --sort-by=.metadata.creationTimestampdiff returns 1 when there are differences. During a rolling update, Kubernetes replaces the old Pods gradually, according to the rollout settings and available capacity. Readiness keeps a newly started copy out of ordinary Service traffic until its check succeeds. If a GitOps controller manages this application, make the change in its source instead of applying a competing local copy.
Suppose a new Pod keeps restarting. Its events and logs are more useful than another restart. Replace POD_NAME with a name from the listing:
kubectl --context staging-cluster -n orders describe pod POD_NAME
kubectl --context staging-cluster -n orders logs POD_NAME -c api --tail=100
kubectl --context staging-cluster -n orders logs POD_NAME -c api --previous
kubectl --context staging-cluster -n orders get endpointslices \
-l kubernetes.io/service-name=orders--previous retrieves logs from the preceding container instance. Events can reveal a scheduling or startup failure; EndpointSlices help establish whether the Service has eligible backends. Those observations narrow the problem to a particular stage of getting the application online.
The same machinery runs queue consumers and other replicated workers. On a shared platform, teams can use a consistent deployment interface while the platform handles placement and replacement. The application still needs sensible probes and recovery behavior; putting a database in a Pod does not establish replication or backups.
The lessons on workload reconciliation and traffic transitions follow those control loops in more detail.