打死不宕机:Linux 系统内核免重启升级(Kexec 快速切换与 Canonical Livepatch 热补丁)

更新内核必须重启?未必。本文手把手教你用 kexec 几秒切到新内核,以及用 Canonical Livepatch/kpatch 给运行中内核打热补丁,关键 VPS 节点从此不宕机。

每次 apt upgrade 蹦出 linux-image 更新,你是不是都一阵胃疼?因为按老黄历,装完新内核必须 reboot,一重启服务器就黑屏个几分钟,上面的网站、数据库、游戏服全跟着断。要是你这台机器挂着 100% SLA 的承诺,或者跑着不能停的实时业务,这种"计划内重启"也照样是事故。好消息是:现代 Linux 早就不用这么粗暴了。这篇讲两套方案,一套叫 kexec,几秒钟把新内核切上去;另一套叫 Livepatch(Ubuntu 上是 Canonical Livepatch,红帽上是 kpatch),直接在跑着的内核上打补丁,连一秒钟都不停。下面一步一步来。

延伸阅读

更多相关攻略推荐:高级玩家玩出花:如何在 VPS 上广播自己的 IP 地址?BYOIPWeb 与数据库分在两台 VPS?跨机房 MySQL 3306 安全【VPS 进阶玩法精选 011】VPS 上 MySQL / PostAWS / GCP 的"出站流量税":云巨头按 GB 扣费解析与 B【TCP优化 02】为什么晚高峰 Ping 值正常,SSH 却卡到掉

传统内核升级的痛点:为什么重启这么要命

先说清楚 reboot 到底卡在哪。一台正经服务器执行 reboot,流程是:CPU 复位 → BIOS/UEFI 做加电自检(POST)→ 网卡、RAID 卡、NVMe 这些外设挨个初始化 → GRUB 选内核 → 新内核再做一遍硬件探测和驱动加载。在有 512G 内存、带 RAID 卡和一堆 10G 网卡的机器上,光硬件那一段就能吃掉 5 到 8 分钟。我见过有朋友在数据库上发完 reboot,监控直接炸出 P1 告警,因为那 9 分钟的空窗期里服务就是不可用的。

对 VPS 来说虽然没有真 BIOS,但底层宿主的虚拟化初始化、再加上你这台虚机内部的内核启动,实测也得几十秒到几分钟,而且这段时间里 TCP 连接全断、对外不可达。如果你的 uptime 合同写的是"月度可用率 99.95%",一次重启就可能把整月的余量吃掉一大块。所以"怎么少重启、甚至不重启地换内核/修内核",是运维绕不开的功课。

方案 1:kexec,跳过 BIOS 几秒切到新内核

kexec 是 Linux 内核自带的一个系统调用,作用是:让正在跑的内核,直接把另一个新内核加载进内存,然后跳过去执行,全程不经过 BIOS/UEFI、不经过 GRUB、不做硬件 POST。正常启动是"BIOS → GRUB → 内核",kexec 启动是"老内核 → 直接跳新内核",中间的固件初始化整段被砍掉,重启时间从几分钟压到几秒到十几秒。它不是"零停机"——切的那一下 SSH 会断、连接会闪断,但比完整冷启动快一个数量级,适合"我想换内核版本,但要快"。

原理上,kexec 分两个阶段。第一阶段的 kexec -l 把新内核镜像和 initramfs 装进预留的内存区域(并不执行);第二阶段 kexec -e 让当前内核关掉设备、关中断,直接跳到新内核的入口点。因为硬件根本没掉电,CPU 也不会回到复位向量,相当于"给服务器换脑子,身子还醒着"。它底层依赖内核的 CONFIG_KEXEC 选项,主流发行版(Ubuntu/Debian/RHEL 系)默认都开着。

动手前先装工具包:

sudo apt update
sudo apt install -y kexec-tools

