Lab 07 - Pods

Lab 07 - Pods

Goal: generate a Pod manifest, add resources, and see what a Pod really is. Chapter: Pods

# 1 - imperative: create and throw away
kubectl run bbox --image busybox --restart=Never -- sleep 3600
kubectl get pods
kubectl delete pod bbox

--restart=Never is what makes kubectl run produce a bare Pod instead of something managed. -- sleep 3600 overrides the image’s command, because busybox would otherwise exit immediately.

# 2 - generate the manifest instead
cd ~
kubectl run bbox --image busybox --restart=Never --dry-run=client -o yaml \
  -- sleep 3600 > bbox.yaml
cat bbox.yaml

Edit bbox.yaml and add resources to the container:

spec:
  containers:
    - name: bbox
      image: busybox
      command: ["sleep", "3600"]
      resources:                     # <-- add this block
        requests:
          cpu: "50m"
          memory: "32Mi"
        limits:
          cpu: "100m"
          memory: "64Mi"

50m is 50 millicores - five hundredths of a CPU. The scheduler subtracts the requests from the node’s allocatable capacity; the limits are enforced at runtime by cgroups.

# 3 - apply and verify what the API actually stored
kubectl apply -f bbox.yaml
kubectl get pod bbox -o wide
kubectl describe pod bbox | grep -A6 Limits
kubectl get pod bbox -o jsonpath='{.spec.containers[0].resources}{"\n"}'
# 4 - live in there
kubectl exec -it bbox -- sh -c 'hostname; ip -brief address; cat /etc/resolv.conf'

resolv.conf points at the CoreDNS Service and lists the search domains that make web-svc resolve to web-svc.default.svc.cluster.local. That is how every Service name in this course works.

# 5 - which fields can you change in place?
sed -i 's/image: busybox/image: busybox:1.36/' bbox.yaml
kubectl apply -f bbox.yaml              # allowed - image is mutable
sed -i 's/cpu: "100m"/cpu: "200m"/' bbox.yaml
kubectl apply -f bbox.yaml              # read the error carefully

Most of a Pod’s spec is immutable. Kubernetes replaces Pods rather than reconfiguring them - which is exactly why you use a controller.

Two containers, one Pod

# 6 -
cat > twin.yaml <<'YAML'
apiVersion: v1
kind: Pod
metadata:
  name: twin
spec:
  containers:
    - name: web
      image: nginx:1.27
    - name: shell
      image: busybox
      command: ["sleep", "3600"]
YAML
kubectl apply -f twin.yaml
kubectl get pod twin                            # READY 2/2
kubectl exec -it twin -c shell -- wget -qO- localhost:80 | head -3
kubectl logs twin -c web

The busybox container reaches nginx on localhost - they share one network namespace. -c selects the container for exec and logs; without it, kubectl picks the first one.

Discovery

Infodiscovery

Task A. Create a Pod called initdemo that waits for the twin Pod’s nginx to answer before its main container starts. The main container just sleeps. Expected: kubectl get pod initdemo shows Init:0/1 for a moment, then Running.

IP=$(kubectl get pod twin -o jsonpath='{.status.podIP}')
cat > init.yaml <<YAML
apiVersion: v1
kind: Pod
metadata:
  name: initdemo
spec:
  initContainers:
    - name: wait-for-web
      image: busybox
      command: ["sh", "-c", "until wget -q --spider http://$IP:80; do sleep 2; done"]
  containers:
    - name: app
      image: busybox
      command: ["sleep", "3600"]
YAML
kubectl apply -f init.yaml
kubectl get pod initdemo -w
kubectl logs initdemo -c wait-for-web

Task B. Without deleting anything, find out how much memory the twin Pod is allowed to use. Expected: it has no limit at all.

kubectl get pod twin -o jsonpath='{.spec.containers[*].resources}{"\n"}'
kubectl describe pod twin | grep -A4 -i limits

Empty {} - no requests, no limits. The scheduler assumed it needs nothing, which is how nodes get overcommitted.

Clean up

kubectl delete -f bbox.yaml -f twin.yaml
kubectl delete pod initdemo --ignore-not-found