
在内网或者离线环境里给UOS专业版装软件我踩过的坑比大部分人见过的包都多。最难受的不是软件本身装不上而是一堆七拐八拐的依赖缺一个就卡住你的部署进度剩下的全盘白干。今天这篇实战指南就把我用命令行批量下载离线安装包和依赖的整套流程完整拆开从原理、准备、实操到排坑一次讲清楚内容基于UOS专业版的APT体系适合运维、实施工程师以及所有需要在国产化环境里批量装软件的朋友直接抄作业。1. 从包管理机制说起UOS离线安装为什么绕不开“依赖”很多人刚到UOS上会有点懵明明在Windows上装个exe点下一步就结束了怎么到了UOS这里要先处理一堆“依赖”这不是UOS为难你而是Linux发行版的包管理机制本来就是这样设计的理解这点之后离线安装的思路就顺了。1.1 UOS专业版本质是Debian系apt/dpkg是核心UOS专业版底层基于Debian体系这意味着它的软件安装、卸载、查询都绕不开两个核心工具底层的dpkg和上层的apt。dpkg负责直接操作.deb包类似Windows里的msiexecapt则是在dpkg之上做软件源管理、依赖解析和安装排序类似一个自带“自动装依赖”能力的商店前端。线上环境里你执行sudo apt install xxx时apt会从/etc/apt/sources.list和/etc/apt/sources.list.d/下配置的软件源地址拉取软件包列表然后自动分析依赖关系把需要的包一次性从源里取下来。这个过程在联网时是无感的你只看到一个进度条。但到了离线环境没有源可以拉取你就必须把“安装时所需的全部deb文件”准备好带到内网机器上手动交给dpkg或apt去安装。这里的核心难点就是你得精确知道一个软件依赖哪些包、这些包又分别依赖什么缺一个都会报错。顺带一提UOS专业版的软件源配置和Debian略有差异官方源、商业源、应用商店源会分布在不同的list文件里后面准备离线包时建议先确认目标机器用的是哪一套源否则下载的包版本可能对不上。1.2 “装好后别直接剪切粘贴移动安装目录”是怎么回事网上经常有人问“我能不能在一台UOS机器上装好WPS、Office然后把整个安装目录拷贝到另一台机器上直接用”答案是不行。这里有个底层逻辑Linux下的软件尤其是通过dpkg安装的软件不只是把文件放在目录里它还会做三件关键的事。第一它会向系统注册文件清单记录哪些文件属于哪个包这个信息存放在/var/lib/dpkg/info/下。第二它会写入配置文件或系统级配置比如服务的启动脚本、环境变量、桌面文件、MIME类型关联这些信息散落在/etc、/usr/share等目录里。第三像WPS、Office这类商业软件安装过程还会做产品注册、用户数据路径初始化、许可校验等操作类似Windows的注册表写入只不过在Linux下这些注册信息放在独立的注册文件里。如果你直接把安装目录剪切粘贴到另一台机器等于把“运行文件”带过去了但系统里没有对应的注册信息、没有包管理器记录、没有桌面关联软件要么无法启动要么启动后各种报错。尤其WPS、Office这类软件切割粘贴之后数据目录和注册状态基本全乱。所以UOS上的离线部署本质上是要把“安装动作”完整搬到目标机器上而不是搬运安装后的文件夹。这一点决定了我们后面做离线包时必须把软件本身的deb包和它的依赖一起备齐在目标机器上重新走一遍安装注册流程。1.3 三种典型的离线安装场景先对号入座我遇到的离线部署需求大致可以分成三类处理方式不太一样。场景A是单机临时补包。机器已经日常运行只缺一两个软件和少量依赖比如要装个ffmpeg或者nginx这类场景包数量少用apt-get download配合依赖查询就能搞定。场景B是批量同配置部署。几十台机器型号一样、系统版本一样要预装一套统一软件集这种情况只下载一堆deb然后逐台dpkg -i虽然可行但效率低、容易漏包更推荐把离线包做成本地APT源后面每台机器直接用apt install安装。场景C是完全无外网的安全内网。这类环境往往连GPG公钥都无法在线获取软件源验证、架构校验都得人工处理对我们准备离线包的要求最高。本文第3节到第5节会覆盖这三个场景的做法关键是把流程理顺后面所有机器都能复用。2. 下载离线依赖包前先把环境和工具备好准备工作没做好就直接开干后面大概率翻车。我见过不少人在这步偷懒拿一台Ubuntu机器当下载机结果下出来的依赖包在UOS上根本装不了。这节就把我常用的“备货准备清单”列出来。2.1 一台与离线机同源同架构的联网机器是关键准备离线包最理想的环境是在一台能够联网、且系统版本和目标离线机基本一致的UOS专业版机器上进行下载。为什么强调“同版本”“同架构”因为apt解析依赖时拿到的包版本取决于软件源里的版本信息和系统本身的版本基线。如果下载机是UOS 1050离线机是UOS 1060两边源里的依赖库版本可能就不一样你下载的依赖包在目标机器上可能出现“已安装版本高于待安装版本”或者“依赖版本不满足”的冲突。如果没有同版本的UOS下载机退而求其次可以在Debian或Ubuntu上临时挂载UOS的软件源配置好/etc/apt/sources.list.d/uos.list再把架构设置为amd64或arm64后执行apt update。但这种做法风险较高因为非UOS系统自带的基础库版本和UOS可能存在细微差异下载的依赖包未必能完美匹配只建议作为最后手段。另外架构一致性是硬指标。UOS专业版支持多种CPU架构包括x86_64amd64、aarch64arm64、mips64el、sw_64等。你在下载机上准备的.deb包架构必须与离线机一致否则安装时会出现“wrong architecture”报错这属于低级错误但极易发生。2.2 三条命令确认系统信息避免白忙活在准备离线包之前我会先在下载机和目标机器上分别执行下面三条命令核对系统版本、CPU架构和软件源信息。# 查看系统版本信息 cat /etc/os-release # 查看CPU架构 uname -m # 查看软件源里某个包的可用版本 apt-cache policy 软件包名/etc/os-release里的VERSION_ID能帮你快速确认系统是1050还是1060uname -m输出x86_64、aarch64等架构标识apt-cache policy则能让你看到某个包在源里的候选版本和当前已安装版本。这三条命令的输出建议截图或者记下来后面下载完包之后再做一次对比基本能杜绝版本错配的问题。2.3 主力工具与相关命令说明离线包下载主要靠下面几组命令它们各有分工apt download 包名仅下载指定包到当前目录不安装、不处理依赖适合按清单逐个下载。apt-get install --download-only 包名会把软件包和它的依赖一次性下载到/var/cache/apt/archives/适合依赖树不深的场景。apt-cache depends 包名查看指定包的直接依赖、推荐、建议等关系。apt-rdepends 包名递归展开依赖树能看到硬件级的完整依赖链做离线包时最有用。dpkg-scanpackages从deb目录生成软件源索引构建本地APT源时使用属于dpkg-dev包。apt-rdepends不是UOS的默认安装组件需要先用sudo apt install apt-rdepends安装。如果连这个工具的安装包都拿不到可以在联网机器上先准备好apt-rdepends及其依赖的离线包也算是“先用后买”的经典操作了。3. 核心实操一条龙下载离线包和依赖环境确认清楚工具就位接下来进入实战。我会按“简单方案到完整方案”的顺序讲大家可以根据实际包数量选合适的路。3.1 简单场景用apt-get install --download-only快速收集如果你的软件依赖树不深比如就装个小工具直接用--download-only最省事。操作流程如下# 1. 更新软件源缓存 sudo apt update # 2. 清空已有缓存便于后续统一拷贝 sudo apt clean # 3. 仅下载软件及其依赖不执行安装 sudo apt-get install --download-only -y 包名 # 4. 把下载得到的deb全部拷贝到U盘或指定目录 mkdir -p ~/offline-debs sudo cp /var/cache/apt/archives/*.deb ~/offline-debs/这里的原理是apt-get install --download-only在解析依赖时和正常安装完全一样它会走一遍完整依赖解析流程然后把所有需要的deb文件下载到本地缓存目录只是不执行dpkg安装步骤。这样做的好处是简单坏处是会把Recommended推荐包也一并拉下来而且如果目标机器上已经安装了某些依赖下载包里可能没有包含它们导致在干净的离线机器上装的时候缺包。为了避免这种情况可以在命令里加上--no-install-recommends参数只下载必要依赖减少无用包。但反过来如果内网机器上可能缺少某些推荐组件你又需要这些推荐组件提供完整功能那就不能加这个参数。取舍标准取决于你对目标环境“干净程度”的判断。3.2 依赖树复杂时用脚本递归下载全套依赖当要装的软件依赖很深比如ffmpeg、mysql、nginx这类动不动牵扯几十个依赖包依赖里又有依赖手工用apt download一个个敲命令根本敲不过来。这时候我会用一个小脚本实现宽度优先的递归下载。先创建一个脚本文件down-debs.sh#!/bin/bash # 递归下载 deb 包及其依赖 # 用法: ./down-debs.sh 包名1 包名2 ... DOWNLOAD_DIRoffline-debs mkdir -p $DOWNLOAD_DIR cd $DOWNLOAD_DIR || exit 1 # 用队列实现递归遍历 processed queue$* while [ -n $queue ]; do # 取出队首包名 pkg$(echo $queue | awk {print $1}) queue$(echo $queue | awk {$1; print $0}) # 跳过已处理的包 if echo $processed | grep -qw $pkg; then continue fi processed$processed $pkg # 下载包本体 apt-get download $pkg 2/dev/null || { echo 下载失败: $pkg; continue; } # 获取直接依赖包含 Depends 和 Recommends deps$(apt-cache depends $pkg | grep -E ^(Depends|Recommends) | awk {print $2} | grep -v ^ | sort -u) # 把新依赖加入队列尾部 for dep in $deps; do if ! echo $processed | grep -qw $dep; then queue$queue $dep fi done done echo 下载完成包数量: $(ls *.deb | wc -l)给脚本加执行权限后运行chmod x down-debs.sh ./down-debs.sh nginx脚本的核心思路是用一个队列做宽度优先遍历。第一次从队列取出nginx下载它再查询nginx的直接依赖把依赖追加到队列尾部。随后循环处理队列里的每个包下载后再查依赖新依赖继续入队直到队列为空。为了避免重复下载脚本用processed变量记录了所有处理过的包名。需要注意apt-cache depends输出里形如xxx的包名是虚拟包或者替代包比如default-mysql-server、x-terminal-emulatorapt-get download无法直接下载这些包名。脚本里用grep -v ^做了过滤但如果某个包只依赖虚拟包那这个虚拟包对应的真实实现包还需要你手工确认后用脚本参数补上。例如nginx依赖init-system-helpers一般没问题但遇到default-jre这种虚拟包时你就得额外指定openjdk-11-jre-headless之类的实际包去下载。3.3 最推荐先导出完整依赖清单再用循环定点下载脚本虽好但在依赖树特别大时递归下载的速度和失败率都不好控制。更稳妥的做法是先用apt-rdepends一次性导出完整依赖清单然后对这个清单做清洗最后批量下载。# 安装 apt-rdepends sudo apt install apt-rdepends # 导出直接/间接依赖清单 apt-rdepends nginx dep-list.txtapt-rdepends输出里没有缩进的行是“软件包本身或依赖包”的名字有缩进的行是“这个包被什么包依赖”或“依赖关系说明”。我们要提取有效包名可以用apt-rdepends nginx | grep -E ^[^ ] | sort -u package-list.txt然后就可以循环下载mkdir -p offline-debs cd offline-debs while read -r pkg; do echo 正在下载: $pkg apt-get download $pkg 2/dev/null || echo 跳过/失败: $pkg done ../package-list.txt这个方式的优点是可以先人工查看package-list.txt剔除明显不需要的包或补充缺失的真实包再开始下载出错时可以定位到具体包名而不是在递归脚本的黑盒里打转。apt-rdepends还有个参数--with-recommends要不要加取决于你的软件是否需要推荐包方法同前。如果下载过程中遇到“Unable to locate package”基本都是虚拟包、元包或私有包名导致用apt search找到真实包名替换后再下载即可。3.4 下载完成后必须做的完整性校验把一堆deb拷进U盘之前一定先校验一遍。我用的校验手段有两个层次。第一层检查每个deb的架构和版本是否符合预期。用dpkg-deb -I可以在不安装的情况下读取deb的控制信息dpkg-deb -I ./nginx_1.18.0-3_amd64.deb | head -20重点看Architecture字段和Version字段和离线机的uname -m、apt-cache policy输出对比确认没有架构错配和版本倒挂。第二层生成哈希校验文件方便目标机器安装前再次核验文件完整性md5sum *.deb MD5SUMS # 或更推荐 sha256sum *.deb SHA256SUMS把整个offline-debs目录复制到U盘或者移动硬盘后在目标机器上执行cd 离线包目录 sha256sum -c SHA256SUMS这一步能有效避免U盘拷贝过程中文件损坏、半截文件进入安装流程的问题。我见过太多人跳过校验结果复制到一半文件损坏安装时报错排查半天也找不到线索。4. 目标机器离线安装两种姿势和取舍离线包已经拿到内网机器上接下来就是安装了。方法主要有两种我建议优先用第二种但第一种也值得了解因为你总会遇到只能硬装的场景。4.1 姿势一用dpkg -i批量硬装快但有坑最直觉的做法是进到deb目录一条命令全部丢给dpkgcd /path/to/offline-debs sudo dpkg -i *.deb这个命令会把当前目录下所有deb包尝试安装。如果包数量少、依赖树浅它是能跑通的。但问题也很明显如果某个包依赖另一个包而后者的安装顺序排在它后面dpkg -i安装前者时就会因为找不到依赖而报错。虽然报错后你把剩余包继续装完再回头执行sudo apt install -f可以修复依赖但离线机器如果没配置本地源apt install -f会因为找不到源而无法完成修复。dpkg -i *.deb适合的场景是你非常确定下载的包集是完整的且安装顺序无所谓每个包都能找到依赖。一旦中途报错我的建议是不要反复重试单包直接把所有包列出来确认是否漏了依赖或者干脆把报错信息拍下来回到联网机器重新补包。4.2 姿势二用apt install ./*.deb让apt自己排依赖这是我在批量部署时最常用的方式强烈推荐。cd /path/to/offline-debs sudo apt install ./*.deb -y注意这里的命令是apt而不是dpkg。apt会分析当前目录下所有deb包的依赖关系优先从这些deb包中寻找满足条件的依赖如果找不到再去已配置的软件源中寻找。这意味着只要你的离线包集是完整闭环的apt会自动安排安装顺序把互相依赖的包按正确顺序处理好。如果包集不完整apt会明确告诉你“无法满足依赖”并列出缺失的包名。这比dpkg的报错要好排查得多因为你只要根据提示的名字回联网机器补下载即可。有一点需要注意apt install ./*.deb要求所有deb都在一个目录里如果零散放在多个目录命令要分别执行或者把deb文件先合并到一起。4.3 安装完成后的验证和固化安装完成后不能直接收工我习惯做三步验证。第一步用dpkg -l查看关键包的安装状态dpkg -l | grep -E nginx|mysql|php输出第一列是ii就表示正确安装。第二列是rc、iU等状态就需要处理rc表示包已卸载但配置文件残留iU表示包处于半安装状态。第二步用包管理器做一次完整性检查sudo apt-get check这个命令会检查所有已安装包的依赖是否满足如果不满足会列出问题比逐个dpkg -l快得多。第三步如果你希望内网机器以后不要随意升级这些离线安装的包可以锁定关键包的版本sudo apt-mark hold 包名锁定后后续的apt upgrade就不会动这些包了避免因为版本漂移导致依赖崩坏。这在生产环境里很重要因为离线部署的包集是经过验证的一旦自动升级很可能触发新的依赖缺失问题。5. 进阶把离线包变成本地APT源一劳永逸如果只是装一两台机器上面按目录安装已经够用。但当你面对的是一批同配置机器或者后续需要持续增补软件最合适的方案是把U盘里的deb包做成一个真正的本地APT源。做完之后内网机器就像连了一个本地镜像仓库apt install直接能用再也不用每次拷deb灌进去了。5.1 为什么推荐本地源而不是散装deb散装deb的问题是包一旦多了人工维护依赖完整性会越来越吃力。而且安装时总得执行apt install ./*.deb如果某台机器已经装有部分包apt可能因为版本冲突拒绝安装你又得手工干预。本地APT源把“包集合”变成“软件仓库”面向apt提供了一套完整的元数据索引Packages文件和可选签名信息。apt可以像处理远程源一样处理本地源它能够准确知道这个源里有哪些包、依赖关系如何安装时自动选择合适的包和版本体验几乎等同于联网安装。5.2 用dpkg-scanpackages生成源索引首先在存放所有deb文件的目录下生成索引文件。dpkg-scanpackages一般包含在dpkg-dev包里如果当前机器没装先安装sudo apt install dpkg-dev然后进入deb目录执行cd /path/to/offline-debs dpkg-scanpackages . /dev/null Packages gzip -k Packages执行后目录下会出现一个Packages文件和Packages.gz压缩文件。这个文件就是APT源的“货架清单”里面记录了每个deb的包名、版本、依赖关系、文件路径、校验和等信息。没有这个文件apt就不知道这个目录里有什么软件。如果dpkg-dev装不上还有个变通办法手动写一个最简单的Packages文件但格式容易出错还是建议在线下载机把dpkg-dev装好后再把deb和生成的索引一起拷到内网。5.3 在内网机器上配置并安装把包含Packages文件和所有deb文件的目录拷到目标机器的某个路径比如/opt/offline-debs。然后添加一个apt源配置echo deb [trustedyes] file:///opt/offline-debs ./ | sudo tee /etc/apt/sources.list.d/local-offline.list这里有几处细节需要注意。file://表示本地文件系统源后面跟着的路径必须是deb文件所在目录的绝对路径。./表示这个源直接对应目录下的包而不是子目录。[trustedyes]表示跳过GPG签名验证内网离线环境一般没问题但如果有严格安全要求你需要按5.4节做签名。执行更新并安装sudo apt update sudo apt install nginx -yapt会读取本地源的Packages索引自动解析nginx和它的依赖从本地源中完成安装。至此你等于在内网搭了一个微型软件仓库后续往这个目录丢新的deb并重新生成Packages就能持续扩展可用的软件集。5.4 有签名要求的离线源怎么做可选[trustedyes]在部分安全要求严格的环境里不满足审计要求。如果你需要带签名的本地源可以按下面流程操作。在一台有gpg的联网机器上生成一对密钥gpg --gen-key然后在deb目录下生成Release文件并签名apt-ftparchive release . Release gpg --clearsign -o InRelease Release gpg -abs -o Release.gpg Release导出公钥拷贝到目标机器并导入gpg --export --armor offline-source-pubkey.asc # 目标机器上 sudo cp offline-source-pubkey.asc /etc/apt/trusted.gpg.d/同时在源配置里去掉[trustedyes]deb file:///opt/offline-debs ./然后sudo apt updateapt会通过公钥验证本地源的Release签名。注意新版Debian系系统对apt-key add方式的支持已经减弱我更推荐直接放到/etc/apt/trusted.gpg.d/目录兼容性更好。6. 常见问题与排查技巧实录离线部署最耗时间的不是操作而是排错。我把自己在UOS离线安装过程中踩过的高频问题整理成了一份速查遇到直接对照找答案。6.1 版本不一致导致的依赖错乱症状在联网机器上下载的deb包放到内网机器安装时提示某个依赖版本不满足或者提示“已安装的版本高于要安装的版本”。原因下载机和目标机器的软件源版本存在差异依赖解析基于不同的源基线。解决回到2.2节用apt-cache policy对比同一包在两台机器上的可用版本。如果下载机版本比目标机高要么在下载机上把源版本降到和目标机一致要么直接复制目标机的/etc/apt/sources.list等源配置到下载机再apt update后重新下载。6.2 遇到“GPG error”或公钥验证失败症状sudo apt update或安装时报“The following signatures couldnt be verified”并提示公钥缺失。解决处理官方源问题时需要导入对应公钥方法见5.4节。处理本地源问题时最简单的办法是改用[trustedyes]配置但要有意识地意识到这等同于不要签名只在可信内网中使用。若必须验证签名就按要求导入公钥后再操作。6.3 架构不对装不上症状安装时提示“wrong architecture arm64”。原因你把aarch64架构的deb包安装到了amd64机器上或者反过来。解决先执行uname -m确认架构。UOS的x86平台是x86_64ARM平台通常是aarch64龙芯平台可能是mips64el申威平台是sw_64等。在下载离线包之前务必用dpkg-deb -I抽查几个包核对Architecture字段。6.4 下载时提示“Unable to locate package”症状在下载机上执行apt-get download 包名或脚本循环时提示找不到这个包。原因要么软件源里确实没有这个名字的包要么该包是虚拟包、元包要么该包来自私有/商业源没有启用。解决先用apt search 关键词搜索包名确认真实包名。如果软件本身要自己下deb包比如WPS、某些商业软件就从官方渠道下载deb单独放进包集不依赖apt源。如果遇到虚拟包通过apt-cache depends看它被哪些实现包满足再下载对应的实际包。6.5 软件注册与路径绑定问题不能剪切粘贴移动安装目录症状有人把装好的WPS或Office安装目录直接拷贝到另一台机器结果目标机器上软件无法启动或者出现文件关联失效。原因如1.2节所述商业软件安装时进行了系统级注册单纯复制安装目录无法迁移注册信息。WPS、Office这类软件在安装时注册了文档打开方式、桌面入口、授权信息和用户数据路径这些都不在安装目录里。剪切粘贴安装目录不仅不能节省部署时间还会破坏原机器和目标机器的两边注册状态。解决务必在每个目标机器上完整安装从官网或源里获取的官方deb包。离线部署时把这些deb和依赖一起放进包集用apt install ./*.deb或本地源安装。不要试图通过拷贝已安装目录实现“绿色版”。这也解释了一个被反复问到的问题“为什么离线包要带依赖不能直接把整个软件文件夹拷过去”因为UOS上的软件不是绿色软件安装动作本身就是注册过程的一部分。6.6 缓存目录越来越大、同名多版本混杂症状/var/cache/apt/archives里积压了大量历史deb手动拷贝时混入多个版本安装时版本冲突。解决apt-get install --download-only前先执行sudo apt clean清空缓存避免旧版本干扰。如果已经混了多版本可以用ls /var/cache/apt/archives/ | grep 包名 | sort -V查看版本顺序只保留需要的那一个。结尾就用我自己的经验收个尾。踩过几次坑之后我现在做离线包的习惯是先严格核对版本和架构再按“依赖树清单、分批下载、完整性校验、本地源/目录安装”的流程走尤其批量部署时宁愿先花半小时把本地源配好也不要拿一堆散装deb逐台硬装。另外一个小建议每做一批离线包就在包目录外面加一个说明文件标注系统版本、架构、源地址、生成日期再打成一个tar快照保存。下次遇到同型号机器直接解压就能用能省掉大半天的重复排查时间。这个习惯帮我在后续几个现场省了无数事。