Debian系统中unattended-upgrades自动移除旧内核的问题,直接表现为系统更新后旧内核文件未被清理,导致/boot分区被占满,进而引发系统启动失败或更新错误。解决方法是通过配置unattended-upgrades和APT钩子脚本,在自动更新时安全删除旧内核,同时保留当前和上一个备用内核以确保系统可回退。

理解unattended-upgrades与内核保留机制

unattended-upgrades是Debian和Ubuntu系统中用于自动安装安全更新的工具,默认配置下它会自动升级内核包,但不会自动移除旧内核文件。这是因为内核删除涉及系统核心组件,不当操作可能导致系统无法启动。Debian的APT包管理器通常保留多个旧内核版本,这虽然增加了安全性,但也容易让/boot分区(通常单独分区且空间有限)快速耗尽。你需要明确:unattended-upgrades本身不处理旧内核删除,这需要通过额外的APT钩子或定期任务来实现。

检查当前内核与/boot分区状态

在配置前,先查看系统内核状态和磁盘使用情况。使用以下命令列出已安装内核:

dpkg --list | grep linux-image

查看/boot分区空间:

df -h /boot

如果/boot使用率超过90%,就需要立即清理。注意:不要手动删除内核文件,而应使用包管理命令,避免破坏依赖关系。

配置unattended-upgrades启用自动删除

Debian的unattended-upgrades配置目录为/etc/apt/apt.conf.d/。编辑或创建配置文件50unattended-upgrades,确保以下选项启用:

Unattended-Upgrade::Remove-Unused-Kernel-Packages "true";
Unattended-Upgrade::Remove-Unused-Dependencies "true";

这两个选项让系统在自动升级后删除未使用的内核包和依赖。但仅此还不够,因为它可能不会删除所有旧内核文件,尤其是当/boot分区使用extlinux或GRUB时,需要结合APT钩子。

设置APT钩子脚本自动清理旧内核

APT钩子脚本可以在APT操作完成后触发自动清理。创建文件/etc/kernel/postinst.d/apt-auto-removal,内容如下:

#!/bin/sh
# 脚本保留当前内核和上一个备用内核
version="$1"
current_kernel="$(uname -r)"
# 获取所有已安装内核列表
installed_kernels=$(dpkg --list | grep -E 'linux-image-[0-9]+' | grep -F ii | awk '{print $2}')
# 标记保留的内核:当前运行内核和最新安装的一个备用内核
保留_kernels="$(echo "$installed_kernels" | sort -V | tail -2)"
# 移除不在保留列表中的旧内核
for kernel in $installed_kernels; do
    if ! echo "$保留_kernels" | grep -q "$kernel"; then
        apt-get purge -y "$kernel"
    fi
done

给脚本添加执行权限:

chmod +x /etc/kernel/postinst.d/apt-auto-removal

此脚本会在每次新内核安装后运行,自动清理除当前和上一个备用内核外的所有旧内核。它通过dpkg列表和版本排序实现精准控制,避免误删。

手动安全清理旧内核的步骤

如果/boot已满导致自动更新失败,需手动清理。首先,使用apt命令删除旧内核包:

sudo apt autoremove --purge

此命令会移除所有自动安装且不再需要的包,包括旧内核。但有时它可能不会清理所有内核文件,这时可以指定删除:

sudo dpkg --list | grep 'linux-image' | awk '{print $2}' | grep -v $(uname -r) | xargs sudo apt-get purge -y

此命令列出所有内核包,排除当前运行内核(uname -r输出),然后批量删除。操作前务必确认当前内核版本,并确保至少保留一个备用内核。

验证配置与监控/boot空间

配置完成后,测试unattended-upgrades的自动删除功能。运行以下命令模拟自动升级:

sudo unattended-upgrade --dry-run --debug

检查输出中是否包含"Removing unused kernel packages"相关提示。此外,设置定期监控/boot分区,可以添加cron任务:

# 每周检查/boot使用率,超过80%时发送警报
echo "0 0 * * 0 df -h /boot | awk '{print \$5}' | grep -o '[0-9]*' | head -1 > /tmp/boot_usage" >> /etc/crontab

结合日志分析,/var/log/unattended-upgrades/unattended-upgrades.log记录了自动更新和删除操作,定期检查可确保机制运行正常。

高级策略:内核保留数量与回滚方案

根据系统关键性调整内核保留数量。对于生产服务器,建议保留至少3个内核(当前内核+两个备用),以提供充分回滚余地。修改APT钩子脚本中的"tail -2"为"tail -3"即可。同时,确保GRUB配置正确显示所有保留内核。编辑/etc/default/grub,设置:

GRUB_DEFAULT=saved
GRUB_SAVEDEFAULT=true

运行update-grub后,系统会在启动菜单显示所有保留内核,方便故障时手动选择旧内核启动。

常见问题与故障排除

1. 自动删除后系统无法启动:通常是因为误删了当前内核或GRUB配置损坏。解决方法是从LiveCD引导,chroot到原系统,重新安装最新内核并更新GRUB。

2. unattended-upgrades未触发删除:检查配置文件语法,确保选项为true而非"true"。查看日志文件/var/log/unattended-upgrades/unattended-upgrades.log,排查错误。

3. /boot分区仍快速填满:可能是旧内核initrd映像未删除。使用命令"sudo update-initramfs -d -k 版本号"手动删除,或调整钩子脚本加入initrd清理。

最佳实践总结

Debian系统自动移除旧内核的关键在于结合unattended-upgrades配置与APT钩子脚本,实现安全自动化。配置后,系统会在每次内核更新后保留至少两个内核版本(当前+备用),自动清理其余旧内核,平衡/boot空间安全与系统可回退性。定期检查日志和磁盘使用率,根据服务器角色调整保留策略,可确保长期稳定运行。记住:永远不要手动删除/boot下的文件,始终通过包管理器操作,避免不可逆的系统损坏。