Skip to main content
RunBook Academy

← All runbooks in Linux

high riskservice affecting~60 min

Runbook: Rolling kernel upgrade - the production procedure

1 · Prerequisites

Confirm every item is in place before any state change.

2 · Pre-checks

Read-only diagnostic commands. If any of these don't match expected output, stop and investigate further.

  • · Verify the new kernel package is available in the repository
  • · Verify the cluster is healthy (all nodes online, and no node already in standby)
  • · Verify GRUB has the old kernel as the fallback option: grubby --info=ALL lists an entry for the currently running kernel
  • · Confirm GRUB_DEFAULT=saved in /etc/default/grub - grub2-reboot and grub2-set-default have no effect otherwise
  • · Verify out-of-band access (BMC, console)

3 · Procedure

Execute each step in order. Verify the expected output of a step before moving to the next.

  1. 1Drain node1 (canary) with pcs node standby
  2. 2Install the new kernel package
  3. 3Reboot the node
  4. 4Validate: kernel version, services, network, storage
  5. 5Return node1 to service: pcs node unstandby node1, then confirm resources can be placed with pcs status nodes
  6. 6Hold for 24 hours
  7. 7If validation fails, roll back via GRUB
  8. 8Proceed to node2 and node3 in the same way (drain, upgrade, reboot, validate, unstandby, hold)
  9. 9Document the change

4 · Verification

Confirm the procedure actually fixed the problem.

  • All nodes running the new kernel
  • No node is left in standby: pcs status nodes shows an empty Standby list
  • All services healthy
  • No regressions observed in 24h
  • GRUB fallback still works (tested in staging)
  • grubby --default-kernel and grub2-editenv list agree with the kernel the node is running - the node will boot the same kernel next time

5 · Rollback

If verification fails, undo the procedure in reverse order.

  • Set the persistent GRUB default to the old kernel with grubby --set-default (grub2-reboot is one-shot and does not survive the following boot)
  • Reboot the node
  • Verify the old kernel boots and that grubby --default-kernel still points at it
  • Remove or version-lock the bad kernel package so it cannot be reselected
  • If the new kernel must be removed, uninstall the package
  • Return the node to service with pcs node unstandby <node> before leaving the maintenance window, whether the upgrade succeeded or was rolled back

6 · Escalation

When the runbook isn't enough, contact:

  • · If the new kernel does not boot, escalate to the platform team
  • · If a regression is observed in production, escalate immediately
  • · If the rollback fails, escalate to support

This runbook covers a rolling kernel upgrade on a cluster node by node. The procedure is the production discipline for kernel maintenance.

When to use this runbook

Use this runbook when:

  • A security update requires a kernel upgrade.
  • A new kernel feature is needed.
  • A driver or hardware change requires a newer kernel.
  • The new kernel has been tested in staging.

Inputs

Gather before starting:

  • The target kernel version.
  • The cluster name and node names.
  • Out-of-band access (BMC, console).
  • A maintenance window (typically 24+ hours per node).
  • Communication channels.

Procedure

Step 1: Capture baseline

Read-only / Safeuname
# Current kernel
uname -r > /tmp/kernel-before.txt

# Cluster status
sudo pcs status > /tmp/cluster-before.txt

# Service health
curl -sf http://<vip>/health > /tmp/health-before.txt

Step 2: Configure GRUB for fallback

Read-only / Safegrubby
# Note the current default kernel
sudo grubby --default-kernel
sudo grub2-editenv list | grep saved_entry

# List every bootable kernel entry
sudo grubby --info=ALL | grep -E '^(index|kernel|title)='

# Explicit gate: the currently RUNNING kernel must still have an entry
running=$(uname -r)
sudo grubby --info=ALL | grep -q "vmlinuz-${running}" \
&& echo "FALLBACK OK: ${running} is still bootable" \
|| { echo "ABORT: no fallback entry for ${running}"; exit 1; }

The old kernel is the safety net. Confirm it is still in the menu before proceeding. This is a gate, not a note: if the ABORT branch fires, stop the change. dnf prunes old kernels once installonly_limit is reached, so a node that has been patched several times may have no fallback left.

Step 3: Drain node1 (canary)

Cluster-wide riskpcs node
sudo pcs node standby node1 --wait=300
sudo pcs status nodes

Verify resources have migrated. Node1 must appear under Standby, and every resource must be running on node2 or node3.

Standby is a node attribute in the CIB. It survives the reboot. Node1 will come back as Online (standby) and will host nothing until you clear it in Step 7. That is the point of the drain, and it is also the trap: nothing clears standby for you.

Step 4: Install the new kernel on node1

Configuration changednf install
sudo dnf install kernel

Step 5: Reboot node1

Service impact possiblereboot
sudo reboot

Wait for the host to come back. SSH in and verify.

Step 6: Validate node1

Read-only / Safeuname
uname -r
# New kernel

