第一次在Kylin系统上做离线部署时我以为把软件包的.deb文件拷进内网服务器dpkg -i一下就能收工。结果连续踩了三小时的坑先是发现fluent-bit的依赖链比预想长得多接着发现手上这批包是amd64架构目标机却是arm64最后一台机器上还残留了dpkg锁安装直接被卡死。那台机器在隔离的网段里没有外网身边只有一块U盘。也就是从那次之后我开始认真梳理Kylin系统离线环境下dpkg依赖包的部署方法后来这套方法帮我搞定了大量内网交付。这篇文章不会跟你讲太多虚的就是一个完整的可落地方案依赖解析怎么做、批量下载怎么下、离线机上的本地仓库怎么搭、安装时的高频故障怎么排查最后再用一台Kylin V10 ARM64机器离线安装fluent-bit给你完整复盘一遍。适合信创项目交付、运维工程师以及所有在无外网环境里折腾过Linux软件包的人。1. 内网Kylin环境下的依赖包困境为什么离线部署不能靠暴力拷贝很多人第一次接触离线安装下意识的做法就是找一台能上网的机器把需要的.deb包下载下来U盘拷过去然后dpkg -i xxx.deb。这个思路在只有一两个包、且目标系统刚好齐全的情况下能跑通但一旦软件稍微复杂一点就会出各种幺蛾子。1.1 “把.deb拷过去”为什么行不通根本原因在于.deb包不是孤立的。拿fluent-bit举例它本身是一个日志采集器deb包安装时依赖libc6、libssl、zlib1g等基础库这些库又可能依赖其他更底层的包。一个看似简单的软件背后的依赖链可能长达十多个包。手动apt-cache depends一个个去查查到第三层就容易漏。更麻烦的是版本匹配。Kylin V10有SP1、SP2、SP3等版本同一个软件在不同系统版本上依赖的基础库版本要求可能完全不同。比如A机器上编译好的包依赖libssl1.1B机器默认只有libssl3你把包拷过去dpkg -i直接报依赖不满足。架构问题也是重灾区。Kylin V10同时支持x86_64和ARM64aarch64平台对应dpkg架构分别是amd64和arm64。很多人习惯在自己办公电脑通常是x86上下载软件包结果拷到鲲鹏、飞腾这些ARM服务器上安装时直接提示“package architecture (amd64) does not match system (arm64)”。还有一个隐蔽问题dpkg维护着自己的包数据库/var/lib/dpkg/status。如果上一次安装中断数据库可能停留在未完成状态后面你装什么都会提示先运行dpkg --configure -a。离线环境下没有apt源修复起来就比在线环境麻烦得多。1.2 dpkg与apt在离线场景中的分工要理解离线部署的正确姿势先得搞清楚dpkg和apt它们各自扮演什么角色。dpkg是底层包安装器负责安装、卸载、查询单个.deb包但它本身不解决依赖关系。你给它一个包装了就装了依赖缺不缺它不管。apt是上层包管理工具它维护软件源索引解析依赖树下载依赖包。apt install之所以比dpkg -i好用就在于它会自动把依赖包一起装上。离线部署的本质就是把apt依赖解析这件事情提前到联网机器上做完把解析出来的所有依赖包统一打包再在离线机器上重建一个“本地软件源”让目标机的apt也能像在线环境一样解析依赖和顺序。所以正确的流程应该是联网机同版本、同架构下载全部依赖包 → 整理归档 → 拷入离线机 → 建立本地仓库 →apt install安装。2. 动手之前先摸清家底版本、架构与工具链确认我在做任何离线部署前不会急着下载软件包而是先花十分钟把目标机器的情况摸清楚。这一步省了后面可能要花几小时来填坑。2.1 确认Kylin版本和CPU架构登录目标机器先跑三条命令cat /etc/os-release uname -m dpkg --print-architecture/etc/os-release会告诉你系统版本是V10还是V10 SP1/SP2以及系统名称。uname -m显示内核架构dpkg --print-architecture显示dpkg打包架构离线部署时这两个必须对应上平台uname -mdpkg --print-architecturex86服务器/桌面x86_64amd64ARM服务器鲲鹏/飞腾等aarch64arm64这一步特别重要因为后面的下载、构建本地源、安装全都要围绕这个架构来。我还见过有人在ARM机器上装x86的rpm转deb包最后运行时报“Exec format error”就是架构不匹配的典型结果。另外Kylin的服务器版和桌面版的软件包默认源也不同同一个软件在桌面版能装上服务器版可能会因为缺少图形库依赖而失败。所以如果目标机是服务器版下载依赖时最好在服务器版环境里下载。2.2 准备一台“同版本同架构”的联网机器离线部署最理想的下载环境是和目标机完全同版本、同架构的联网机器。如果你手头没有物理机虚拟机也行用VMware、KVM装一个相同版本的Kylin只要能联网即可。Docker容器不一定完全可靠因为容器与宿主共享内核某些依赖的检测结果会和物理机有差异。联网机确定好后先更新源sudo apt-get update如果这台机器也访问不了外网那就只能想办法让它的apt源能通。注意Kylin系统默认软件源可能指向官方仓库如果网络受限需要先配置一个能访问的镜像源或者内网源这一步就属于另外一个话题了这里按下不表。2.3 必备工具清单下面这些工具要么在联网机上用来下载要么在离线机上用来建仓库提前确认它们是否可用apt-get download下载单个deb包不安装联网机必备apt-get install --download-only只下载软件包和依赖不安装这是离线部署的核心神器dpkg-scanpackages生成本地软件仓库索引来自dpkg-dev包离线机上也要有dpkg-deb查看deb包信息、解包通常自带md5sum校验文件完整性生成校验清单如果你计划手动递归解析依赖树还可以在联网机上装一个apt-rdepends不过我更推荐用apt-get install --download-only自动搞定后面细说。3. 依赖树的梳理与批量下载在联网机上准备好一切这一章是整个离线部署里最有技术含量、也最需要耐心的部分。很多人卡在这里主要是因为不清楚依赖到底包含哪些包用什么方式收集才能既不遗漏也不冗余。3.1 先用apt-cache depends看清依赖关系虽然我推荐用--download-only自动下载但看依赖关系依然是必要的一步。它能帮你了解目标软件到底依赖什么避免下载出冗余包或在部署时一脸懵。假设目标是fluent-bit在联网机上执行apt-cache depends fluent-bit输出会包含几种关系字段Depends强依赖必须安装Recommends推荐安装不装也能运行但部分功能会缺失Suggests建议安装通常和软件特性相关Conflicts冲突不能共存Replaces替换会替代某些包离线部署的生产环境里我通常只保留DependsRecommends看情况Suggests一律不装。因为离线环境里多一个包就多一份出错风险能用的事项保持最小集最稳定。如果想递归查看整棵依赖树可以用apt-rdepends fluent-bit但这个工具要提前安装而且输出结果比较长依赖包里的重复项也很多。所以我实际工作中很少逐层手动查而是直接走下一节的方法。3.2 更省事的批量下载apt-get install --download-onlyapt-get install --download-only是离线部署里效率最高的命令。它的作用是按照apt的依赖解析规则把软件包和所有依赖下载到本地缓存目录/var/cache/apt/archives/但不进行安装。在联网机上执行sudo apt-get clean sudo apt-get install --download-only --no-install-recommends -y fluent-bit这里的几个参数值得说明--download-only核心开关只下载不安装--no-install-recommends不拉取推荐依赖避免下载一堆用不到的包保持依赖闭包最小化-y自动确认避免交互卡住先执行apt-get clean是为了清空缓存确保后面拷出来的deb都是本次需要的不会混入历史残留包如果你的软件包不在系统的软件源里而是从官网/官方GitHub手动下载的deb文件也没关系。把deb文件放到一个目录然后用类似下面的命令解析它的依赖cd /path/to/downloaded-debs sudo apt-get install --download-only --no-install-recommends -y ./fluent-bit_xxx_arm64.debapt会读取这个deb文件解析它的依赖把缺失的依赖包下载到缓存本地这个deb本身不会被安装但你已经拿到了完整的依赖闭包。这个方法的优势是apt的依赖解析算法相当成熟能正确处理复杂依赖链、虚拟包、多版本选择等问题比人肉递归查依赖靠谱得多。3.3 下载完成后的归档整理与校验下载完成后/var/cache/apt/archives/里会有一堆.deb文件。把它们统一拷贝到一个目录并生成校验信息mkdir -p ~/offline-debs cp /var/cache/apt/archives/*.deb ~/offline-debs/ cd ~/offline-debs md5sum *.deb debs.md5 ls *.deb | wc -l拷贝时注意/var/cache/apt/archives/partial/目录下可能会有未下载完成的文件不要拷贝进去。apt-get clean已经清空了缓存下载完后的文件都在archives根目录下。建议顺手抽查一下关键包的架构dpkg-deb -I fluent-bit_*.deb | grep Architecture确保是arm64。如果下载了很多包可以批量看for f in *.deb; do echo -n $f: ; dpkg-deb -I $f | grep -E ^ Architecture: | awk {print $2}; done | sort | uniq -c这一步能帮你快速发现有没有混入其他架构的包。归档完成后把offline-debs整个目录拷贝到U盘或传输到内网机器。4. 本地仓库的搭建与目标机上的dpkg安装实战把依赖包带进内网后接下来要在目标机上搭建本地仓库。这一步做对了后续安装就是一条apt install命令的事做不对你就要在dpkg -i的依赖泥潭里打滚。4.1 把deb包目录改造成本地软件源先在目标机上创建目录并把包拷进去sudo mkdir -p /opt/offline-debs sudo cp /path/to/offline-debs/*.deb /opt/offline-debs/ cd /opt/offline-debs关键一步生成软件仓库索引文件Packages.gz。apt需要靠这个索引来识别目录里的deb包以及它们的依赖关系。在deb包所在目录下执行sudo dpkg-scanpackages . /dev/null | gzip Packages.gz解释一下这条命令dpkg-scanpackages扫描当前目录下的所有deb包生成包含包名、版本、依赖、架构等信息的Packages文件第二个参数/dev/null是指定override文件本地仓库不需要额外覆盖信息所以传空通过管道用gzip压缩成Packages.gzapt更习惯读取压缩后的索引文件执行完目录下会多出Packages和Packages.gz两个文件。注意dpkg-scanpackages命令来自dpkg-dev包。如果目标机器上提示command not found说明系统没装dpkg-dev需要提前在联网机的下载列表里把dpkg-dev及其依赖一起打包带进来。这也是为什么我在前面强调下载时宁可多带一个dpkg-dev也不要等到了离线机才发现缺工具。4.2 修改sources.list让apt识别本地源备份原有软件源配置然后再写入本地源的地址sudo cp /etc/apt/sources.list /etc/apt/sources.list.bak sudo bash -c echo deb [trustedyes] file:///opt/offline-debs ./ /etc/apt/sources.list这里几个要点file:///opt/offline-debs是本地源的路径必须是绝对路径./表示deb包就在该目录根下和dpkg-scanpackages生成索引时使用的路径前缀一致[trustedyes]表示信任这个源跳过Release/InRelease签名校验。本地自建仓库没有签名如果不加这个选项apt update会报“repository is not signed”的错改完后执行更新sudo apt-get update如果能看到类似下面的输出说明本地源生效Hit:1 file:/opt/offline-debs ./ Reading package lists... Done Building dependency tree... Done如果提示File not found大概率是Packages.gz文件位置不对或者sources.list里的路径写错了。4.3 安装阶段的命令顺序与选择本地源配置好之后安装就很轻松了sudo apt-get install -y fluent-bitapt会从本地源里解析依赖、排序、逐个安装。这条路是最稳的因为apt会自动处理依赖顺序。如果离线机上已经手动拷入了一批deb包不想建本地源也可以直接用dpkg批量安装sudo dpkg -i /opt/offline-debs/*.deb但这个方法有个隐患dpkg -i不会按依赖顺序排序如果命令行传入的包顺序恰好反了它会报依赖不满足。所以更推荐的做法是sudo apt-get install -y /opt/offline-debs/*.deb这条命令让apt来处理本地文件列表里的依赖顺序。如果提示“The following packages have unmet dependencies”再执行sudo apt-get -f install -yapt-get -f install会自动修复损坏的依赖关系把缺的依赖补装或把冲突的包卸载。在离线环境中只要依赖包都在本地仓库里这个命令通常能顺利收尾。5. 部署中的高频故障lock、架构不匹配与依赖断裂的完整排查链路离线部署最耗时间的往往不是下载和安装而是一堆莫名其妙的报错。我把实际踩过的几个高频故障整理成排查链路每个都按“现象→原因→处理”的顺序展开遇到问题可以直接照着走。5.1 waiting for cache lockdpkg锁导致的安装卡死这是搜索量最高的问题也是离线部署翻车现场最常见的报错。典型输出Waiting for cache lock: could not get lock /var/lib/dpkg/lock-frontend. It is held by process 2345 (apt-get)看到这句话说明系统中存在一个正在运行的apt/dpkg进程或者上一次运行异常退出后锁文件没被释放。排查链路先查有没有apt/dpkg进程还在运行ps aux | grep -E apt-get|apt|dpkg如果输出里有apt-get进程先看它在干什么。在离线环境里这个进程很多时候是因为apt update时源不可达卡在“等待超时”上。如果确认它不是你正在执行的任务就结束它sudo kill 2345如果普通kill杀不掉再用kill -9。进程确实没了但锁文件还占着检查三个位置ls -l /var/lib/dpkg/lock /var/lib/dpkg/lock-frontend /var/lib/apt/lists/lock确认没有任何apt相关进程后删除锁文件sudo rm /var/lib/dpkg/lock-frontend /var/lib/dpkg/lock sudo rm /var/lib/apt/lists/lock最后执行一次修复把可能中断的安装状态恢复sudo dpkg --configure -a重要提醒不要一上来就删锁文件。锁存在的意义是防止多个apt进程同时操作数据库。如果真有apt进程正在安装你强行删锁轻则数据库错乱重则系统包管理崩溃。删锁是最后手段前提是你已经确认没有apt/dpkg进程存活。5.2 架构不匹配amd64的包装不到arm64上在Kylin离线部署里尤其是鲲鹏、飞腾这些ARM平台的机器上架构不匹配的报错很常见dpkg: error processing archive xxx.deb (--install): package architecture (amd64) does not match system (arm64)排查链路确认目标机器架构uname -m dpkg --print-architecture查看报错deb包的架构dpkg-deb -I xxx.deb | grep Architecture如果确实混入了amd64的包回到联网机重新下载arm64版本。这里有个容易犯的错很多人的联网机是x86执行apt download时默认下载的就是amd64包。你可以在联网机上临时添加arm64架构sudo dpkg --add-architecture arm64 sudo apt-get update然后用类似方式下载arm64的依赖包。不过更稳妥的方案是找一台arm64的联网机器比如云上的arm64实例或者手头的飞腾开发机来做下载。同架构机器下载出来的依赖天然就是对的省去很多麻烦。5.3 依赖版本冲突与broken packages有时候安装时apt会提示The following packages have unmet dependencies: libfoo-dev : Depends: libbar ( 1.2.3) but 1.2.4 is to be installed这种“依赖版本不满足”的报错在线环境下可能换个源就解决了离线环境下要麻烦一些。排查链路先尝试自动修复sudo apt-get -f install -y查看本地仓库里那个冲突依赖的可用版本apt-cache policy libbar查看报错deb包要求的版本范围dpkg-deb -I libfoo-dev*.deb | grep -E Depends|Version如果本地仓库缺少指定版本回联网机单独下载对应版本apt-get download libbar1.2.3然后把下载好的deb拷进离线机的/opt/offline-debs重新执行dpkg-scanpackages和apt-get update。如果版本要求过于严苛实在凑不齐考虑换软件版本。例如老版本fluent-bit依赖libssl1.1新版本系统只有libssl3那就优先选择兼容libssl3的新版本软件而不是硬着头皮去手动移植libssl1.1。实践经验告诉我离线部署最忌讳的是混合不同系统版本的软件包。Kylin V10 SP1的第三方包强行装到SP2上经常会触发这种依赖版本冲突。所以下载前一定要确认联网机和目标机是同版本。5.4 dpkg中断后的恢复离线环境里最怕的是安装到一半断电、SSH断连再次执行dpkg时系统提示dpkg was interrupted, you must manually run sudo dpkg --configure -a to correct the problem.排查链路按提示先执行sudo dpkg --configure -a如果某个包配置失败去/var/log/dpkg.log里定位失败的具体包grep -E error | fail /var/log/dpkg.log | tail -n 20对不能完成配置的包强制移除后重新安装sudo dpkg --remove --force-remove-reinstreq 包名清掉可能残留的锁文件sudo rm /var/lib/dpkg/lock-frontend /var/lib/dpkg/lock重新执行安装。这里要记住dpkg --configure -a是中断后的第一动作不要上来就删锁。这个命令会把所有处于“半安装”状态的包尝试重新配置一遍大部分中断场景靠它就能恢复。6. 完整实例复盘Kylin V10 ARM64离线安装fluent-bit下面用一个完整实例把整个流程串起来。场景是一台Kylin Linux Advanced Server V10 ARM64内网服务器需要离线安装fluent-bit用于采集日志。这台机器不能访问外网我从有外网的办公区操作。6.1 联网机上的操作下载deb包和依赖我在办公区准备了一台同样为Kylin V10 ARM64架构的虚拟机确保架构一致。先在联网机上确认架构uname -m # 输出aarch64 dpkg --print-architecture # 输出arm64由于Kylin默认软件源的软件包列表里不一定有fluent-bit我直接到fluent-bit官方GitHub Releases页面下载了适配arm64的deb安装包放到工作目录下mkdir -p ~/fluent-bit-offline cd ~/fluent-bit-offline # 这里假设已经把 fluent-bit_3.x_arm64.deb 上传到了该目录下载依赖闭包。先清空apt缓存避免把历史残留包混进来sudo apt-get clean sudo apt-get install --download-only --no-install-recommends -y ./fluent-bit_3.x_arm64.deb命令执行后apt会分析这个本地deb文件的依赖自动下载缺失的依赖包到/var/cache/apt/archives/。稍等片刻后把缓存里的deb和最初的fluent-bit的deb一起归档cp /var/cache/apt/archives/*.deb ~/fluent-bit-offline/ cp ~/fluent-bit-offline/fluent-bit_3.x_arm64.deb ~/fluent-bit-offline/ cd ~/fluent-bit-offline md5sum *.deb debs.md5 ls *.deb | wc -l同时我还会多带一个dpkg-dev包以便离线机上用dpkg-scanpackages生成本地源索引sudo apt-get install --download-only -y dpkg-dev cp /var/cache/apt/archives/*.deb ~/fluent-bit-offline/最后把我需要的全部deb打包cd ~/fluent-bit-offline tar czf fluent-bit-offline.tar.gz *.deb debs.md5用U盘或内网传输工具把它传到目标机器上。6.2 离线机上的操作搭本地源并安装在目标Kylin服务器上把压缩包解压到/opt/offline-debssudo mkdir -p /opt/offline-debs sudo tar xzf fluent-bit-offline.tar.gz -C /opt/offline-debs cd /opt/offline-debs如果离线机上已经有dpkg-scanpackages直接生成索引。如果没有这个命令来自dpkg-dev我们需要先手动安装dpkg-dev。这里注意由于dpkg-dev的deb也在同一目录可以先用apt直接解析本地deb来安装它sudo apt-get install -y /opt/offline-debs/dpkg-dev*.deb然后生成本地仓库索引sudo dpkg-scanpackages . /dev/null | gzip Packages.gz接下来配置本地源sudo cp /etc/apt/sources.list /etc/apt/sources.list.bak sudo bash -c echo deb [trustedyes] file:///opt/offline-debs ./ /etc/apt/sources.list sudo apt-get update最后安装fluent-bitsudo apt-get install -y fluent-bit如果apt提示找不到fluent-bit有可能是本地目录里没有这个包或Packages.gz没生成成功。可以检查目录下是否存在fluent-bit_*.deb和Packages.gz。也可以用指定文件的方式安装sudo apt-get install -y /opt/offline-debs/fluent-bit_*.deb6.3 验证安装结果与后续维护安装完成后先确认版本fluent-bit --version然后确认动态依赖是否齐全。这一步很关键能验证依赖闭包是否完整闭包有没有漏掉动态库ldd /usr/bin/fluent-bit | grep not found如果没有任何输出说明所有动态库依赖都满足。如果有not found说明还有动态库依赖缺失需要在联网机上把对应的库包装进来。再确认服务状态sudo systemctl enable fluent-bit sudo systemctl start fluent-bit sudo systemctl status fluent-bit看到active (running)就说明部署成功。最后我习惯把当前系统的包状态导出备份dpkg-query -W -f${Package} ${Version}\n | grep -E fluent-bit|^lib|^zlib|^openssl installed-packages.txt这个文件用于后续在另一台同版本机器上部署时快速对比依赖是否一致。7. 离线部署的几个收尾习惯前面流程走通但真正让效率提升的是最后这几个习惯都是从多次踩坑里攒下来的。第一U盘里永远多备一个dpkg-dev的deb包。这个包体积不大但它里面的dpkg-scanpackages在离线机上几乎是必需品。很多机器为了最小化安装根本不会预装dpkg-dev。你到了现场才发现没有这个命令又没有外网那才叫寸步难行。第二安装完成后备份/var/lib/dpkg/status文件。这个文件记录了系统全部已安装包的状态我每次部署成功都会cp /var/lib/dpkg/status /var/lib/dpkg/status.bak。下次在另一台机器上部署时直接对比两份status文件就能快速知道目标机器还缺什么依赖比一个个试错高效得多。第三如果是信创环境下批量交付强烈建议维护一个“本地源更新记录”。每次有新软件包要加入就在台式机上同步更新deb目录重新生成Packages.gz然后把增量包通过内网传过去。时间久了这个本地源会成为团队内部的“私房软件仓库”后续所有离线部署都会越来越快。Kylin的离线部署其实并不神秘dpkg加本地仓库这套思路适用面非常广。我今天拿fluent-bit做了完整演示你换成nginx、docker-ce、dolphinscheduler的插件包只要它提供deb包流程都一样。希望这篇整理能让你在下次面对隔离网络时少走几个我走过的弯路。
