1. 为什么我偏爱 download-only 这套离线安装打法
apt-get install --download-only这个参数,第一次看到的人多半会觉得它有点鸡肋——装就装吧,只下载不安装是图什么?但只要你经历过一次内网环境里没有外网出口、或者生产机器被严格限制不能直连软件源的场景,就会明白这个参数简直是救命稻草。它的作用非常直接:把某个软件包以及它依赖的所有 deb 包全部拉到本地缓存目录,但不执行解包和配置动作。换句话说,它帮你把“联网获取”和“本地安装”这两件事彻底拆开了。
这套打法的核心价值在于解决一个非常现实的矛盾:目标机器需要装软件,但它不能或者不方便访问外部软件源。常见的情况包括内网隔离的服务器、安全策略收紧的办公终端、网络带宽极其有限的边缘设备,以及需要批量部署几十台同配置机器的运维场景。你在一台能联网的机器上把包全部下载好,打包带走,到目标机器上一条dpkg -i或者本地源的方式装完,整个过程干净利落,不依赖目标机器的网络状况。
适合谁来参考?我觉得三类人最需要:一是刚接触 Linux 运维、还没建立离线部署思路的新手;二是经常要在隔离环境里折腾软件安装的运维工程师;三是需要做批量标准化部署、希望把安装过程完全可控化的技术人员。哪怕你只是偶尔帮人装一台没有外网的机器,这套方法也能让你少走很多弯路。下面我把自己反复实践过的完整流程、参数细节和踩坑经验全部摊开讲,尽量做到你照着做就能复现。
2. 整体思路拆解与方案选型考量
2.1 联网机与目标机分离的基本模型
这套方案的本质是一个“两段式”流程。第一段在联网机上完成,用--download-only把目标软件及其完整依赖树下载到本地;第二段在目标机上完成,把下载好的 deb 包传过去,用dpkg或本地源的方式安装。中间靠一个 U 盘、一次 scp、或者一台内网文件服务器来搬运。
为什么非要拆成两段?因为apt的依赖解析是它最值钱的能力。一个看似简单的软件,背后可能拖着十几个甚至几十个依赖包,版本约束还互相牵扯。你手动去一个个找 deb 包,几乎不可能保证版本匹配。而--download-only让 apt 在联网环境下把依赖关系算清楚、把包全部拉齐,你只需要负责搬运和安装,依赖解析这个最烧脑的环节交给工具本身。
这里有个关键认知需要先建立:--download-only下载的包默认落在/var/cache/apt/archives/目录下。这个目录是 apt 的包缓存区,平时正常安装时 deb 包也会临时存在这里,装完可能被清理。用了--download-only之后,包就静静躺在那里等你取用。理解这个落点,后面所有的搬运和校验操作才有依据。
2.2 为什么不用 apt-offline 之类的专用工具
市面上确实有专门做离线安装的工具,比如 apt-offline 这类方案。它们的工作方式是先在目标机生成一个签名请求文件,拿到联网机去解析下载,再带回目标机安装。听起来很优雅,但我在实际使用中发现了几个不太顺手的地方。
第一是链路更长,多了一个“生成请求”的环节,目标机本身也得装好对应工具,对于一台全新的、啥都没有的机器来说反而增加了前置成本。第二是版本对齐问题,请求文件里记录的是目标机的源信息,联网机的源配置如果和目标机不一致,下载下来的包版本可能对不上。第三是排查困难,一旦中间某个环节出错,错误信息不如直接用 apt 来得直观。
相比之下,--download-only的优势是零额外依赖。联网机上只要有 apt 就能干活,目标机上只要有 dpkg 就能装,两个都是 Debian 系系统的标配。整个流程透明、可控、易排查,出问题了一眼就能看出是下载阶段还是安装阶段。对于绝大多数中小规模的离线安装需求,这套原生方案足够用,没必要引入额外工具增加复杂度。
2.3 架构匹配这个坑必须先想清楚
在动手之前,有一个前提必须确认:联网机和目标机的系统架构要一致。apt 下载 deb 包时会根据当前机器的架构来选择,如果你在一台 x86_64 的机器上下载,拿到一台 ARM 架构的设备上装,包根本装不上,会直接报架构不匹配的错误。
同理,发行版大版本也尽量对齐。比如都是某个 Debian 大版本或者都是某个 Ubuntu LTS 版本,这样依赖库的版本基线一致,装起来最稳。跨大版本搬运虽然有时也能成,但依赖版本冲突的概率会明显上升,属于给自己找麻烦。如果确实需要给不同架构的机器准备包,apt 支持通过配置指定目标架构,但那属于进阶用法,后面我会单独提一句。
3. 核心细节解析与实操要点
3.1 download-only 到底做了什么,没做什么
很多人对这个参数的理解停留在“只下载不安装”,但具体边界在哪,值得掰开说清楚。执行apt-get install --download-only 软件名时,apt 会完成这几件事:读取源列表、更新包索引(如果索引过期会提示)、计算依赖树、确定每个包的具体版本、然后把所有需要的 deb 文件下载到/var/cache/apt/archives/。它不会做的是:不解包、不执行 preinst/postinst 脚本、不修改系统里已安装包的状态、不更新 dpkg 的数据库。
这个边界非常重要,因为它意味着下载阶段对联网机是几乎无副作用的。你不用担心下载某个包会把联网机的环境搞乱,包只是躺在缓存目录里。唯一需要注意的是缓存目录的磁盘空间,一个带完整依赖的软件包集合,小则几十 MB,大则几百 MB 甚至上 GB,下载前最好看一眼剩余空间。
还有一个细节:如果某个依赖包在联网机上已经安装过,apt 默认不会再下载它,因为它认为系统里已经有了。这在联网机和目标机环境一致时没问题,但如果目标机是干净的、什么都没装,就会漏包。解决办法是加--reinstall参数,强制把已安装的包也重新下载一份。这个坑我踩过不止一次,后面问题排查章节会详细讲。
3.2 缓存目录的清理与保护策略
/var/cache/apt/archives/这个目录平时是被 apt 当作临时缓存用的,系统里如果有自动清理机制(比如某些定时任务或者手动执行过apt-get clean),里面的包可能被清掉。所以在下载完成后、搬运之前,最好把这个目录里的 deb 包复制到另一个安全位置,而不是直接依赖缓存目录长期存放。
我的习惯是下载完立刻执行一次复制,把*.deb全部拷到一个专门的打包目录,比如/tmp/offline-pkgs/。这样做有两个好处:一是避免后续任何 apt 操作意外清理缓存,二是打包目录干净,只有 deb 文件,方便整体压缩和传输。复制的时候用cp /var/cache/apt/archives/*.deb /tmp/offline-pkgs/就行,注意目标目录要先建好。
提示:复制完成后不要急着
apt-get clean,先确认目标机安装成功再清理联网机的缓存,给自己留一条后路。万一搬运过程中包损坏了,还能从缓存里重新取。
3.3 依赖完整性的判断依据
怎么确认下载下来的包集合是完整的?最直接的信号是--download-only执行结束时没有报错,并且提示信息里显示所有包都已下载。apt 在依赖解析阶段如果发现某个依赖无法满足,会直接报错退出,不会给你一个残缺的集合。所以只要命令正常结束,依赖树基本就是完整的。
但有一个隐蔽情况需要留意:推荐依赖和建议依赖。apt 默认会安装推荐依赖(Recommends),但建议依赖(Suggests)默认不装。如果你在联网机上因为某些原因调整过 apt 的配置,导致推荐依赖的行为不一致,下载下来的集合可能和目标机期望的不同。稳妥的做法是下载时保持默认配置,不要额外加--no-install-recommends之类的参数,除非你明确知道自己在做什么。
另外,下载完成后可以看一眼缓存目录里 deb 包的数量和总大小,心里有个数。如果某个软件你预期只有几个包,结果下载了几十个,说明它的依赖树比想象中深,这是正常的,不用慌。反过来,如果只下载了一两个包,而目标机装的时候报缺依赖,那多半是联网机上已经装了那些依赖导致没被下载,回到 3.1 节说的--reinstall就能解决。
4. 完整实操流程与关键环节实现
4.1 联网机上的下载操作
先在一台能正常访问软件源的机器上操作。第一步建议先更新一下包索引,保证拿到的是最新的版本信息:
sudo apt-get update然后执行下载。这里我给出一个我常用的完整命令形式:
sudo apt-get install --download-only --reinstall -y 软件包名逐个参数解释一下。--download-only是核心,只下载不安装。--reinstall强制把已安装的包也重新下载,避免漏包,这个参数在目标机是干净环境时尤其重要。-y是自动确认,省去交互。软件包名可以是一个,也可以是多个,用空格隔开,apt 会统一计算依赖树。
执行过程中你会看到 apt 列出将要下载的包清单,包括包名、版本、大小。这时候留意一下清单里有没有明显不该出现的包,或者版本号是否符合预期。下载完成后,所有 deb 文件就在/var/cache/apt/archives/里了。执行一次复制:
mkdir -p /tmp/offline-pkgs cp /var/cache/apt/archives/*.deb /tmp/offline-pkgs/ ls -lh /tmp/offline-pkgs/ | wc -l最后一行是数一下包的数量,做到心中有数。如果包比较多,可以打个压缩包方便传输:
cd /tmp && tar czf offline-pkgs.tar.gz offline-pkgs/4.2 搬运与校验环节
把压缩包或者整个目录传到目标机。传输方式看你的环境,U 盘、内网共享、scp 都行。传完之后一定要做完整性校验,这是很多人会跳过但非常关键的一步。deb 包在传输过程中损坏的情况不常见,但一旦发生,安装时报的错会非常迷惑,让你以为是依赖问题,实际是包坏了。
校验方法很简单,在联网机上算一遍校验和,到目标机上再算一遍对比:
# 联网机上 cd /tmp/offline-pkgs && sha256sum *.deb > checksums.txt # 目标机上,把 checksums.txt 一起传过去后 cd /path/to/offline-pkgs && sha256sum -c checksums.txt全部显示 OK 就说明包完好。这一步花不了多少时间,但能帮你排除掉一大类莫名其妙的安装失败。
4.3 目标机上的安装方式选择
到了目标机,安装有两条路可走,各有适用场景。
第一条路是直接用 dpkg 批量安装。进入 deb 包所在目录,执行:
sudo dpkg -i *.debdpkg 会按文件名顺序安装。这里有个细节:dpkg 不处理依赖顺序,如果某个包依赖另一个还没装的包,会报依赖错误。但因为所有依赖包都在同一个目录里,dpkg 装完一轮后,再执行一次同样的命令,通常就能把之前因顺序问题失败的包装上。所以我的习惯是连续执行两次dpkg -i *.deb,第一次装大部分,第二次补齐顺序依赖的。如果第二次还有报错,再执行sudo apt-get install -f来修复依赖关系(这条命令在目标机本地有源或者能访问源时有效,纯离线环境下它只能基于本地已有的包来修复)。
第二条路是搭建本地源。如果包数量很多,或者需要反复给多台机器安装,搭一个本地 apt 源更省事。做法是把 deb 包放到一个目录,用dpkg-scanpackages生成索引:
cd /path/to/offline-pkgs dpkg-scanpackages . /dev/null | gzip -9c > Packages.gz然后在/etc/apt/sources.list里加一行指向这个目录:
deb [trusted=yes] file:/path/to/offline-pkgs ./执行sudo apt-get update之后,就可以像正常装软件一样apt-get install 软件包名了,依赖解析交给 apt 自己处理,体验和在线安装几乎一致。这种方式适合包多、机器多的场景,一次搭好反复用。
| 安装方式 | 适用场景 | 优点 | 注意点 |
|---|---|---|---|
| dpkg -i *.deb | 包少、单台机器 | 简单直接,无需配置 | 需执行两次处理依赖顺序 |
| 本地 apt 源 | 包多、多台机器 | 依赖自动解析,可复用 | 需生成索引并配置源 |
4.4 安装后的验证
装完之后别急着收工,做一次验证。最直接的是查包状态:
dpkg -l | grep 软件包名状态列显示ii表示已正确安装。再跑一下软件本身的版本命令,确认能正常执行。如果软件有服务形态,检查一下服务是否正常启动。这一步是给自己一个明确的完成信号,避免装了个半吊子还以为成功了。
5. 常见问题与排查技巧实录
5.1 目标机报缺依赖,但明明下载了
这是最高频的问题。现象是dpkg -i时报某个依赖未满足,但你确认那个依赖的 deb 包就在目录里。原因通常是 dpkg 的安装顺序问题——依赖包还没轮到装,被依赖的包先装了。解决办法就是前面说的连续执行两次dpkg -i *.deb。如果两次还不行,检查一下是不是真的漏了包,用dpkg -I 包名.deb看依赖声明,对照目录里有没有对应的包。
还有一种可能是联网机上下载时因为已安装而跳过了某个包,导致集合里根本没有它。回到联网机用--reinstall重新下载一遍即可。
5.2 架构不匹配报错
报错信息里会出现architecture字样,说明下载的包架构和目标机不一致。确认两台机器的架构:
dpkg --print-architecture两边输出必须一致。如果不一致,需要在联网机上指定目标架构重新下载。apt 支持通过-o APT::Architecture=目标架构的方式指定,但这要求联网机的源里包含该架构的包,配置起来稍复杂,属于进阶操作。最简单的办法还是找一台架构一致的机器来下载。
5.3 缓存目录里的包不完整或被清理
如果发现缓存目录里的包数量比预期少,先检查是不是被自动清理机制动过。另外确认下载命令是否真的成功结束,中途 Ctrl+C 或者网络中断都会导致包不完整。重新执行一次下载命令,apt 会跳过已完整下载的包,只补缺失的,效率很高。
5.4 常见问题速查表
| 现象 | 可能原因 | 解决方向 |
|---|---|---|
| dpkg 报依赖未满足 | 安装顺序问题 | 连续执行两次 dpkg -i |
| 报 architecture 错误 | 架构不一致 | 确认并统一架构 |
| 包数量偏少 | 已安装包被跳过 | 加 --reinstall 重下 |
| 安装时报包损坏 | 传输损坏 | sha256 校验后重传 |
| 本地源 update 失败 | 索引未生成或路径错 | 重新 scanpackages 并检查源路径 |
注意:纯离线环境下
apt-get install -f只能基于本地已有的包修复依赖,它不会凭空变出缺失的包。所以修复的前提是包集合本身完整。
5.5 一个容易被忽略的实操心得
我踩过最冤的一次坑,是下载时用了--no-install-recommends,结果目标机上某个软件虽然装上了,但缺了推荐依赖里的一个组件,功能不正常,排查了半天才发现是下载阶段就少拿了包。从那以后我的原则是:离线下载阶段尽量保持 apt 的默认行为,不要做任何裁剪。多下载几个包浪费的只是几十 MB 空间,漏包导致的功能异常排查成本要高得多。宁可多带,不可少带,这是离线安装的一条朴素真理。
另外,打包时把checksums.txt和 deb 包放在一起,到目标机先校验再安装,养成这个习惯之后,因为传输问题导致的疑难杂症基本就绝迹了。这套流程看起来步骤不少,但真正跑熟之后,从下载到装完也就几分钟的事,比在隔离环境里临时找包、试错、返工要高效太多。