Ubuntu系统中,apt-check负责检测可用的安全更新并通过motd(message of the day)提示管理员,而unattended-upgrades则负责在后台自动下载并安装这些更新。两者协同工作的核心逻辑是:apt-check扫描更新状态并写入标记文件,unattended-upgrades读取这些标记文件来决定是否执行自动安装。如果你发现系统提示有安全更新但没有自动安装,或者自动更新行为异常,问题几乎都出在这两个组件的配置衔接上。下面我会从原理、配置、排障、最佳实践四个层面把这件事讲透。

一、apt-check和unattended-upgrades各自干什么

apt-check是一个定时任务脚本,默认通过systemd timer(apt-daily.timer和apt-daily-upgrade.timer)每天运行。它的工作就是调用apt-get update刷新包索引,然后比对当前已安装包和可用更新包,把结果写入/var/lib/apt/periodic/目录下的状态文件。具体来说,它会生成update-success-stamp(表示索引刷新成功)和upgrade-available(表示有可升级的包)这类标记文件。

unattended-upgrades是一个独立的守护进程,它会定期扫描/var/lib/apt/periodic/目录下的标记文件。一旦检测到有安全更新可用且符合自动安装策略,它就会调用apt-get install -y自动完成下载和安装,安装完成后还会清理旧内核、重启相关服务。整个过程不需要人工干预,这就是"无人值守升级"的含义。

二、两个组件的协同机制详解

协同的关键在于状态文件的传递。apt-check运行后,如果发现有安全更新,会在/var/lib/apt/periodic/upgrade-available中记录信息。unattended-upgrades的主循环会读取这个文件,判断是否需要触发安装。具体流程如下:

apt-check运行 → apt-get update刷新索引 → 比对包版本 → 写入upgrade-available
       ↓
unattended-upgrades读取upgrade-available → 匹配Allowed-Origins规则 → 执行apt-get install -y
       ↓
安装完成 → 清理 → 记录日志到/var/log/unattended-upgrades/

这里有一个容易被忽略的细节:apt-check本身并不执行安装,它只是"报信"。真正干活的是unattended-upgrades。所以如果你只看到motd提示"有X个安全更新可用"但系统没有自动装,那大概率是unattended-upgrades没有被正确触发,或者它的规则过滤掉了这些更新。

三、核心配置文件解读

要让两者完美配合,你需要关注两个配置文件。第一个是/etc/apt/apt.conf.d/20auto-upgrades,控制apt-check的行为:

APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Unattended-Upgrade "1";
APT::Periodic::AutocleanInterval "7";

Update-Package-Lists设为1表示每天刷新包列表,Unattended-Upgrade设为1表示允许自动升级检查。如果你把Unattended-Upgrade改成0,apt-check仍然会检测更新但不会触发后续自动安装流程。

第二个是/etc/apt/apt.conf.d/50unattended-upgrades,这是unattended-upgrades的核心规则文件。里面最关键的是Allowed-Origins字段:

Unattended-Upgrade::Allowed-Origins {
    "${distro_id}:${distro_codename}-security";
    "${distro_id}:${distro_codename}-updates";
};

这段配置的意思是:只自动安装来自安全仓库和更新仓库的包。如果你的apt源里有第三方PPA或者其他非官方源,这些源的更新默认不会被自动安装,除非你手动加进去。很多人遇到"明明有更新但不自动装"的问题,就是因为Allowed-Origins没有覆盖到对应的源。

四、常见问题排查与解决

问题一:motd一直提示有安全更新但从不自动安装。首先检查unattended-upgrades是否在运行:

systemctl status unattended-upgrades.service

如果显示inactive或failed,执行systemctl enable --now unattended-upgrades启动它。然后查看日志:

cat /var/log/unattended-upgrades/unattended-upgrades.log | tail -50

日志里会明确告诉你为什么没有安装,常见原因包括"No packages found that can be upgraded unattended"(没有符合规则的包)或者"Packages with unmet dependencies"(依赖问题)。

问题二:apt-check和unattended-upgrades时间冲突。两者都有自己的定时器,apt-daily-upgrade.timer默认每天凌晨6点运行,unattended-upgrades.timer默认在apt-daily-upgrade之后30分钟运行。如果你发现更新被重复检测或者时间错乱,可以用以下命令查看和调整:

systemctl list-timers | grep apt
systemctl edit apt-daily-upgrade.timer

问题三:自动更新导致服务异常。这种情况通常发生在内核更新后需要重启但系统没有自动重启。可以在50unattended-upgrades中配置:

Unattended-Upgrade::Automatic-Reboot "true";
Unattended-Upgrade::Automatic-Reboot-Time "02:00";

这样系统会在凌晨2点自动重启,避免影响业务时段。

五、生产环境最佳实践

在生产服务器上,我建议采取分层策略。第一层:保持apt-check每天运行但不直接触发安装,而是让它只负责检测和记录。第二层:unattended-upgrades只处理安全更新(security),普通更新(updates)改为手动审核后批量安装。配置如下:

Unattended-Upgrade::Allowed-Origins {
    "${distro_id}:${distro_codename}-security";
};
Unattended-Upgrade::Mail "admin@example.com";
Unattended-Upgrade::MailReport "always";

这样每次自动安装后你都会收到邮件通知,方便追踪。第三层:对于关键业务机器,建议在/etc/apt/preferences.d/中设置包锁定,防止某些核心包被意外升级:

Package: nginx
Pin: version 1.22.*
Pin-Priority: 1001

第四层:定期手动运行一次完整的更新流程做验证:

apt-get update
apt-get upgrade --dry-run
unattended-upgrades --dry-run --debug

dry-run模式不会实际执行任何操作,但会告诉你如果执行会发生什么,这是上线前必做的检查。

六、版本差异与注意事项

Ubuntu 20.04和22.04在这套机制上有细微差别。22.04开始,apt-check的输出更简洁,motd信息从完整列表改成了摘要提示。另外,22.04引入了needrestart机制,如果更新涉及到需要重启的服务,系统会在motd中额外提示。unattended-upgrades在22.04上默认启用,但在最小化安装的服务器镜像中可能没有预装,需要手动apt install unattended-upgrades。

还有一点值得注意:如果你使用的是容器化部署(比如Docker容器跑Ubuntu),apt-check和unattended-upgrades默认都不会在容器内自动运行,因为容器的设计哲学就是不可变基础设施。在这种场景下,你应该在Dockerfile层面控制更新策略,而不是依赖运行时的自动升级机制。

七、总结

apt-check和unattended-upgrades的协同本质上是一个"检测-执行"的流水线。apt-check负责感知,unattended-upgrades负责行动,中间通过状态文件和规则配置串联。理解了这个架构,你就能精准控制哪些更新自动装、什么时候装、装完怎么处理。对于运维人员来说,与其盲目信任自动更新,不如花十分钟把规则配好、把日志监控接上,让这套机制真正成为安全保障而不是潜在风险。