KubernetesX · Pod Termination and SignalsPod termination and signals
Node shutdown and Pod termination — graceful vs forceful
What you'll learn
- Trace what happens to Pods when a node shuts down
- Configure graceful node shutdown (systemd inhibitor + kubelet flags)
- Distinguish graceful from forceful node shutdown
- Identify the consequences of forceful shutdown (in-flight requests lost, state lost)
Prerequisites
Verified against Kubernetes 1.34.x · kubeadm 1.34.x · kubectl 1.34.x · etcd 3.6.x · CoreDNS 1.11.x · containerd 1.7.x / 2.x · 2026-08-16
Node shutdown is a special case of Pod termination. The kubelet may not have time to gracefully terminate Pods if the node is powered off quickly. This lesson covers graceful node shutdown, how kubelet integrates with systemd inhibitors, and what happens when shutdown is not graceful.
The shutdown problem
When a node shuts down:
- systemd sends SIGTERM to all services, including kubelet.
- The kubelet’s shutdown handler begins terminating Pods.
- The kubelet has limited time before systemd sends SIGKILL
(default 90s, configurable via
TimeoutStopSecin the systemd unit). - If the kubelet is SIGKILL’d before all Pods are terminated, Pods are lost without graceful shutdown.
sequenceDiagram
participant Systemd
participant Kubelet
participant Pods
participant Node as Node hardware
Systemd->>Systemd: shutdown initiated
Systemd->>Kubelet: SIGTERM
Note over Kubelet: shutdown handler starts
Kubelet->>Pods: terminate gracefully
par graceful termination
Pods-->>Pods: SIGTERM, drain, exit
and
Systemd->>Systemd: countdown TimeoutStopSec
end
alt kubelet finishes
Kubelet-->>Systemd: exit
Systemd->>Node: power off
else timeout
Systemd->>Kubelet: SIGKILL
Systemd->>Node: power off (Pods lost)
end
Without graceful node shutdown, the kubelet has the
TimeoutStopSec window (default 90s) to terminate all Pods.
For nodes with many Pods and short grace periods, this is
not enough time.
Graceful node shutdown
The kubelet has a graceful node shutdown feature (beta in 1.21+, GA in 1.27+). The kubelet:
- Listens for systemd’s inhibitor lock release (which signals impending shutdown).
- On inhibitor release, starts terminating all Pods on the node.
- Holds the inhibitor lock until termination is complete or the kubelet’s shutdown grace period expires.
The systemd side:
- The kubelet takes a
shutdowninhibitor lock when it starts. systemd waits for the inhibitor to be released before powering off. - The kubelet releases the inhibitor after it has finished terminating Pods (or after the kubelet’s shutdown grace period).
This coordination gives kubelet the time it needs to gracefully terminate Pods, without racing the kernel’s shutdown.
Configuring kubelet for graceful shutdown
The kubelet flags:
--shutdown-grace-period: total time the kubelet has to terminate all Pods (default 30s).--shutdown-grace-period-critical-pods: time the kubelet has to terminate critical Pods (default 10s). Critical Pods are those withpriorityClassName: system-cluster-criticalorsystem-node-critical.
The total shutdown grace period is
--shutdown-grace-period (regular Pods) +
--shutdown-grace-period-critical-pods (critical Pods after
the regular ones).
# /etc/kubernetes/kubelet-config.yaml
shutdownGracePeriod: 60s
shutdownGracePeriodCriticalPods: 30s
These translate to kubelet flags. For a maintenance window:
- The systemd
TimeoutStopSecmust be ≥ the kubelet’s total shutdown grace period. - The kubelet must be able to take the
shutdowninhibitor (default in modern systemd).
Systemd integration
systemd’s inhibitor locks let services delay or prevent
system shutdown. The kubelet takes a shutdown inhibitor
during its lifetime; when systemd begins shutdown, it waits
for the inhibitor to be released.
sequenceDiagram
participant Systemd
participant Kubelet
participant Pods
Kubelet->>Systemd: acquire shutdown inhibitor
Systemd->>Systemd: shutdown initiated
Systemd->>Kubelet: inhibitor release signal
Kubelet->>Pods: terminate gracefully
Pods-->>Kubelet: all terminated
Kubelet->>Systemd: release inhibitor
Systemd->>Systemd: proceed with shutdown
Without the inhibitor:
- systemd sends SIGTERM to kubelet.
- kubelet begins termination.
- systemd’s
TimeoutStopSecexpires (default 90s). - systemd sends SIGKILL to kubelet; pods may not be fully terminated.
With the inhibitor:
- systemd sends SIGTERM to kubelet.
- kubelet begins termination.
- systemd waits for kubelet to release the inhibitor.
- kubelet finishes termination, releases the inhibitor.
- systemd proceeds with shutdown.
Pod termination ordering
The kubelet terminates Pods on shutdown in this order:
- Critical Pods first
(
priorityClassName: system-cluster-criticalorsystem-node-critical). - Regular Pods next.
- Within each group, the kubelet tries to terminate all Pods simultaneously (it sends SIGTERM to each in parallel).
- Wait for
--shutdown-grace-periodto expire or all Pods to exit. - SIGKILL any remaining Pods.
The --shutdown-grace-period-critical-pods controls the
time the kubelet gives critical Pods; this is shorter than
the regular shutdown grace period because critical Pods
(typically add-ons like kube-proxy, CNI) are designed to
shutdown quickly.
Forceful shutdown
When a node is powered off forcefully (hard power cycle, hardware failure, kernel panic), there is no opportunity for graceful shutdown. The Pods are lost:
- In-flight requests are cut off.
- In-memory state is lost.
- The kubelet’s last reported state may be stale; the API server has not received termination events.
After forceful shutdown:
- The node is
NotReady(the kubelet cannot report). - After
node-monitor-grace-period(default 50s), the node is markedNotReadyby the node controller. - After
pod-eviction-timeout(default 5 minutes), the Pods are evicted (deleted) and recreated on other nodes.
The application sees a Pod termination that looks like forced deletion: exit code 137, no graceful shutdown, lost work.
Production patterns
Maintenance window with graceful shutdown:
# 1. Cordon the node (no new Pods scheduled)
kubectl cordon node-3
# 2. Drain the node (PDB-protected; voluntary)
kubectl drain node-3 --ignore-daemonsets
# 3. Perform the maintenance (kernel upgrade, hardware swap)
# 4. Reboot — kubelet takes the shutdown inhibitor;
# Pods are terminated gracefully
# 5. After reboot, uncordon
kubectl uncordon node-3
The drain handles the voluntary disruption; the reboot handles the unavoidable shutdown. PDBs protect the drain; graceful shutdown protects the reboot.
Forced shutdown (last resort):
# Power off immediately, no graceful shutdown
sudo systemctl poweroff --force
# Or hard reboot
sudo reboot --force
Use this only when the node is unresponsive or the
maintenance is urgent. Pods on the node are lost; the
cluster will recreate them after pod-eviction-timeout.
Cross-course references
- The Linux course part
IX-Linux-Bootcovers systemd and shutdown; graceful node shutdown is the cluster-level equivalent. - The Proxmox course part
XXXV-Linux-Storagecovers cluster shutdown; the kubelet’s inhibitor is the cluster-level equivalent. - The Docker course part
XXX-Docker-Lifecyclecovers container shutdown; node-level shutdown is the cluster-level equivalent.
Quiz
Knowledge check · 4 questions
Q1. What does the kubelet do with the systemd `shutdown` inhibitor lock?
Q2. PodDisruptionBudgets protect Pods from graceful node shutdown.
Q3. An operator performs a kernel upgrade on a node. The node reboots. After reboot, 8 of 10 Pods on the node are missing; the API server shows them as Terminating. Diagnose.
Node `node-3` was running 10 Pods. The operator ran `kubectl drain --ignore-daemonsets` (voluntary), then rebooted for the kernel upgrade. After reboot, 2 Pods are Running on node-3; 8 are showing Terminating in the API server.
Q4. What is the difference between graceful node shutdown and `kubectl drain`? When does each apply?
Passing score: 75%. Answers are checked in this browser.
Production discipline
- Enable graceful node shutdown on every node. Configure
--shutdown-grace-periodand--shutdown-grace-period-critical-podsto match your longest Pod shutdown time. - Verify systemd’s
TimeoutStopSecis ≥ the kubelet’s shutdown grace period. Otherwise systemd SIGKILLs the kubelet before it finishes. - Test graceful shutdown in staging. Trigger a maintenance reboot, verify all Pods terminate cleanly.
- Distinguish drain from shutdown in runbooks. Drain is operator-controlled with PDBs; shutdown is system- controlled without PDBs.
- Plan for forceful shutdown. Hardware failures and kernel panics bypass graceful shutdown; have a recovery procedure for the after-state.