当前位置:首页>Linux>从零构建 Linux|05 包管理

从零构建 Linux|05 包管理

  • 2026-09-09 11:30:11
从零构建 Linux|05 包管理
系列第 5 篇|系统跑起来后,软件是怎么装进去的覆盖 Ubuntu、Debian、CentOS、Fedora;本篇重点讲清 apt

前面四篇解决的是:系统如何从断电变成「能登录、能跑程序」。本篇换一个非常实际的问题:

系统已经跑起来了,我想安装某个软件并运行它——这事在 Linux 上通常怎么做?

在 Ubuntu、Debian、CentOS、Fedora 这类主流发行版上,答案几乎总是:用包管理器。读者后续会在 WSL2 的 Ubuntu 里做 Yocto 构建,日常接触最多的是 apt,因此本篇把 apt 的工作原理、软件源配置、镜像加速讲透;yum / dnf 只作对照。

为什么不能只「拷贝一个二进制」

从 Windows 过来的同学,很容易把安装理解成:下载一个 exe / 绿色文件夹,拷进去就能用。在 Linux 上有时也能这么干,但很快会碰到:

  1. 程序依赖某个 .so 动态库,系统里没有或版本不对;
  2. 升级时不知道旧文件散落在哪些目录;
  3. 卸载时删不干净,或误删了被其它软件共用的库;
  4. 安全更新不知道该更新哪些组件。

包管理器就是为这些麻烦准备的:它不只帮你下载软件,还帮你处理依赖、把文件放到标准位置、记下「到底装过什么」,以便日后升级和卸载。

四个核心概念

概念
含义
软件包(package)
一个软件的「安装包」:里面有程序文件、依赖声明,常常还有安装 / 卸载时执行的脚本
仓库 / 软件源(repository)
一堆软件包 + 索引的存放处。可以在互联网上,也可以是局域网或本地目录
依赖(dependency)
「要装 A,必须先有 B、C」。包管理器会自动把依赖一并装上
本地数据库
系统里记录「已安装哪些包、版本是什么、文件属于谁」的账本。卸载和查询都靠它

可以把仓库想成「应用商店的货架与目录」;把本地数据库想成「你家已经买过什么的收据夹」。

两条主流技术栈

表面上有四个常见发行版,底层其实主要是两套体系:

发行版
日常命令
底层工具
包后缀
Debian
Ubuntu
apt
dpkg
.deb
CentOS
Fedora
yum / dnf
rpm
.rpm

再补充两点避免晕:

  1. apt 与 dpkg 的分工

    • apt:面向用户,负责「读软件源、拉索引、算依赖、下载」。
    • dpkg:更底层,负责「把单个 .deb 解开安装到系统」。日常你主要用 apt 即可。
  2. yum 与 dnf 的关系在较新的 Fedora / RHEL 系里,dnf 是主力;yum 常常还在,但多为兼容入口。把下面的 apt 流程换成「dnf + rpm」,思路是一样的。

apt 的工作原理

一次 sudo apt install hello 不是「下载一个文件再拷贝」,而是分层流水线。

读软件源配置  → apt update:从源下载并校验索引(目录)  → 解析依赖(还要装哪些包、哪个版本)  → 按索引里的地址下载 .deb  → 调用 dpkg 解包、跑安装脚本、落盘  → 更新本地账本(/var/lib/dpkg/status)

分层:你敲的是 apt,真正落盘的是 dpkg

层
典型命令 / 组件
干什么
用户入口
apt
、apt-get、apt-cache
读源、更新索引、算依赖、安排下载顺序
底层安装器
dpkg
解开单个 .deb,执行 preinst / postinst 等脚本,改账本

可以记:

apt 管「买什么、从哪买、先买谁」;dpkg 管「拆箱上架、记账」。

所以你几乎不会直接 dpkg -i xxx.deb 装一堆包——那样不会自动拉依赖。缺依赖时 dpkg 会报错,把残局留给你自己收拾。

apt update 和 apt install 各干什么

这两条命令最容易混:

