Cheat Sheets / Incident Handling

Incident Handling cheat sheet

151 commands from every lesson of Incident Handling — On-Call Playbook & Real Scenarios, on one page.

01 · Answering the page

First 5 minutes

Acknowledge the pageMeans 'I own this now', not 'it's fixed'
Read the alert + its runbook linkWhat fired, since when, which service
Check user impact (SLO dashboard, edge errors, support)Who is hurt, how many, how badly
What changed? (deploys, config, infra, certificates, time)Most incidents follow a change
Decide severity; declare if SEV1/SEV2Get help early
Post the first updateImpact · what we know · next update time

Stabilise options

kubectl rollout undo deploy/<name> -n <ns>Roll back a bad release
git revert <sha> (GitOps)Roll back through Git
Disable the feature flagTurn off new behaviour
Scale up / fail over / shed loadBuy time while you diagnose

02 · Where to start troubleshooting

Kubernetes first look

kubectl get events -A --sort-by=.lastTimestamp | tail -30What just happened, everywhere
kubectl get pods -A | grep -vE 'Running|Completed'Anything unhealthy
kubectl get nodes -o wide / kubectl top nodesNode status and load
kubectl describe pod <p> -n <ns>Events, restarts, last state
kubectl logs <p> -n <ns> --previousLogs of the crashed container

Method

Scope: user → pod → node → zone → everythingWhere does it stop being broken?
Compare a good and a bad instanceThe difference is the clue
One hypothesis at a time, cheapest test firstWrite down what's ruled out

03 · Engaging people & communicating

Escalate when

No mitigation after 15–30 minutesDon't struggle alone
Impact is growing or severe (SEV1/SEV2)More hands, clear roles
It needs access or knowledge you don't haveService owners, DBAs, network, vendor
You're tired or unsureFresh eyes are a feature

A good ask

Context: service, impact, since whenOne line
What's done and ruled outSaves them repeating it
The specific ask + where to join"Check the payments DB, bridge link…"

04 · Runbooks & the knowledge base

Runbook sections

What the alert means + user impactWhy you were woken
Quick checks (copy-paste commands)Confirm and scope in minutes
Mitigations (safest first)Stop the bleeding
Escalation (who, how)When to call whom
Links: dashboard, logs, past incidentsOne click away

Known-issue entry

Symptom (exact error text)What people will search for
CauseWhy it happens
Action / fix / workaroundWhat to do
Prevention status + linksIs it fixed for good?

05 · Writing the RCA

RCA template

Summary (3 sentences)What happened, impact, fix
Impact (numbers)Users, duration, errors, SLO budget used
Timeline (UTC)Detection, response, mitigation, resolution
Root cause + contributing factorsMechanism, and why it was possible
What went well / badly / luckyHonest response review
Action items (owner, date)Specific and verifiable

Useful tools

5 whysAsk 'why' until you reach something you can change
Time to detect / mitigate / resolveMeasure the response

06 · Preventing the repeat

Four kinds of fixes (strongest first)

EliminateDesign it away (automation, safer defaults, remove the dependency)
Detect earlierAlert on leading indicators (80% full, 30 days to expiry)
Limit blast radiusCanaries, quotas, limits, staged rollouts, isolation
Recover fasterRunbooks, tested rollback/restore, automation

Follow-through

Track actions like features (owner, due date)Not in a forgotten doc
Verify: test, drill or chaos experimentProve the fix works
Monthly review of repeats and overdue actionsKeep it honest

07 · etcd out of space at 2 a.m.

Inspect (on a control-plane node, kubeadm paths)

export ETCDCTL_API=3 ETCD='--endpoints=https://127.0.0.1:2379 --cacert=/etc/kubernetes/pki/etcd/ca.crt --cert=/etc/kubernetes/pki/etcd/server.crt --key=/etc/kubernetes/pki/etcd/server.key'Connection flags
etcdctl $ETCD endpoint status --cluster -w tableDB size, leader, raft index per member
etcdctl $ETCD alarm listmemberID:… alarm:NOSPACE ?
df -h /var/lib/etcdIs the disk itself full?

Recover

etcdctl $ETCD snapshot save /var/backups/etcd-$(date +%F-%H%M).dbSnapshot first, always
rev=$(etcdctl $ETCD endpoint status -w json | jq '.[0].Status.header.revision')Current revision
etcdctl $ETCD compact $revDrop old revisions
etcdctl $ETCD defrag --endpoints=<one member>Return free space, one member at a time
etcdctl $ETCD alarm disarmClear NOSPACE after space is back

08 · The noisy neighbour

Find the culprit

