
我去年接手了一个内网办公环境迁移项目要把几十台旧机器换成统信UOS专业版但机房物理隔离没有外网。最头疼的不是系统安装而是安装软件时那一串串依赖报错——缺一个库后面一串软件全装不上。折腾了一周之后我总结出一套用命令行高效下载离线安装包及依赖的完整流程今天把它整理出来希望能帮到同样在做UOS离线部署的朋友。这篇文章的核心就是解决一个问题在一台能联网的Linux机器上把UOS专业版需要的软件包以及所有依赖全部下载下来拿到内网一键装完。内容覆盖apt/dpkg底层机制、三种依赖下载思路、批量自动化脚本、离线安装与修复手段、以及UOS上特有的坑。适合做系统集成、运维、UOS迁移项目的人参考纯新手建议先把基础命令熟悉一遍。1. UOS离线部署为何总卡在依赖先弄懂apt与dpkg的底细1.1 UOS专业版的包管理血缘来自Debian但又不完全一样统信UOS专业版底层基于Debian包管理用的是apt加dpkg这套生态。deb包本质上是一个ar压缩包里面塞了程序文件、控制信息、脚本和依赖声明dpkg负责把包解开并安放到系统对应目录apt则负责处理包与包之间的依赖关系、下载、升级等更上层的工作。这个血缘关系意味着Debian系的大多数操作在UOS上都能用比如apt-get install、apt-cache search、dpkg -i。但UOS的源和Debian官方源不是同一个依赖版本也不完全同步。我试过直接把Debian源里的某个依赖包下载下来往UOS上装结果版本对不上系统报错依赖关系不满足。所以做UOS离线包一定要用UOS自己的源不要想当然去Debian源里抓包。1.2 依赖地狱离线场景为什么放大这个问题在线环境下你执行一条apt-get installapt会自己读取每个包的Depends字段把缺的依赖依次从源里拉下来自动装上。这个过程由apt的依赖解析器全权接管你基本感知不到依赖的存在。离线环境下apt无法访问网络这个自动解析就瘫痪了。你需要把安装包和依赖全部手动准备好一层一层剥洋葱装A需要B装B需要CC又依赖D和E……一旦漏掉中间某个包前面装的全白搭。举个真实例子我帮客户装一个办公套件时它依赖了十几个库文件其中一个库又依赖低版本的glibc相关模块。漏掉任何一个dpkg就会中断并告诉你未安装的软件包 X。1.3 哪些场景最需要离线安装包不是所有UOS装软件都需要离线包。以下场景基本绕不开物理隔离内网机房没有外网连局域网源都没有这是最常见的场景。统一装机基线多台机器需要在同一时间用同一版本软件部署防止各台机器从源里拉到不同版本导致行为不一致。保密或安全管理要求不允许在线安装必须经过人工审查的软件包才能进内网。网络波动严重有些单位的外网质量堪忧安装到一半断线会留下半配置状态离线包反而更稳。2. 搭建下载环境开发者模式、apt源与系统版本基线2.1 开发者模式绕不开的第一步UOS专业版默认不开放root终端直接执行sudo apt-get可能会提示权限受限。安装部分deb包时需要root权限写入系统目录所以第一件事是开启开发者模式。常规做法是在控制中心找到通用设置进入开发者模式选项按提示绑定账号开启。开完之后在桌面右键打开终端执行sudo -i验证一下是否具备root权限。开发者模式还能顺手帮你打开SSH后面批量下发离线包会方便很多。提示开发者模式开启后系统会提示安全风险这是正常提示离线网络环境下风险可控。如果实在不能开也可以试试用普通用户配合sudo运行命令但部分包的postinst脚本会因为没有权限而失败。2.2 配置apt源先解决从哪下载的问题下载离线包之前需要确认下载机上的源列表可用。UOS的源配置文件在/etc/apt/sources.list以及/etc/apt/sources.list.d/目录下。专业版预装的是官方企业源如果能联网且能正常apt update直接用就行。如果你用的是社区版或想指定一个公共源需要手动改配置。以UOS 20为例一份可用的源配置大致长这样deb [trustedyes] https://community-packages.deepin.com/beige/ beige main contrib non-free注意这里的beige是版本代号不同UOS版本的代号不一样。在动手改源之前最好先执行cat /etc/os-release确认系统版本和代号再去匹配对应的源地址。改完源之后必须执行apt update。2.3 环境评估下载机和目标机的版本必须对齐这一步是很多人忽略的关键点。下载离线包时下载机和目标机的条件要尽可能一致CPU架构必须一致。UOS支持x86_64、ARM64、LoongArch等架构用uname -m确认。x86_64的包在ARM机器上装不了。系统大版本尽量一致小版本差异较大时部分依赖包版本会不同。源配置也尽量一致否则下载的依赖版本可能和目标机源里的不一致导致安装时版本冲突。我最开始犯过一个错在x86_64的下载机上下了一堆ARM机器的包结果送去现场全部装不上来回折腾了好几天。现在我在做离线包前第一件事就是对比两边机器的/etc/os-release和uname -m输出。3. 用apt命令把安装包和依赖完整抠出来三种最实用思路3.1 最朴素的方案apt-get download加手动分析依赖apt-get download的作用是只下载某个软件包的文件不做任何安装操作。它和apt-get install的区别在于不检查依赖、不修改系统、不下载依赖包。这给了我们手动控制的空间。原理搞清楚了问题是依赖列表从哪来两个常用命令apt-cache depends 包名列出该包的直接依赖、推荐、建议等。dpkg-deb -I 某个.deb文件查看deb包的控制信息其中Depends字段就是依赖关系。Debian系包依赖声明中常见的运算符包括、、比如libc6 ( 2.34)表示需要libc6版本大于等于2.34。手动方案的流程是先用apt-cache depends看直接依赖然后对每个依赖再用同样的命令去查它们的依赖递归下去。实际操作中如果依赖层级很多纯手动非常痛苦。这个方法适合依赖少、层级浅的小工具类软件比如只依赖两三个基础库的小命令。3.2 精准模拟用apt-get install --simulate拿到完整依赖清单这个方案是我日常工作用最多的。apt-get install --simulate简写-s的作用是模拟安装过程不实际下载、不安装只打印apt的解析结果。执行后输出里会有大段以Inst开头的包列表这些就是apt认为需要安装的所有依赖包。举个例子在一台UOS机器上执行sudo apt-get install --simulate onlyoffice-desktopeditors输出会显示类似Inst libcurl4 (7.74.0-1.3deb11u7 amd64) Inst onlyoffice-desktopeditors (7.3.3.131 amd64)把Inst后面的包名提取出来就是完整的安装清单。接下来把这些包名逐一带给apt-get downloadapt-get download libcurl4 onlyoffice-desktopeditors执行完之后你会发现当前目录下多了一批deb文件这就是离线安装所需的全部家当。提示apt-get download只接受包名不接受deb文件路径。如果你有一个chroot环境或想安装一个本地deb并把它的依赖打包离线请参考下一节的chroot方案。3.3 一网打尽chroot环境下的完整依赖下载上面两种方案有一个共同局限它们依赖apt的模拟分析如果你的目标机没法联网、没法跑apt update而你又想精准预测某个本地deb文件在干净系统上的依赖怎么办chroot方案能解决这个问题。思路是在下载机上创建一个小型模拟目标机把目标机的系统源和deb包放进去在chroot环境里运行apt来下载依赖下载完把deb全部取出。核心步骤如下# 1. 创建一个chroot目录并安装debootstrap若系统里有UOS的base文件系统也可以直接用它 sudo debootstrap --archamd64 beige /var/chroot/uos-target # 2. 进入chroot并配置UOS的源 sudo chroot /var/chroot/uos-target # 在chroot中写入与目标机一致的source.list然后执行apt update # 3. 在chroot中模拟安装 apt-get install --simulate 软件包名 # 4. 在chroot中下载所有deb到某个目录 apt-get download $(apt-cache depends --recurse --no-recommends --no-suggests 软件包名 | grep -E ^[a-zA-Z0-9] | tr \n ) # 注意这条命令需要包管理器递归解析实际使用时最好配合apt-rdepends看起来有些繁琐但它的好处是能在一个与目标机高度一致的软件环境中做依赖解析不会因为下载机装了一堆额外软件而绕开某些依赖。三种方案的适用场景可以这么区分。方案适合场景优点缺点apt-get download手动分析单包小依赖、应急简单直接依赖多时容易漏apt-get install --simulate常规软件离线打包精准、依赖完整需要在能解析源的环境中执行chroot环境复杂依赖、不能污染下载机环境最接近目标机真实状态搭建繁琐、占用空间4. 把反复下载封装成脚本批量获取依赖与apt-offline方案4.1 自动提取依赖列表并批量下载的完整脚本当你需要下载十几个软件包、每个包又有几十个依赖时手工敲命令就完全不现实了。我已经习惯把整个过程封装成一个bash脚本核心逻辑是先用apt-get install --simulate生成依赖清单解析出所有包名再循环调用apt-get download批量下载最后把下载好的deb归档到一个目录里。下面是一个可直接使用的脚本在UOS/deepin/Debian系机器上都适用#!/bin/bash # uos-debs-download.sh # 用法: ./uos-debs-download.sh 软件包名... DOWNLOAD_DIR$HOME/offline-debs mkdir -p $DOWNLOAD_DIR PACKAGES$ if [ -z $PACKAGES ]; then echo 请至少指定一个软件包名 exit 1 fi # 1. 生成依赖清单模拟安装输出 SIM_OUTPUT$(apt-get install --simulate $PACKAGES 2/dev/null) if [ $? -ne 0 ]; then echo 模拟安装失败请先确认apt源可用并已执行apt update exit 1 fi # 2. 提取Inst开头的包名 DEPS$(echo $SIM_OUTPUT | grep ^Inst | awk {print $2}) # 3. 把主包也加入清单 ALL_PACKAGES$PACKAGES $DEPS # 4. 逐一下载 cd $DOWNLOAD_DIR for PKG in $(echo $ALL_PACKAGES | tr \n | sort -u); do if [ -f ${PKG}_*.deb ] 2/dev/null; then echo 跳过已存在的 $PKG continue fi echo 正在下载: $PKG apt-get download $PKG 2/dev/null || echo 下载失败: $PKG done echo 全部下载完成文件保存在 $DOWNLOAD_DIR ls -lh $DOWNLOAD_DIR脚本里有两个值得注意的细节sort -u去重同一个依赖可能被多个主包共享没必要重复下载。已存在文件的跳过判断如果之前下载过某个包再次执行脚本时不会覆盖这能避免反复下载大文件。4.2 apt-offline一个更省心的离线工具方案如果你觉得手动写脚本太麻烦apt生态里还有一个现成工具叫apt-offline专治离线环境依赖问题。它的工作方式是在目标机上生成一个需求文件然后在下载机上按需求文件下载包最后把包带回目标机安装。目标机离线机上执行sudo apt install apt-offline sudo apt-offline set /tmp/offline-requestapt-offline set会根据当前系统已安装的包和差额生成一个包含所有需要下载包信息的签名文件。把它拷贝到下载机sudo apt-offline get /path/to/offline-request -d /path/to/debs-dir之后把debs-dir里的包拷回目标机执行sudo apt-offline install /path/to/offline-download它能自动处理包顺序和依赖安装比纯手动dpkg省心很多。不过要注意UOS的源里有可能没有预装apt-offline目标机上如果连这个工具都装不上可以先用上面的一键脚本把离线包下载完然后用dpkg -i进行安装。我在实际项目里两种方案都留下备着脚本负责批量下载apt-offline负责精细化增补。5. 离线安装全链路组织deb仓库、dpkg安装顺序与修复手段5.1 构建一个结构清晰的离线仓库目录下载回来的几十个deb包如果全部堆在一个目录里一到安装时就会非常乱。我习惯按项目或日期建目录每个项目单独一个文件夹里面再细分debs、lists、logs几个子目录。比如这样一个结构/opt/offline-pkgs/ ├── office-debs/ │ ├── debs/ # 所有deb文件 │ ├── install-list.txt # 从simulate输出的包清单 │ └── install.log # 安装日志 └── dev-tools/ ├── debs/ ├── install-list.txt └── install.log目录建好之后建议在正式安装前用dpkg-deb -I检查一下主包的Depends字段和目录里的deb文件对照一遍看缺没缺依赖。这一步虽然多花几分钟但能避免在目标机上装到一半才发现缺包。5.2 安装策略与常用dpkg参数内网安装时最直接的方式是dpkg -i。但如果依赖顺序不对报错几乎是必然的。我的经验是分三步走第一步先安装基础依赖库再把主包放最后。可以按依赖树从底向上装但人工排序在大包面前不现实。一个更聪明的做法是先把所有deb包丢给dpkg装让它自己报错然后用dpkg --fix-broken自动修复依赖问题。cd debs sudo dpkg -i *.deb sudo apt-get install -f -y # 或者使用 dpkg --fix-brokendpkg -i *.deb会按文件名顺序尝试安装中途如果遇到未满足的依赖会中断并提示。这时执行apt-get install -f它会尝试修复依赖关系——在离线无源的情况下修复能力取决于你已经放进去的deb是否覆盖了缺口。第二步如果依赖缺口较多修复无果就得找到具体缺哪个包从离线包里补装sudo dpkg -i /path/to/missing-package.deb第三步安装完成后统一配置sudo dpkg --configure -a这个命令会把所有已解包但未配置的包做一遍配置经常在安装中断后使用能回收不少半成品状态。5.3 安装验证与半配置状态修复装完之后别急着撤至少用下面几个命令确认一次# 查看主包是否正常安装 dpkg -l | grep 包名关键字 # 查看某个关键动态库是否能被系统找到 ldconfig -p | grep 库名 # 查看程序的依赖是否全部满足 ldd /opt/程序路径/可执行文件如果dpkg -l里状态显示ii表示安装成功如果是iU、iF这类状态说明包已解压但未配置或配置失败需要执行dpkg --configure -a再次修复。我在一次批量部署WPS时遇到过iF状态直接重新执行dpkg --configure -a就恢复了问题不大。6. UOS离线部署的高频坑以及把离线包变成内网apt源6.1 不能直接剪切粘贴安装目录的软件注册机制的坑UOS环境里有一类常见误解以为把一台机器上装好的软件目录比如/opt/xxx直接拷贝到另一台机器上就能正常使用。实话说这对于一些绿色软件可能行得通但对office、wps这类深度集成的办公软件绝对不行。原因是这些软件在安装过程中会做大量系统级注册写入动态库缓存和系统路径比如/usr/lib下的库链接缺了它程序根本起不来。在/etc、~/.config等位置保存配置和注册信息软件启动时会校验。注册菜单项、文件关联、图标主题、字体缓存等桌面环境资源。部分软件使用了账号或授权文件绑定机器信息直接拷贝授权失效。所以无论离线包多大也要用deb包正规安装。如果实在找不到deb包只能拷贝目录那也要把上面这些系统级配置一并迁移操作成本比重新安装高得多。6.2 多版本依赖冲突与锁定策略离线安装时最怕的是两个软件对同一个依赖库的版本要求互相冲突A要libfoo-1.0B要libfoo-2.0而系统只能装一个。在线环境下apt会自动做一些妥协或提示冲突离线手工安装时这个矛盾会直接摆到你面前。我的处理思路是能用系统自带版本就优先用系统自带版本如果某个软件必须升级共享库我会先确认升级后其他软件会不会受影响。在部署时尽量保持系统base环境版本和下载离线包时一致不轻易手动升级核心库。对于确实要锁定版本的包可以在源里用apt-mark hold把自己不希望的升级包锁住sudo apt-mark hold libfoo这样后续即使有源、有人手贱跑了apt upgradelibfoo也不会被意外升级。6.3 把离线仓库变成内网apt源一劳永逸的做法如果你的项目不止一两台机器而是几十台上百台逐台dpkg装包就是灾难。更好的方案是把离线deb包整理成一个内网apt源让所有内网机器像在线环境一样使用apt install。核心原理是apt源本质上就是一个目录加一个Packages索引文件。用apt-ftparchive可以快速生成索引# 把所有deb放进同一目录如/var/www/uos-repo/debs cd /var/www/uos-repo dpkg-scanpackages debs /dev/null | gzip debs/Packages.gz然后配置内网机器的源指向这台仓库服务器deb [trustedyes] http://192.168.1.100/uos-repo/debs/ beige main配置完成后执行apt updateapt就能看到这个离线源里的所有包依赖解析也恢复在线一样的体验。这个方案我一向推荐给长期项目使用因为它把离线转变成了受限在线后续任何一台机器缺包直接从内网源装完全不需要再碰U盘。如果觉得dpkg-scanpackages在UOS里没有预装可以改用apt-ftparchive packages . Packages效果类似。最后再分享一点实操心法做了这么多UOS离线部署之后我最大的体会是离线部署本身不难难的是版本一致性和流程标准化。下载离线包的机器尽量保持和目标机同系统版本每次下载完的deb包不要直接扔进U盘先归档、记录清单、写清日期和对应源环境一套完整的离线包务必要在测试机上从零装一遍验证确认没问题再送去现场。一个小技巧是下载完离线包之后顺手在下载目录里生成一个manifest.txt把每个deb包的文件名和版本号都记下来。真到了现场发现少了一个包查这个文件就能知道当时是从哪个源、哪个版本环境下载的排查效率翻倍。