命令
实际动作
不做什么
apt update
按软件源配置,下载各仓库的 索引(有哪些包、版本、校验和、下载路径)
不安装、不升级已装软件
apt install
读 本地已缓存的索引,算依赖,下载 .deb,再交给 dpkg
索引过期时可能选到旧版本或找不到新包

索引缓存在 /var/lib/apt/lists/。很久没 update,商店货架还是上周的,install 只能按旧目录采购。

apt upgrade 则是:对照新索引,把已经安装的包升到索引允许的新版本。本篇不展开升级策略,知道它和 install 一样依赖「先有一份新索引」即可。

一次安装在磁盘上经过哪些地方

以 Ubuntu 为例,关键路径如下。不必背全,但要能把「配置 → 索引 → 包文件 → 账本」对上号。

路径
作用
/etc/apt/sources.list
主软件源列表(较新 Ubuntu 可能只剩一行提示,真正的源在下一目录)
/etc/apt/sources.list.d/
额外软件源:每个 .list 或 .sources 一个文件
/etc/apt/apt.conf
/etc/apt/apt.conf.d/
apt 行为配置(代理、是否删除下载缓存等)
/etc/apt/keyrings/
/usr/share/keyrings/
校验仓库签名用的公钥
/var/lib/apt/lists/apt update
 拉下来的索引缓存
/var/cache/apt/archives/
下载下来的 .deb(安装前的临时货仓)
/var/lib/dpkg/status
已安装包账本:名字、版本、状态
/var/lib/dpkg/info/
每个包的文件清单、配置脚本

流程用路径再说一遍:

/etc/apt/sources.list(+.d)        │  告诉 apt:去哪些 URL 找哪套发行版组件        ▼apt update  →  /var/lib/apt/lists/   (索引)        │        ▼apt install →  算依赖        │        ▼下载 .deb   →  /var/cache/apt/archives/        │        ▼dpkg 安装   →  文件落到 /usr/bin、/usr/lib 等        │        ▼记账        →  /var/lib/dpkg/status

索引文件里对每个包都写了大小和哈希(如 SHA256)。下载完成后 apt 会核对哈希,再交给 dpkg。换镜像源之所以「只换地址、不换内容」,正是因为校验的是这份索引,而不是「信网站长什么样」。

软件源:配置路径和作用

软件源 = 告诉 apt:去哪台服务器、取哪个发行版套件、要哪些组件。

没有正确的源,apt update 拉不到索引,后面的 install 全部无从谈起。

配置写在哪

Ubuntu / Debian 会读两处,合并生效:

  1. /etc/apt/sources.list
  2. /etc/apt/sources.list.d/ 下所有合法的源文件

常见两种写法:

格式
文件后缀
出现场景
一行一条的 classic 格式
.list
Debian、Ubuntu 22.04 及更早版本很常见
DEB822(多行键值)
.sources
Ubuntu 24.04 起默认用 /etc/apt/sources.list.d/ubuntu.sources

第三方源(Docker、VS Code 等)也习惯单独丢一个文件进 sources.list.d/,避免和系统自带源搅在一个大文件里。改完源之后必须再执行一次 sudo apt update,新地址才会进入 /var/lib/apt/lists/。

classic 格式:每一段是什么意思

deb http://archive.ubuntu.com/ubuntu jammy main restricted universe multiverse

从左到右:

字段
例子
作用
类型
debdeb
 = 二进制包(日常安装用);deb-src = 源码包(apt source 用,构建镜像一般不需要)
URI
http://archive.ubuntu.com/ubuntu
仓库根地址。镜像加速改的就是这一段
套件
jammy
发行版代号。Ubuntu 22.04 是 jammy,24.04 是 noble;Debian 12 是 bookworm。必须和本机系统一致
组件
main restricted universe multiverse
同一套件下的分区:官方支持、受限、社区、非自由等

同一发行版通常还有更新通道,例如:

deb http://archive.ubuntu.com/ubuntu jammy-updates main restricted universe multiversedeb http://security.ubuntu.com/ubuntu jammy-security main restricted universe multiverse

jammy 是发行时冻结的底座;jammy-updates 是常规更新;jammy-security 是安全补丁。三条都指向「同一代系统的不同货架」,不能把 jammy 的机器改成指向 noble。

