暗色模式

Linux 软件包管理:从 apt 软件源到 dpkg 包管理

技术教程
2026-08-13
8
0
本文要点
  • Ubuntu 的软件包体系分两层:底层 dpkg 直接操作 .deb 包,上层 apt 负责依赖解析与软件源管理,日常操作基本都用 apt
  • Ubuntu 24.04 的软件源采用 deb822 格式/etc/apt/sources.list.d/ubuntu.sources),结构更清晰;老格式 sources.list 仍然兼容
  • apt update 刷新软件源索引,apt upgrade 升级已装包,两者顺序不能颠倒;升级前建议先 apt list --upgradable 预览
  • 卸载分两级:apt remove 保留配置文件,apt purge 连配置一起删除;apt autoremove 清理无用依赖
  • dpkg -l / -s / -S / -L 分别查询已装列表、包状态、文件归属、包内文件清单;本文命令均在 Ubuntu 24.04 上真实执行验证

apt 与 dpkg:两层包管理

大多数 Linux 用户对 Ubuntu 的印象是从「双击安装包」或「一行命令装软件」开始的,而这两件事背后是两套分工明确的工具:

  • dpkg:Debian 系最底层的包管理器,直接操作 deb 包文件,负责安装、卸载、查询。但它不处理依赖关系——装 A 需要 B 时,它不会自动帮你把 B 一起装上。
  • apt:构建在 dpkg 之上的高级工具。它读取软件源索引,解析依赖树,把「要装一个软件」翻译成「要装这一组 deb 包」,再交给 dpkg 落地执行。

用一句话概括:apt 管「要装什么」,dpkg 管「怎么装」。 日常运维 90% 的操作发生在 apt 这一层,但排查问题时经常要下钻到 dpkg——这也是这篇文章把两层都讲清楚的原因。

apt 的完整文档可参考 Ubuntu 官方 Apt 文档

软件源:包从哪来

apt 安装的软件来自「软件源(repository)」。Ubuntu 把官方软件源按「套件(Suite)× 组件(Component)」切成网格,软件源配置就是告诉 apt 去哪里、拉哪些网格。

deb822 格式:Ubuntu 24.04 的默认配置

从 Ubuntu 22.04 起,系统默认使用 deb822 格式管理软件源,配置文件在 /etc/apt/sources.list.d/ubuntu.sources。下面这张图是在演示服务器(Ubuntu 24.04)上执行 grep 过滤掉注释后的真实内容:

deb822 软件源配置与 apt-cache policy 输出

图中每一条「源」由几个字段组成,含义如下:

  • Types:包类型。deb 是二进制包,如需下载源码包则追加 deb-src
  • URIs:仓库服务器地址,本机是 archive.ubuntu.com(主源)和 security.ubuntu.com(安全更新源)。
  • Suites:套件名。Ubuntu 24.04 代号 noblenoble 是正式发布版,noble-updates 是修复补丁,noble-backports 是向后移植的新版软件。
  • Components:组件。main(官方维护、完全免费)、universe(社区维护)、restricted(含专有驱动)、multiverse(法律受限软件)。
  • Signed-By:仓库签名公钥,apt 用它校验下载的包是否被篡改。

图中下方的 apt-cache policy 输出则展示了 apt 对每个源的「优先级」:数字越大优先级越高,500 是常规源,100 是本机已装状态。多个源提供同一软件时,apt 会优先用优先级高的版本。

deb822 的完整字段说明可参考 sources.list(5) 手册页

老式 sources.list 格式

如果你看到的还是 /etc/apt/sources.list 单行格式,那也一样有效:

deb http://archive.ubuntu.com/ubuntu noble main universe restricted multiverse
deb-src http://archive.ubuntu.com/ubuntu noble main universe restricted multiverse

每行开头是 deb(或 deb-src),中间是仓库地址,后面依次是发行版代号和组件列表。deb822 格式本质上就是这种单行格式的「结构化拆解」,两者可以共存。

手动增删软件源

需要添加第三方源时,推荐的做法是单独建文件、单独配签名,这样卸载时删除对应文件即可,互不干扰:

# 添加 GitHub CLI 官方源(示例)
curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | sudo tee /etc/apt/keyrings/githubcli-archive-keyring.gpg > /dev/null
echo "deb [arch=amd64 signed-by=/etc/apt/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" \
  | sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null
sudo apt update

apt update / upgrade:更新系统

新装或修改软件源后,第一件事是 apt update——它从所有已配置的源拉取最新的包索引:

sudo apt update

看到 Reading package lists... Done 以及最后的 All packages are up to date(或可升级数量),说明索引刷新成功。注意:update 只是更新索引,并不会升级任何软件。

真正升级已装包的是 apt upgrade。升级前建议先预览有哪些可升级:

apt list --upgradable
sudo apt upgrade

几点实用经验:

  • 先 update 再 upgrade:索引没刷新就 upgrade,装的是旧索引里的旧版本,等于白做。
  • 升级内核apt upgrade 升级内核后,需要重启系统新内核才生效,可用 uname -r 确认当前内核版本。
  • 只升级安全更新:如果不想被普通更新打扰,可以用 sudo apt update && sudo apt upgrade --only-upgrade 配合套件筛选,或直接用 unattended-upgrades 做全自动安全更新。

apt install:安装与依赖解析

安装软件是 apt 最常见的用法。下图是演示服务器上 apt-get install -y tree 的真实执行过程(tree 是一个以树状图显示目录结构的工具):

apt install 安装 tree 包的完整过程