装的时候 Debian/Ubuntu 会问你"是否让 kexec-tools 接管重启",一般选是,这样以后 systemctl reboot 也会优先走 kexec。然后看看 /boot 下有哪些内核:

ls /boot/vmlinuz* /boot/initrd.img*

假设你刚 apt install 了一个新内核,比如 vmlinuz-6.8.0-45-generic,先把新内核加载进内存(注意 --reuse-cmdline 会沿用当前内核的启动参数,比如根分区 UUID,这个几乎总是你想要的):

sudo kexec -l /boot/vmlinuz-6.8.0-45-generic \
  --initrd=/boot/initrd.img-6.8.0-45-generic \
  --reuse-cmdline

加载完可以用一个虚拟文件确认状态,返回 1 表示已就绪:

cat /sys/kernel/kexec_loaded

确认无误后,执行切换:

sudo kexec -e

你的 SSH 会瞬间断开,等个十几秒再连,uname -r 一看已经是新内核了。更省事的做法是用 systemd 封装的命令,效果一样:

sudo systemctl kexec

几个坑提醒你:第一,kexec -e 是不可逆的硬切换,执行前务必确认新内核和 initrd 版本对得上,否则可能起不来;第二,它仍会造成短暂断流,不是真·零停机,对"绝对不能闪断"的业务别单独指望它;第三,如果机器开了 Secure Boot,需要内核镜像带可信签名(CONFIG_KEXEC_VERIFY_SIG),否则加载会被拒;第四,想用 kexec 顺手做崩溃捕获(kdump),得在 GRUB 里预留 crashkernel= 内存。

方案 2:Canonical Livepatch / kpatch,运行中打热补丁

如果你要的不是"换内核版本",而是"有个内核漏洞得赶紧修",那 kexec 还是得重启,不够优雅。这时候上 Livepatch:它直接在正在跑的内核内存里,把有漏洞的函数替换成修好的版本,整个过程不重启、不断连、不丢一个 TCP 连接,是真正的零停机。Ubuntu/Debian 阵营叫 Canonical Livepatch,红帽/RHEL 阵营叫 kpatch,原理一模一样。

原理上,Livepatch 做的是"函数级替换":用内核的 ftrace 子系统,把对某个旧函数的调用"拐弯"到补丁里的新函数上。补丁本身是一个小的内核模块(.ko),由官方针对特定内核版本精心编译、累计叠加(后面的补丁包含前面所有修复,所以回滚基本不需要)。要注意它只修"安全类"漏洞(高/严重级别的 CVE,比如提权、远程代码执行),不修驱动、不升级内核大版本、不动内核数据结构,所以它顶多帮你把"紧急重启"变成"下次维护窗口再重启",而不是永远不重启。

Ubuntu 上开启 Livepatch 最简单(免费额度是个人用途最多 5 台机器)。先去 Ubuntu Livepatch 官网用 Ubuntu One 账号领一个 token,然后:

sudo snap install canonical-livepatch
sudo canonical-livepatch enable YOUR_TOKEN_HERE
sudo canonical-livepatch status --verbose

status 里看到 "patch state: all applicable livepatch kernel modules applied" 就说明补丁已经生效,全程没重启。如果你用的是带 Ubuntu Pro 订阅的机器(免费个人版也覆盖),更标准的姿势是:

sudo pro attach YOUR_PRO_TOKEN
sudo pro enable livepatch
sudo canonical-livepatch status

红帽系(RHEL 9 及同类)走 kpatch,需要有效的订阅,用 DNF 插件管理:

subscription-manager status
sudo dnf install -y kpatch-dnf
sudo dnf kpatch auto
sudo kpatch list

dnf kpatch auto 是关键,它把当前运行的内核订阅到 live patching 流,以后有补丁跟着普通 dnf update 一起自动装上。kpatch list 能看到补丁已加载,而且有个贴心细节:kpatch.service 会在你因别的原因重启后,自动把补丁重新应用回同一个内核,保护不丢失。