DEB822 格式(Ubuntu 24.04+)

含义相同,只是写成多行,方便加签名文件路径:

Types: debURIs: http://archive.ubuntu.com/ubuntuSuites: noble noble-updatesComponents: main restricted universe multiverseSigned-By: /usr/share/keyrings/ubuntu-archive-keyring.gpg

Signed-By 指定用哪把公钥验索引签名。apt 不只下载文件,还会确认「这份目录确实由发行版签过」。镜像站同步的是同一批已签名文件,所以换镜像后校验仍然成立。

源配错了会怎样

配错
典型后果
URI 写错 / 网络不通
apt update
 失败,索引不更新
代号和本机不一致(jammy 写成 noble)
可能装上无法混用的包,系统依赖乱掉
只改了 sources.list,忘了 sources.list.d/ 里还有一份
看起来改了,实际仍在走旧地址
改完不 apt update
install
 仍按旧索引下载

镜像加速:原理是什么

官方源(如 archive.ubuntu.com、deb.debian.org)往往在海外。国内访问延迟高、带宽差,apt update 和下载 .deb 都会慢。镜像加速解决的是 同一份内容,换一个更近的下载入口。

镜像站在同步什么

正规镜像站会定期从官方仓库做同步(常见用 rsync 一类工具),尽量保持:

  • 同样的目录结构(dists/ 下放索引,pool/ 下放 .deb);
  • 同样的套件名、组件名;
  • 同样的包文件和哈希。

对 apt 来说,软件源 URI 只是「仓库根」。把

http://archive.ubuntu.com/ubuntu

换成

https://mirrors.tuna.tsinghua.edu.cn/ubuntu

之后,apt 请求的仍是 dists/jammy/main/.../Packages 这类相对路径。索引里的包哈希不变,下载到的 .deb 也应能通过校验。

你的机器   │  改的只是 URI 主机名   ▼国内镜像(清华 / 阿里 / 中科大 / 华为云 …)   │  定期同步   ▼官方仓库(archive.ubuntu.com 等)

所以:镜像加速 不是「换了一套不同的软件」,而是 CDN / 就近副本。快,是因为链路短、带宽够;安全边界仍然是「索引有发行版签名 + 包文件有哈希」。

改哪里

只改软件源里的 URI 主机(和镜像站要求的路径前缀),套件、组件保持不动。

Ubuntu 22.04 一类 classic 格式,把 archive.ubuntu.com 换成镜像站给出的地址即可,例如:

# 官方deb http://archive.ubuntu.com/ubuntu jammy main restricted universe multiverse# 清华镜像(示例,以镜像站当前文档为准)deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu jammy main restricted universe multiverse

Ubuntu 24.04 则改 /etc/apt/sources.list.d/ubuntu.sources 里的 URIs: 行。许多镜像站还提供一键脚本;原理都是改 URI,然后 sudo apt update。

安全源 security.ubuntu.com 有的镜像站也同步了(路径常叫 ubuntu-security 或合并进同一树)。改的时候对照镜像站说明,不要把 security 指到一个根本没有安全套件的目录。

使用镜像时要注意

  1. 先 update 再 install。只改文件不刷新索引,apt 仍按旧主机信息工作,或索引与新 URI 不一致。
  2. 代号必须匹配本机。镜像再快,也不能给 22.04 去拉 24.04 的仓库。
  3. 校验失败就停。若镜像同步到一半(索引新、包文件旧),apt 会因哈希对不上而拒绝安装——这是保护,不要关校验来「强行加速」。
  4. 第三方源单独处理。Docker 等源不在 Ubuntu 官方树里,换 Ubuntu 镜像帮不上它们;它们要换自己的镜像或官方地址。

WSL2 里的 Ubuntu 同样走 /etc/apt/。后续用 Yocto 在 WSL2 上编系统时,宿主自己装 gawk、git、python3 等构建依赖,走的就是这一套源;源慢,整个环境准备都会慢。

对照:yum / dnf 在做什么