sudo pcs status nodes
# Node1 rejoined the cluster, still listed under Standby

# Cluster-level health, served by node2 and node3
curl -sf http://<vip>/health

# Latency
time curl -sf http://<vip>/

# Logs
sudo journalctl -k --since "5 minutes ago" | grep -i error

Node1 is back in the membership but still drained, so these checks prove the new kernel boots and the cluster stack starts. They do not yet prove node1 can carry the workload. That is Step 7.

If validation fails, roll back:

Service impact possiblegrubby
# 1. Identify the known-good kernel entry
sudo grubby --info=ALL | grep -E '^(index|kernel|title)='

# 2. Make the OLD kernel the PERSISTENT default (survives every future boot)
sudo grubby --set-default /boot/vmlinuz-<old-version>
sudo grubby --default-kernel        # verify it took

# 3. Reboot
sudo reboot

# 4. After boot, confirm running == intended
uname -r
sudo grubby --default-kernel

# 5. Prevent recurrence: the bad kernel must not be reselectable
sudo dnf remove kernel-core-<bad-version>
# or, if it must stay installed:
sudo dnf versionlock add kernel-<good-version>

Verify the rollback. Leave node1 in standby while it is rolling back, then clear standby in Step 7 once the old kernel has booted and validated. A rolled-back node still has to go back into service.

Step 7: Return node1 to service

Cluster-wide riskpcs node
sudo pcs node unstandby node1 --wait=300
sudo pcs status nodes
# node1 must be listed under Online, and under no Standby line

sudo pcs status
# Resources placed on node1

The node is only upgraded when it is carrying resources again. Until unstandby runs, node1 is a spare that costs capacity and gives nothing back, and the cluster is running on the remaining nodes with no headroom.

Do not proceed to node2 until node1 is out of standby. If you drain node2 while node1 is still drained, a three-node cluster is down to one node, and the third drain takes the service down completely.

Step 8: Hold for 24 hours

After node1 is back in service, hold for 24 hours. Monitor:

  • Error rates.
  • Performance.
  • Health check status.

The hold only counts while node1 is carrying live traffic. A drained node under no load proves nothing.

If any regression, roll back immediately.

Step 9: Update node2 and node3

Repeat the full procedure for node2 and node3, one at a time, with 24-hour holds. The full procedure is: drain, install, reboot, validate, unstandby, hold. Each node returns to service before the next is drained.

Step 10: Final validation

After all nodes updated:

Read-only / Safepcs status
# All nodes online, no node left in standby
sudo pcs status nodes

# All resources running and spread across the nodes
sudo pcs resource status

# Synthetic monitoring
curl -sf http://<vip>/health

The Standby line in pcs status nodes must be empty. If a node name is still on it, that node is online, patched, and idle, and the cluster has less capacity than the change record claims.

Step 11: Document

In the change log:

  • Time of upgrade.
  • Old and new kernel versions.
  • Nodes updated.
  • Validation results.
  • Confirmation that no node was left in standby.
  • Confirmation that each node’s persistent default kernel (grubby --default-kernel) matches the kernel it is running.
  • Rollback tested.

Common patterns

SymptomLikely causeResolution
New kernel does not bootDriver or initramfs issueRoll back; investigate
Rolled-back node returns to the bad kernel weeks laterRollback used one-shot grub2-reboot onlygrubby --set-default /boot/vmlinuz-<good>; remove or version-lock the bad package
grub2-reboot appears to do nothingGRUB_DEFAULT=saved not set in /etc/default/grubSet it, run grub2-mkconfig -o the active config, retest in staging
Network interface renamedPredictable naming changeUpdate network config; rename or disable
Service fails post-rebootModule not loadedLoad module; rebuild initramfs
Performance regressionDriver bugRoll back; file upstream bug
Node online but hosts nothingLeft in standby after the rebootpcs node unstandby <node>; recheck pcs status nodes
Resources will not start anywhereEvery node drainedpcs node unstandby --all; then re-drain one node at a time

Knowledge check

Knowledge check · 7 questions

  1. Q1. What is the first step in a kernel upgrade?

  2. Q2. A kernel upgrade does not require a reboot.

  3. Q3. Which of the following are valid for kernel upgrade? Select all that apply.

  4. Q4. Node1 has rebooted onto the new kernel and pcs status shows it as Online (standby). What must happen before node2 is drained?

  5. Q5. A cluster can be fully down while pcs status reports every node as Online.

  6. Q6. You rolled a node back with grub2-reboot, it booted the old kernel, validation passed and you closed the incident. Three weeks later the same regression reappears on that node after an unrelated power event. What happened?

  7. Q7. On RHEL 8 and 9 a check that scrapes /boot/grub2/grub.cfg prints nothing even when a fallback kernel entry is present and bootable.

Passing score: 75%. Answers are checked in this browser.

References

  1. Linux kernel administration guide
  2. dracut(8) - rebuilding the initramfs