kubectl top pods -A --sort-by=cpu | head / --sort-by=memoryBiggest consumers
kubectl describe node <n> | sed -n '/Conditions/,/Events/p'Pressure conditions, allocated resources
kubectl get pods -A -o wide --field-selector spec.nodeName=<n>Who shares the node
crictl stats (on the node)Per-container usage
iostat -x 2 / pidstat -d 2Disk hogs

Contain & prevent

kubectl scale deploy/<hog> --replicas=0 -n <ns> (or cordon + move)Immediate relief
resources.requests + limits on every containerFair scheduling and caps
LimitRange (defaults) + ResourceQuota (per namespace)Guard rails for teams
Taints/tolerations, dedicated node poolsIsolate heavy or sensitive workloads

09 · Certificates expired after a failed rotation

Diagnose

sudo kubeadm certs check-expirationEvery kubeadm-managed cert and CA
echo | openssl s_client -connect 127.0.0.1:6443 2>/dev/null | openssl x509 -noout -datesWhat the API server presents
sudo openssl x509 -in /var/lib/kubelet/pki/kubelet-client-current.pem -noout -enddateKubelet client cert on a node
kubectl get certificate -A (cert-manager)Ingress/app certificates

Renew (kubeadm control plane)

sudo kubeadm certs renew allRenew leaf certs (on each control-plane node)
Restart control-plane static pods (move manifests out and back, or restart the containers)They must reload the new certs
sudo cp /etc/kubernetes/admin.conf ~/.kube/configRefresh your admin kubeconfig

10 · Docker network collides with the site network

Diagnose

ip route / ip -br addrLook for 172.17.0.0/16 dev docker0 (or br-…) overlapping site ranges
ip route get 172.17.5.40Which interface would traffic to that IP use?
docker network ls / docker network inspect bridgeDocker networks and their subnets
kubectl cluster-info dump | grep -m1 -E 'cluster-cidr|service-cluster-ip-range'Pod and Service CIDRs

Fix Docker ranges (/etc/docker/daemon.json)

"bip": "192.168.254.1/24"Move the default bridge
"default-address-pools": [ { "base": "192.168.240.0/20", "size": 24 } ]Ranges for user-defined networks
sudo systemctl restart dockerApply (recreate containers/networks as needed)

11 · Node unreachable after a network restart

Check (from the console / BMC)

ip -br link / ip -br addrInterfaces up? Addresses present?
ip route / ip route show table localDefault route? local routes incl. 127.0.0.0/8 dev lo?
ping -c1 127.0.0.1 / ping -c1 <gateway>Loopback and gateway reachable?
journalctl -u systemd-networkd -u NetworkManager --since -1hWhat the network service did
systemctl status kubelet containerdDid Kubernetes components survive?

Recover

sudo ip link set lo upBring the loopback back
sudo netplan apply / nmcli con up <name>Re-apply the persistent config
sudo systemctl restart kubeletAfter the network is right

12 · Longhorn volumes won't attach after a reboot

Diagnose

kubectl describe pod <p> -n <ns> | sed -n '/Events/,$p'FailedAttachVolume / FailedMount / Multi-Attach
kubectl -n longhorn-system get volumes.longhorn.io,replicas.longhorn.ioVolume state/robustness, replicas
kubectl get volumeattachments | grep <pv>Stale attachment to another node?
systemctl status iscsid (on the node)iSCSI initiator running?
multipath -ll / lsblkIs multipathd holding Longhorn's devices?

Fix