RPM 系把「源」写成 /etc/yum.repos.d/*.repo。一个 .repo 里常见:

[fedora]name=Fedorabaseurl=https://mirrors.example.com/fedora/releases/$releasever/Everything/$basearch/os/enabled=1gpgcheck=1
apt
yum / dnf
/etc/apt/sources.list
 与 sources.list.d/
/etc/yum.repos.d/*.repo
apt update
 拉索引
dnf makecache
(dnf install 也会按需刷新)
索引在 /var/lib/apt/lists/
元数据缓存在 /var/cache/dnf/
dpkg 落盘并记账
rpm 落盘并记账

baseurl 换成国内镜像,原理与 apt 相同:同一套包,换近的 HTTP 入口。有的仓库用 mirrorlist= 让客户端自动挑镜像,本质仍是「官方内容的副本」。

动手:最小闭环示例

下面命令需要你在对应发行版上操作,并且通常需要管理员权限(sudo)。

在 Debian / Ubuntu 上(apt)

先看本机源配在哪(Ubuntu 24.04 可能主要看第二行):

cat /etc/apt/sources.listls /etc/apt/sources.list.d/

再走一遍安装闭环:

# 1)按当前软件源刷新索引sudo apt update# 2)安装示例包(会解析依赖、下载 .deb、调用 dpkg)sudo apt install hello# 3)运行hello# 4)查看包元数据(来自索引 + 本机账本)apt show hello# 5)卸载(按 dpkg 账本删除文件)sudo apt remove hello

过程复述:update 刷新 /var/lib/apt/lists/ → install 计算依赖并安装 → 直接输入命令名运行 → show 查看元数据 → remove 按账本卸载。

若要确认某个包是不是 dpkg 记下的,可以:

dpkg -L hello    # 这个包装了哪些文件dpkg -s hello    # 账本里的状态与版本

在 Fedora / CentOS 上(dnf)

sudo dnf install hellohellorpm -qi hellosudo dnf remove hello

若环境以 yum 为主:

sudo yum install hellosudo yum remove hello

rpm -qi 是直接问底层数据库:「hello 这个包的详细信息是什么?」——这能帮你理解「高层工具 vs 底层数据库」的分层。

这和后面的 Yocto 有什么关系?

很多人会问:既然 apt 这么方便,为什么还要 Yocto?

关键差别在时机:

方式
时机
典型动作
发行版包管理
系统已经运行之后(运行时)
apt install
 / dnf install
Yocto
制作系统镜像的时候(构建时)
写 recipe,把软件编译并打进镜像

思想是相通的:都有「组件、依赖、部署」;但嵌入式或定制系统常常希望:

  1. 出厂镜像里已经带好需要的软件;
  2. 目标设备上不一定有完整的应用商店;
  3. 版本要可复现、可长期维护。

另外有一层容易忽略的关系:你在 WSL2 Ubuntu 上跑 Yocto 时,宿主仍用 apt 安装编译工具链和依赖。软件源与镜像是否配好,影响的是「能不能顺利开始构建」,不是「目标镜像里有没有 apt」。

所以下一篇会进入 Yocto:换一个阶段,用另一套工具,继续解决「软件如何进入系统」这个问题。

本篇小结

请确认自己能讲清:

  1. 包、仓库、依赖、本地数据库分别是什么。
  2. apt 管源、索引、依赖和下载;dpkg 管单包解压、脚本和账本。
  3. 软件源写在 /etc/apt/sources.list 与 /etc/apt/sources.list.d/;URI / 套件 / 组件各管什么。
  4. apt update 只更新索引;apt install 按索引下载并安装。
  5. 镜像加速是换近的同步副本,哈希与签名仍按官方索引校验。
  6. Ubuntu / Debian 走 apt(dpkg);CentOS / Fedora 走 yum / dnf(rpm)。
  7. 发行版包管理偏运行时;Yocto 偏构建时。

系列文章列表:

从零构建 Linux 系统
从零构建 Linux|01 启动流程总览
从零构建 Linux|02 Bootloader
从零构建 Linux|03 内核启动
从零构建 Linux|04 Rootfs、init 与服务

最新文章

随机文章