LabHub
学习 学习路径 课程

包管理

apt 看着什么来判断

在 LabHub 中继续学习

一句话总结

apt 的所有判断都来自本地缓存的软件仓库索引。索引过期,apt 看到的就是过时的世界。

概念图: 本地缓存的软件仓库索引 · 只查看下载到 /var/lib/apt/lists/ 的索引文件 · 读取索引 · 选择候选版本

为什么需要这些知识

执行 apt-get install nginx 后提示“找不到软件包”,但仓库里明明存在。十有八九是因为没有运行 apt-get update

apt 安装时不会直接询问仓库。它只查看下载到 /var/lib/apt/lists/ 的索引文件,据此计算依赖;计算完成后,才真正下载 .deb。这种分离让 apt 运行得更快,也造成了“仓库里有,但本地看不到”的问题。

它是如何运作的

一次安装分为四个阶段。

  1. 读取索引——读取 /etc/apt/sources.listsources.list.d/*.list 所列仓库中的 Packages 文件。
  2. 选择候选版本——同一软件包存在于多个仓库时,根据 **pin 优先级(priority)**选择。apt-cache policy <패키지> 会直接展示判断结果。
  3. 解析依赖——沿着 Depends 和 Recommends 生成安装集合。
  4. 下载并执行 unpack/configure——交给 dpkg 处理。

关键是学会读取 apt-cache policy 输出。

nginx:
  Installed: (none)
  Candidate: 1.24.0-2ubuntu7
  Version table:
     1.24.0-2ubuntu7 500
        500 http://archive.ubuntu.com/ubuntu noble/main amd64 Packages

左侧数字是版本,右侧数字是优先级。默认值为 500,有两种方法可以修改相关行为。

二者用途不同。hold 表示“停留在当前版本”,pin 表示“在多个仓库中优先选择这一侧”。同时使用企业内部 mirror 和官方仓库的环境,必须设置 pin。

在实际工作中会是什么样

Kubernetes 节点上的 kubelet。 为了控制集群版本,apt-mark hold kubelet kubeadm kubectl 实际上已是标准流程。如果没有 hold,某天不经意运行的 apt-get upgrade 可能只把一个节点升级到新的 minor 版本,随后只有该节点无法启动 Pod。

企业内部 mirror 的背叛。 把内部 mirror 加入 sources.list 后,下载仍来自官方仓库。原因是优先级相同时,apt 会选择版本更高的一方。要强制使用 mirror,必须设置 pin。

先弄清 upgrade 会做什么,再执行

apt-get upgradeapt-get dist-upgrade(现在称为 apt full-upgrade)名称相似,行为却不同,而这种差异会在生产环境中引发事故。

因此,生产服务器应分两步执行。先使用 -s 进行模拟,查看会发生哪些变化;确认清单中没有陌生内容后,再真正执行。尤其必须每次阅读 The following packages will be REMOVED 这一行。 依赖混乱时,apt 提出的解决方案有时确实是“删除这个服务”。

还要说明 unattended upgrade。自动应用安全更新通常是正确选择,但如果没有规定如何处理需要重启的更新,就会出现两种结果之一:一直不重启,使更新后的库没有生效,漏洞依然存在;或随时重启,导致服务中断。可以使用工具列出哪些进程仍加载旧版库,再在计划窗口中重启。

最后是 aptapt-get 的区别。人工操作时 apt 更方便,但脚本应使用 apt-getapt 明确声明可能为了便于人类阅读而改变输出格式和行为;一旦格式变化,解析它的脚本就会悄然损坏。

下一次实操要做什么

你将针对 /opt/localrepo 离线仓库进行搜索、安装和删除,亲自设置 hold 与 pin,并观察 apt-cache policy 输出如何变化。