举个真实例子感受下 Livepatch 的威力:2016 年的 Dirty COW 漏洞(CVE-2016-5195)能让任意本地普通用户几秒内拿到 root 权限,几乎波及当时所有 Linux 版本,危害极大。Canonical 在漏洞公开后几小时内就编译好 livepatch 并推送到所有开启服务的机器上,用户在后台无感知地就被保护住了,完全不需要半夜爬起来重启。这还不是孤例,这些年 Ubuntu 上那些高危内核提权漏洞,大多都在公开当天或次日就有了可用的 livepatch。换句话说,只要你的机器开着服务、内核在支持列表里,漏洞当天就被修好、业务一秒不停,就是 Livepatch 的日常。反过来看,如果你的发行版或内核版本不在官方支持矩阵里,Livepatch 就帮不上忙,这时还是得靠 kexec 这类快速切换,或者老老实实挑窗口重启。

两套方案怎么选?关键 VPS 节点的建议

一句话总结区别:kexec 解决"换内核版本要快",Livepatch 解决"修漏洞不要停"。它们是互补的,不是二选一。

对一台要保 100% SLA 的关键节点(比如 Hetzner 的独立机、Contabo 的大内存实例、DigitalOceanVultr 上跑核心服务的 VPS),推荐的组合拳是:平时开着 Livepatch,一旦爆出内核 CVE,几分钟内后台自动把补丁打上,业务完全无感,你不必半夜爬起来重启;等到下个计划维护窗口,再用 kexec 把内核真正升级到带修复的新版本并完成切换,这样既守住了安全,又完成了该做的版本演进。

选型上还有几点实在建议:优先选 Ubuntu LTS(20.04/22.04/24.04)或 RHEL 系镜像,Livepatch/kpatch 支持最完整;CentOS Stream、Debian 也能用 kexec,但 Livepatch 的官方覆盖以 Ubuntu 最佳;小内存、单实例的廉价 VPS 如果跑的不是关键业务,老老实实挑个低峰 reboot 反而最省心,没必要上这套复杂机制。最后强调一遍:Livepatch 帮你买的是"时间",不是"永生",该重启的新内核版本最终还是要重启,只是把紧迫感去掉了而已。

写在最后

内核升级不再等于宕机,这件事本身就值回票价。先用 kexec 把"换内核从几分钟压到几秒"跑通,再给关键机器挂上 Livepatch/kpatch 做"漏洞热修兜底",你的 VPS 就能在安全和在线率之间两头讨好。还是那句老话:动内核前先快照、先在测试机验证,别拿生产环境练手。稳,才是不宕机的真正秘诀。

常见问题 FAQ

问:kexec 和 Livepatch 有什么区别?? kexec 是绕过 BIOS 直接把新内核载入内存并切换,几秒完成、需要一次进程重启但主机不黑屏断电;Livepatch(Ubuntu 的 Canonical Livepatch、RHEL 的 kpatch)是在运行中的内核上热打补丁,连一秒都不停。前者换整内核,后者只修特定漏洞,适合不同停机容忍度。

问:怎么用 kexec 快速切内核?? 装好新 linux-image 后,用 kexec -l 载入新内核与 initrd,再 kexec -e 切换(需 root)。系统会直接跳到新内核,跳过 POST。注意:它不自动迁移全部状态,部分服务仍需重启;务必先在测试机验证,并做好回滚预案。适合能接受极短中断、但要避免整机断电的场景。

问:Livepatch 能修所有漏洞吗?? 不能。Livepatch 只覆盖可被热补的缺陷(多数高危内核 CVE),涉及复杂数据结构或语义大改的漏洞仍需完整重启内核。免费档常限台数(如 Ubuntu 个人 3 台)。把它当「争取时间」的手段:先热修止血,再排期在低风险窗口做正式 reboot 升级。