sudo systemctl enable --now iscsidStart iSCSI and keep it enabled
/etc/multipath.conf: blacklist { devnode "^sd[a-z0-9]+" }Stop multipathd grabbing Longhorn devices (check Longhorn's KB for your setup)
kubectl delete volumeattachment <name> (only when the old node is really gone)Clear a stale attachment

13 · Clock drift: NTP sync failed

Check

timedatectlSystem clock synchronized? NTP service active?
chronyc trackingOffset from the reference, stratum, last update
chronyc sources -vWhich servers, reachable? (^* = selected)
for n in node1 node2 node3; do ssh $n date -u +%s; doneCompare node clocks quickly

Fix

Allow UDP 123 to your NTP servers / run a local NTP serverRestore sync
sudo chronyc makestepStep the clock now (jumps time; see cautions)
node_timex_offset_seconds > 0.05 (node-exporter)Alert on drift

14 · Cluster-wide DNS timeouts

Diagnose

kubectl -n kube-system get pods -l k8s-app=kube-dns -o wideCoreDNS pods healthy? Where?
kubectl -n kube-system logs -l k8s-app=kube-dns --tail=50Errors, upstream timeouts
kubectl run dns --rm -it --image=busybox:1.36 -- nslookup kubernetes.defaultTest from a pod
cat /etc/resolv.conf (inside a pod)search domains, ndots:5
coredns_dns_requests_total, coredns_dns_request_duration_secondsCoreDNS metrics

Fix

Scale CoreDNS (replicas / cluster-proportional-autoscaler)More capacity
NodeLocal DNSCachePer-node cache, fewer conntrack issues
dnsConfig: options: [ { name: ndots, value: "2" } ]Fewer search-path lookups for external names
Use FQDNs with a trailing dot for external hosts (api.example.com.)Skip search expansion

15 · A broken admission webhook blocks every deploy

Diagnose

kubectl get validatingwebhookconfigurations,mutatingwebhookconfigurationsWhich webhooks exist
kubectl get validatingwebhookconfiguration <name> -o yaml | grep -E 'failurePolicy|timeoutSeconds|service:' -A3Fail closed? Which Service?
kubectl -n <ns> get pods,endpoints <webhook-svc>Is the webhook backend running?

Recover (carefully)

Restore the webhook's pods (scale up, fix the node, fix its certificate)Best fix
kubectl patch validatingwebhookconfiguration <name> --type=json -p '[{"op":"replace","path":"/webhooks/0/failurePolicy","value":"Ignore"}]'Temporary fail-open (record it, revert later)
Back up the config, then delete it only as last resortEscape hatch

16 · Node disk full: images and logs

Diagnose (on the node)

kubectl describe node <n> | grep -A6 ConditionsDiskPressure=True?
df -h / /var/lib/containerd /var/logWhich filesystem is full
sudo du -xh --max-depth=2 /var | sort -h | tail -15Biggest directories
sudo crictl images / sudo crictl ps -aImages and (exited) containers
sudo journalctl --disk-usagejournald size

Free space safely

sudo crictl rmi --pruneRemove images not used by any container
sudo journalctl --vacuum-size=500MShrink the journal
kubectl delete pods -A --field-selector=status.phase=FailedClean up evicted pod records
resources.limits.ephemeral-storageCap a pod's local disk use

17 · EKS: pods can't get IP addresses

Diagnose

kubectl describe pod <p> | grep -i 'assign an IP'The CNI error
aws ec2 describe-subnets --subnet-ids <ids> --query 'Subnets[].[SubnetId,AvailableIpAddressCount]'Free IPs per subnet
kubectl -n kube-system logs -l k8s-app=aws-node -c aws-node --tail=50VPC CNI (ipamd) errors
kubectl get node <n> -o jsonpath='{.status.allocatable.pods}'Max pods on the node
kubectl -n kube-system get ds aws-node -o yaml | grep -A1 -E 'WARM_|PREFIX'CNI settings

Fix / plan

ENABLE_PREFIX_DELEGATION=true (Nitro instances)Assign /28 prefixes per ENI slot: more pods per node
Tune WARM_IP_TARGET / MINIMUM_IP_TARGETDon't hoard IPs on every node
Add subnets / a secondary CIDR (e.g. 100.64.0.0/16) with custom networkingMore address space for pods

18 · EKS: locked out after editing aws-auth

Diagnose

aws sts get-caller-identityWhich IAM identity am I using?
aws eks describe-cluster --name <c> --query 'cluster.accessConfig'Authentication mode (CONFIG_MAP / API_AND_CONFIG_MAP / API)
aws eks list-access-entries --cluster-name <c>Access entries (if enabled)
kubectl -n kube-system get configmap aws-auth -o yamlThe mapping (once you have access)

Recover & harden

Use the cluster creator identity or an existing admin access entryA path that doesn't depend on aws-auth
aws eks create-access-entry + associate-access-policy (AmazonEKSClusterAdminPolicy)Grant admin via the EKS API
aws eks update-cluster-config --access-config authenticationMode=API_AND_CONFIG_MAPEnable access entries

19 · AWS: ALB 502s during every deployment

Diagnose

ALB metrics: HTTPCode_ELB_502_Count, HTTPCode_ELB_504_Count, TargetResponseTimeErrors align with deploy times?
kubectl get targetgroupbindings -AWhich Services the controller manages
kubectl get pod <p> -o jsonpath='{.status.conditions}'Readiness gate condition present?
ALB access logs: elb_status_code vs target_status_codeALB-generated vs app-generated errors

Fix

lifecycle.preStop: sleep ~15–30sKeep serving while the ALB deregisters the target
terminationGracePeriodSeconds > preStop + drain timeDon't get killed mid-drain
namespace label elbv2.k8s.aws/pod-readiness-gate-inject=enabledPods Ready only when healthy in the target group
alb.ingress.kubernetes.io/target-group-attributes: deregistration_delay.timeout_seconds=30Align deregistration delay