Skip to content
Laviyx Learn

Try

Docker and Kubernetes course menu

Kubernetes Pods and Deployments Tutorial

Write Kubernetes YAML for pods and deployments, apply it with kubectl, scale replicas, do rolling updates and rollbacks, and debug pods with logs and describe.

Advanced9 min readUpdated
On this page

In Kubernetes, you usually write the desired state in YAML files, and keep them in Git.

A pod#

A pod is one or more containers that share a network address. You rarely create pods by hand, but this shows the format that every Kubernetes object uses:

Terminal
cat > pod.yaml <<'EOF'
apiVersion: v1
kind: Pod
metadata:
  name: hello
  labels:
    app: hello
spec:
  containers:
    - name: web
      image: nginx:1.30-alpine
      ports:
        - containerPort: 80
EOF
kubectl apply -f pod.yaml
kubectl wait --for=condition=Ready pod/hello --timeout=90s
kubectl get pod hello --no-headers | awk '{print $1, $2, $3}'
Output
pod/hello created
pod/hello condition met
hello 1/1 Running
FieldMeaning
apiVersion, kindWhat type of object this is
metadataIts name and labels
specWhat you want

Labels are key-value tags, and they matter later. See inside the pod with commands that look like Docker's:

Terminal
kubectl exec hello -- nginx -v
kubectl delete pod hello --wait=false > /dev/null
sleep 3
kubectl get pods --no-headers 2> /dev/null | grep -c Running
Output
nginx version: nginx/1.30.6
0

Once deleted, this pod does not come back. Nothing is managing it. For that, you need a Deployment.

A deployment#

A Deployment says "keep this many copies of this pod running":

Terminal
cat > deployment.yaml <<'EOF'
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web
spec:
  replicas: 3
  selector:
    matchLabels:
      app: web
  template:
    metadata:
      labels:
        app: web
    spec:
      containers:
        - name: nginx
          image: nginx:1.29-alpine
          ports:
            - containerPort: 80
          resources:
            requests:
              cpu: 50m
              memory: 32Mi
            limits:
              memory: 64Mi
EOF
kubectl apply -f deployment.yaml
kubectl rollout status deployment/web --timeout=120s | tail -n 1
kubectl get deployment web --no-headers | awk '{print $1, $2}'
kubectl get pods -l app=web --no-headers | awk '{print $2, $3}'
Output
deployment.apps/web created
deployment "web" successfully rolled out
web 3/3
1/1 Running
1/1 Running
1/1 Running
  • replicas is the number of pods.
  • template is the pod to create.
  • selector tells the Deployment which pods belong to it, by label.
  • requests is what the scheduler reserves, and limits is the maximum.

A Deployment manages a ReplicaSet, which in turn manages the pods.

Scaling#

Terminal
kubectl scale deployment web --replicas=5
kubectl rollout status deployment/web --timeout=90s | tail -n 1
kubectl get pods -l app=web --no-headers | wc -l
Output
deployment.apps/web scaled
deployment "web" successfully rolled out
5

Changing replicas in the file and applying it again is the better way, because the file stays correct. A HorizontalPodAutoscaler can scale automatically, based on CPU.

Rolling updates#

Change the image, and Kubernetes replaces pods gradually, so that the app stays up:

Terminal
sed -i 's/replicas: 3/replicas: 4/; s/nginx:1.29-alpine/nginx:1.30-alpine/' deployment.yaml
kubectl apply -f deployment.yaml
kubectl rollout status deployment/web --timeout=120s | tail -n 1
kubectl rollout history deployment/web | tail -n +3 | awk '{print $1}' | grep -c .
kubectl get deployment web -o jsonpath='{.spec.template.spec.containers[0].image}{"\n"}'
Output
deployment.apps/web configured
deployment "web" successfully rolled out
2
nginx:1.30-alpine

Rolling back#

Suppose a bad version is deployed. This image tag does not exist:

Terminal
kubectl set image deployment/web nginx=nginx:0.0.0-missing
sleep 12
kubectl get pods -l app=web --no-headers | awk '{print $3}' | sort | uniq -c
Output
deployment.apps/web image updated
      2 ErrImagePull
      3 Running

The old pods stay up while the new ones fail, so users are not affected. Roll back:

Terminal
kubectl rollout undo deployment/web 2> /dev/null
kubectl rollout status deployment/web --timeout=120s | tail -n 1
kubectl get deployment web -o jsonpath='{.spec.template.spec.containers[0].image}{"\n"}'
Output
deployment.apps/web rolled back
deployment "web" successfully rolled out
nginx:1.30-alpine

Debugging pods#

CommandUse
kubectl get podsSee status
kubectl describe pod nameRead events at the bottom
kubectl logs nameRead logs; --previous for the last crash
kubectl exec -it name -- shOpen a shell
StatusUsual meaning
ImagePullBackOffWrong image name, or no access to the registry
CrashLoopBackOffThe app keeps crashing; read the logs
PendingNo node has room
OOMKilledOver the memory limit
Terminal
kubectl describe deployment web | grep -E '^Replicas:|Image:' | sed 's/  */ /g'
kubectl delete -f deployment.yaml
Output
Replicas: 4 desired | 4 updated | 4 total | 4 available | 0 unavailable
 Image: nginx:1.30-alpine
deployment.apps "web" deleted from default namespace

Common mistakes#

Key takeaway#

Next: Services and Networking.

Finished this lesson?

Some links are affiliate links. If you buy through them, Laviyx Learn may earn a commission at no extra cost to you. As an Amazon Associate, we earn from qualifying purchases.