安装输出的关键行值得逐条读一遍:

  1. Reading package lists...Building dependency tree...:apt 读取索引、构建依赖树,这是「自动解析依赖」的开始。
  2. The following NEW packages will be installed: tree:apt 告诉你本次要装的包列表。没有依赖要额外安装时,列表只有它一个。
  3. 0 upgraded, 1 newly installed, 0 to remove and 5 not upgraded.:升级 0 个、新装 1 个、移除 0 个;末尾的 5 not upgraded 表示还有 5 个包因依赖等原因暂未升级。
  4. Preparing to unpack / Unpacking tree ...:dpkg 层面开始解包。
  5. Setting up tree ...:解包完成后的配置阶段,此时软件才真正可用。
  6. Processing triggers for man-db ...:处理触发器,如刷新 man 手册索引。

如果某个软件依赖了多个包,你会看到列表变成好几行,apt 会一次性把依赖全部装好,这正是它比 dpkg 好用的地方。

# 同时安装多个包
sudo apt install htop curl jq
# 只下载不安装(-d = download)
sudo apt install -d htop
# 重新配置已安装包的配置向导
sudo dpkg-reconfigure tzdata

卸载与清理

卸载同样走 apt 这一层,但要知道「删配置」和「删干净」是两件事:

# 卸载软件,保留配置文件(重新安装时配置还在)
sudo apt remove tree
# 卸载并连配置文件一起删除
sudo apt purge tree
# 清理因依赖装上来、现在没用的软件包
sudo apt autoremove
# 清理下载缓存(/var/cache/apt/archives)
sudo apt clean

什么时候用 purge 卸载服务类软件(nginx、mysql 等)后,它们通常会把配置和数据留在 /etc/var 下,重装时可能读到旧配置导致「装了等于没装」。此时用 purge 更干净。只卸工具类软件用 remove 即可。

apt 查询:装之前先看看

安装前用 apt-cache 系列命令侦察一下,能避免很多「装错版本」的问题:

# 搜索软件包
apt-cache search "pdf 编辑器"
# 查看包详情:版本、依赖、大小、描述
apt-cache show htop
# 查看安装/候选版本与优先级
apt-cache policy htop
# 查看某个包依赖什么
apt-cache depends htop

apt-cache policy 输出里两个数字最关键:Installed(已装版本)和 Candidate(可升级到的版本)。候选版本往往决定着你能不能用上某个新功能。

dpkg:包管理的「底层机关」

apt 只管上层编排,真正的安装、查询、卸载动作都落在 dpkg 上。当需要精确控制单个 deb 包时,直接操作 dpkg 更顺手。下图是在演示服务器上对 tree 做的三种查询:

dpkg 查询:包状态、文件归属与文件清单

逐条解释图中命令:

  • dpkg -s tree(query status):显示包的状态与元信息。Status: install ok installed 里三段分别表示「期望状态=已安装」「实际状态=正常」「错误=无」。Installed-Size: 108 是占用磁盘大小(KB),Version 是当前版本号。
  • dpkg -S /usr/bin/tree(search):反查「某个文件属于哪个包」,排查「这个文件是哪来的」时非常有用。
  • dpkg -L tree(list files):列出包安装后包含了哪些文件,包括二进制、文档和 man 手册。看到 /usr/share/man/man1/tree.1.gz 就能确认手册页已就位。

其他高频 dpkg 命令:

# 查看已安装的所有包(-l = list),管道 grep 按名筛选
dpkg -l | grep htop
# 列出某个包的版本与状态简表
dpkg -l htop
# 安装本地 .deb 文件(不解析依赖,需自行保证依赖已装)
sudo dpkg -i 某软件.deb
# 卸载本地安装的包
sudo dpkg -r 包名
# 检查包是否完好(校验文件完整性)
sudo dpkg -V 包名

注意 dpkg -i 不处理依赖——直接装一个带依赖的 .deb 会报依赖缺失。想用本地 .deb 又不想手动装依赖,可以先 sudo dpkg -i 文件.deb 再用 sudo apt -f install 让 apt 补齐缺失的依赖。

常用组合与排查技巧

把 apt 和 dpkg 串起来,能解决绝大多数包管理问题:

# 1. 依赖损坏修复:装一半断了,用 -f 修复
sudo apt -f install

# 2. 锁定版本:防止某个包被 upgrade 误升级
sudo apt-mark hold nginx
apt-mark showhold          # 查看被锁定的包
sudo apt-mark unhold nginx # 解除锁定

# 3. 列出某个已装包的确切版本
dpkg-query -W -f='${Version}\n' nginx

# 4. 查看 apt 操作历史日志
grep -E "^(Start|Commandline|Install|Remove|Upgrade)" /var/log/apt/history.log

常见故障定位顺序:先 apt update 看索引是否正常 → 报依赖错误就 apt -f install → 还不行就 apt-cache policy 包名 看版本来源 → 最后用 dpkg -l 包名 确认实际状态。绝大多数「装不上」的问题都能在这个循环里解决。

总结

Ubuntu 的包管理是一套清晰的上下层协作:apt 负责软件源与依赖解析,dpkg 负责对 deb 包的落地操作。日常用 apt update/install/remove/upgrade 四个命令就能覆盖大部分场景,遇到依赖或本地 deb 包问题再下钻到 dpkg -i/-r/-l/-S/-L。掌握这套体系,就掌握了 Ubuntu 运维的最基础也是最常用的一环。

更多细节可参考 Ubuntu 官方软件包管理文档dpkg(1) 手册页

发表评论

暂无评论,快来抢沙发吧!