Defect Scenarios Basics
This page shows the small, plausible container and Kubernetes settings that turn into outages, with a runnable snippet and the fix for each.
Search across all documentation pages
This page shows the small, plausible container and Kubernetes settings that turn into outages, with a runnable snippet and the fix for each.
Work through these to build intuition before the deeper incident walkthroughs in this section.
kubectl configured (kind or a cloud cluster both work).kubectl create namespace defect-lab
kubectl config set-context --current --namespace=defect-labPulling :latest means two identical manifests can run different code.
containers:
- name: api
image: registry.example.com/api:latest # today's latest, not yesterday'simage: registry.example.com/api@sha256:....imagePullPolicy: IfNotPresent with a fixed tag so nodes do not silently re-pull.A liveness probe that fires before the app is ready restarts a healthy container.
livenessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 1
periodSeconds: 5initialDelaySeconds: 1 assumes a one-second startup that does not survive load.startupProbe for slow boot, then let liveness take over.A pod with no memory limit can consume a node and get OOMKilled unpredictably.
resources:
requests:
memory: "256Mi"
limits:
memory: "512Mi"limits, the kernel OOM killer, not Kubernetes, decides who dies.requests, the scheduler cannot bin-pack safely and overcommits the node.requests and limits for memory.kubectl get pod RESTARTS and describe for Reason: OOMKilled.Build with Docker, but pods run on containerd via the CRI - dockershim is gone.
# On a node, inspect running containers with the CRI tool, not docker
crictl ps
crictl imagesdocker ps on a node shows nothing about pods on a modern cluster.crictl for node-level debugging.A container that runs as root widens the blast radius of any compromise.
securityContext:
runAsNonRoot: true
runAsUser: 1000
allowPrivilegeEscalation: false
capabilities:
drop: ["ALL"]runAsNonRoot: true.Without readiness, a Service sends traffic to a pod that is still warming up.
readinessProbe:
httpGet:
path: /ready
port: 8080
periodSeconds: 5An aggressive rollout amplifies a bad config across the whole Deployment instantly.
strategy:
rollingUpdate:
maxUnavailable: 25%
maxSurge: 25%maxUnavailable can drop capacity below what traffic needs.PodDisruptionBudget.A JVM that ignores the cgroup limit sizes its heap to the node, then gets OOMKilled.
FROM eclipse-temurin:21-jre
# Modern JVMs read cgroup limits by default; tune the fraction explicitly
ENV JAVA_OPTS="-XX:MaxRAMPercentage=75.0"
ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar /app/app.jar"]limits.memory.MaxRAMPercentage sizes the heap from the detected cgroup limit, not the host.kubectl exec and check the reported max heap against the limit.Open pod-to-pod networking lets one compromised workload reach everything.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-ingress
spec:
podSelector: {}
policyTypes: ["Ingress"]podSelector applies the policy to every pod in the namespace.ingress rules, all inbound pod traffic is denied by default.Before fixing, reproduce the failure so you know the trigger.
kubectl apply -f bad-liveness.yaml
kubectl get pod -w # watch RESTARTS climb under load
kubectl describe pod api-xxxx # read Events for Liveness probe failed
kubectl logs api-xxxx --previous # inspect the crashed container--previous reads the log of the container instance that was just killed.Events section names the trigger: probe failure, OOMKilled, or ImagePullBackOff.Stack versions: This page was written for Kubernetes 1.36.2, Docker Engine 29.6.1 (BuildKit default), containerd (CRI runtime on nodes), Helm 3, Compose v2, Argo CD (latest - verify at build), and Gateway API (GA - verify controller support at build).
Reviewed by Chris St. John·Last updated Jul 16, 2026