☰
openEuler离线升级包制作:从dnf抓包到内网本地repo部署全流程
2026/10/14 11:41:14 网站建设 项目流程

简介:这份离线升级包面向 openEuler 系统管理员与运维人员,用于将 openEuler 22.03 LTS SP1 平滑升级至 SP3,尤其适合内网隔离、无法访问外部软件源的服务器环境。包内已按升级需求处理了 rpm 依赖关系,并在全新安装的 SP1 系统上验证通过,可显著减少离线升级时逐个排查依赖、反复下载补丁的工作量。资源共 508 个文件,主要包含 501 个 rpm 升级包,另有 3 个 gz、3 个 bz2 和 1 个 xml 文件,用于构建本地 yum 源时提供仓库元数据,整体压缩包约 389.15 MB。文件结构接近标准软件源布局,既可直接按清单应用升级,也可挂载为本地源供批量主机使用。目前已有 906 人学习下载,适合需要在无外网条件下完成 openEuler SP1 到 SP3 升级的运维场景。 所谓“补丁”,平时有网的时候就是个dnf upgrade -y的事,可一旦服务器部署在隔离内网、只开放业务端口,公网 yum 源根本连不上,这时候你就知道离线升级包有多救命。我最近刚给一批搭载 openEuler 22.03 LTS SP3 的服务器做过一轮补丁同步,踩了不少坑,也理顺了一套从“联网机器抓包”到“内网机器装包”的标准流程。这篇就把完整做法、命令和坑都写出来,给正被离线升级折磨的运维同学一个可抄的作业。

先说清楚适用范围:openEuler 22.03 LTS 是长期支持版本,SP3 是它的第三个服务包,和 SP2 相比主要是把前面若干个月的 bug 修复、CVE 安全补丁统一打包推进。如果你在内网维护的是 x86_64 或 aarch64 两种架构的机器,且没有公网权限,那这篇文章就是给你准备的。

1. 先理解离线升级包的层次:补丁包、软件仓库、全量 ISO

很多人一听到“离线升级包”,脑子里以为就是下载几个 RPM 文件拷进去装。真到生产环境你会发现,这种思路在只有三五个依赖的小软件上或许可行,但一旦涉及 glibc、openssl、kernel 这种底层组件,依赖链条会瞬间膨胀到几十上百个包。手工一个个rpm -ivh大概率会把系统搞坏,所以我更倾向于把它拆成三个层次来理解。

第一层是“单机补丁包”:适合离线装某个具体软件,比如 Docker、Nginx,顶多带上一二十个依赖。做法是用联网机器把指定包及其依赖下载成 RPM 文件,拷贝进内网后逐个安装。第二层是“本地软件仓库”:把一批 RPM 按目录组织好,用 createrepo 生成 repodata 元数据,在内网机器上配置一个本地 repo 源,之后还能继续用 dnf 来做依赖解析和升级,这是我最推荐的方式,也是这篇文章的主线。第三层是“完整 ISO 全量源”:从 openEuler 官方镜像站下载 Everything 版 ISO,挂载后直接作为离线源使用,适合一次性部署新系统而不是日常补丁升级。

日常补丁场景里,我实际用得最多的是第二层。因为 SP3 的补丁不是静态的,官方仓库会持续更新,一次拷 ISO 进去,三个月后又落后了。做成本地 repo,内网机器每次升级只需要从这台“中转机”同步增量 RPM,路径短、可控性强、风险也低。

做之前还有一件事要搞清楚:你的目标机器架构。openEuler 的软件源按 x86_64、aarch64 严格分离,别在 x86 机器上抓 aarch64 的包,反过来也不行。离线升级包的第一原则就是架构一致、同版本基线一致,否则后面全是坑。

2. 制作离线升级包:联网机器上的完整操作链路

制作离线升级包需要一台“中转机”,它必须满足两个条件:能和 openEuler 的 yum 源正常通信,且和目标内网机器是同一个大版本、同一个架构。这台机器不需要完全一样,但尽量干净,避免把实验环境里乱七八糟的第三方源带进抓包结果。

2.1 配置干净的 yum 源,别把第三方源混进来

中转机系统装好 openEuler 22.03 LTS SP3 后,第一步是检查/etc/yum.repos.d/下的仓库文件。官方源至少要保留OS、everything、EPOL、update、source这几个常用 repo 名称,每个 repo 内部有baseurl指向 mirror 站点。第三方用 noarch 的软件源,建议在抓包期间先禁用,避免 dnf 自动把非官方依赖包拉进来,导致内网安装时签名或版本混乱。

我在实践中还会固定一下源地址,直接用官方 mirror 列表里某个节点。因为 dnf 默认会做 mirrorlist 轮询,抓包过程中如果经常在不同节点之间跳,偶尔会出现个别文件命中 404。写死一个 node 能减少这种偶发问题。

# 查看当前启用的仓库 dnf repolist # 确认系统版本 cat /etc/openEuler-release # 查看架构 uname -m

执行完这三条,确认系统是 openEuler 22.03 LTS SP3,架构是 x86_64(或你目标的 aarch64),再往下走。

2.2 先看有哪些补丁可升级:dnf check-update

在抓包之前,我习惯先执行dnf check-update,看看这个 22.03 LTS SP3 基线到底落后了多少个补丁。输出结果里会列出可更新的包名、仓库来源和版本号。这一步有两个作用:一是确认中转机的源确实能拉到更新,二是对升级包规模有个心理预期。

dnf check-update

如果输出一大堆,说明 SP3 基线之后的更新积累了不少;如果输出为空,说明 SP3 的 update 仓库已经和当前版本一致,不需要做离线升级包。这里要注意,check-update的输出结果是动态的,今天看到的包和明天看到的可能不同,所以离线升级包本质上是一个“快照”,打在包上的版本号才是最终生效的版本。

如果只想为特定软件做离线包,比如把 openssl 单独升级,可以用:

dnf list --showduplicates openssl

它能列出 openssl 在当前仓库里的所有可用版本,然后你用下面第四节里的dnf download方式单独抓这一个包和它的依赖。

2.3 全量升级包生成:dnf update --downloadonly 还是 reposync

对于大多数场景,我推荐的是“全量抓取所有可更新包”。这里的全量不是指把整个 openEuler 仓库几十 GB 都拉下来,而是把当前基线到最新版本之间、所有存在更新的 RPM 和它们的依赖拉下来。

dnf 自带一个 downloadonly 插件,直接执行:

dnf install dnf-plugins-core -y dnf update --downloadonly --downloaddir=/data/offline-updates

执行完之后,/data/offline-updates里就是本次系统全部可更新包的 RPM 文件。这个方法的好处是精准:只包含中转机当前环境需要更新的内容。缺点是:如果内网机器的软件包组合和中转机不完全一致(比如内网多装了一个中转机上没有的软件包),那这个目录里可能缺东西。

所以我更推荐第二个方案:dnf reposync直接同步整个 update 仓库。它不会管中转机装了什么,而是把 openEuler update 仓库里所有 RPM 全部拉到本地。缺点是体积大,优点是不会漏包,内网无论哪台机器都能用它补齐。

# 同步 update 仓库(包含所有更新包) dnf reposync --repoid=update --download-path=/data/offline-updates --download-metadata

如果你连 EPOL、everything 里的软件也要离线分发,可以继续:

dnf reposync --repoid=EPOL --download-path=/data/offline-updates --download-metadata dnf reposync --repoid=everything --download-path=/data/offline-updates --download-metadata

--download-metadata会把仓库的元数据也拉下来,后面让内网本地 repo 直接用,省一次 createrepo 的时间。但我在实际使用中还是会重新跑一次 createrepo,因为 reposync 拉下来的元数据可能引用的是远程绝对路径,本地 repo 场景下反而容易出现路径错乱。

2.4 生成或补全本地仓库元数据:createrepo_c

如果用了 reposync 且下载了 metadata,可以直接跳过这步;如果是用dnf update --downloadonly抓的包,或者想重建一份干净的元数据,就需要用 createrepo_c 或 createrepo。

dnf install createrepo_c -y cd /data/offline-updates createrepo_c .

执行完后目录里会出现repodata文件夹,里面是 primary、filelists、other 等元数据文件。这相当于给这堆 RPM 做了一本“目录索引”,内网 dnf 拿到这本索引才能做依赖解析、版本对比和事务计算。

还有一个细节:一定要把 GPG 密钥导出来一起带走。openEuler 的 RPM 包都带官方签名,内网机器如果开启 gpgcheck,就必须先导入密钥,否则 dnf 会报签名验证失败。密钥文件一般在系统里叫RPM-GPG-KEY-openEuler,可以通过下面的命令找到并复制到目标目录:

find /etc/pki/rpm-gpg -name "*openEuler*" -o -name "*openEuler*" cp /etc/pki/rpm-gpg/RPM-GPG-KEY-openEuler /data/offline-updates/

到这一步,离线升级包内容上已经完整了:RPM 文件 + repodata 元数据 + GPG 密钥。接下来就是打包传输。

3. 从联网机器到内网机器:repo 配置与升级执行

离线升级包制作完成只是第一步,真正容易翻车的是把它安全地送进内网并让目标机器认账。整个过程我习惯拆成三步:打包校验、配置本地 repo、执行升级。

3.1 打包传输与三次校验

/data/offline-updates目录可能很大,一般用 tar 压缩传输。内网没有飞书网盘、没有共享文件夹,最朴素的办法就是 U 盘拷贝,或者用运维跳板机作为文件转发节点。打包命令:

cd /data tar czvf offline-updates.tar.gz offline-updates sha256sum offline-updates.tar.gz > offline-updates.sha256

传输到目标机器后,先做校验再解压,避免传输过程中文件损坏。我遇到过 U 盘文件系统问题导致 RPM 解压失败的情况,所以强烈建议把 sha256 校验做成固定动作。

sha256sum -c offline-updates.sha256 tar xzvf offline-updates.tar.gz -C /opt/

解压完成之后,目标是/opt/offline-updates,里面应该有 repodata 目录、一堆 RPM 文件和 GPG 密钥。

3.2 编写内网本地 repo 文件

repo 文件是 dnf 识别软件源的“钥匙”,路径通常放在/etc/yum.repos.d/下。为了防止内网机器误连外网源,我会把所有默认 repo 文件改成.bak后缀或移走,只保留离线 repo。这步操作在生产环境要谨慎,最好先备份。

mkdir -p /etc/yum.repos.d/backup mv /etc/yum.repos.d/*.repo /etc/yum.repos.d/backup/

然后新建一个offline.repo,内容如下:

[offline-update] name=openEuler 22.03 LTS SP3 offline update repository baseurl=file:///opt/offline-updates enabled=1 gpgcheck=1 repo_gpgcheck=0 gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-openEuler

这里我把gpgcheck=1开着,因为 RPM 包本身是官方签名的,校验签名能防止包被篡改或损坏。repo_gpgcheck=0是关掉对仓库自身元数据的签名校验,因为离线仓库的元数据是我们自己生成的,没有官方密钥签名,硬开会报错。这个组合是内网离线仓库比较实用的配置。

写完 repo 文件后,导入密钥并重建缓存:

rpm --import /etc/pki/rpm-gpg/RPM-GPG-KEY-openEuler dnf clean all dnf makecache

如果dnf makecache能正常完成,说明本地仓库的元数据和文件路径都没问题。

3.3 执行升级与验证

最稳妥的做法是先查后更。先看一眼离线仓库到底提供了多少可更新包:

dnf --disablerepo='*' --enablerepo=offline-update check-update

--disablerepo='*'是强制所有源禁用,只开启 offline-update,确保内网机器不会偷偷去连其他源。这一步输出如果和你在中转机上看到的版本基本一致,说明离线包齐全。

然后执行升级:

dnf --disablerepo='*' --enablerepo=offline-update upgrade -y

执行过程中 dnf 会先做事务检查,列出将要安装、升级、删除的包,确认依赖能闭环。如果提示缺少依赖,优先考虑是不是离线包里漏了 noarch 或特定架构的包,可以在中转机上用dnf repoquery --requires之类的命令反查。

升级完成后,重启系统并验证内核版本:

reboot uname -r

如果你的离线包中包含 kernel 更新,重启后uname -r应该显示新的内核版本。我还会顺手检查几个关键组件版本,比如 openssl、glibc、systemd,确认它们和离线包里的版本号一致。

4. 离线升级包常见故障:现场排查记录

离线包看着简单,实际操作中各种问题层出不穷。下面这六个问题是我在不同项目里真实遇到过的,按发生率从高到低排。

4.1 架构不匹配导致的“软件包不存在”

在 x86_64 的中转机上抓包,拷到 aarch64 的内网机器上,dnf 会直接报错,说某个包在仓库里找不到,或者包名有冲突。因为 RPM 的包名里带了架构标签,比如openssl-3.0.7-24.oe2203sp3.x86_64.rpm和...aarch64.rpm完全是不兼容的东西。解法只有一个:制作离线包时就严格按目标架构走。如果内网是混合架构,建议分别做 x86_64 和 aarch64 两套离线包,路径上也要区分开,别混在一个目录里。

4.2 gpg 签名验证失败:公钥没导入或密钥不匹配

这是最容易遇到的报错,现象是 dnf 输出Public key for xxx.rpm is not installed或GPG key retrieval failed。原因基本都是目标机器没有导入 openEuler 官方 GPG 密钥。解决办法就是前面说的,先把密钥拷贝进内网、rpm --import导入,再写 repo 文件里指定gpgkey。

还有一种情况是你的离线包不是从官方源抓的,而是从某个第三方镜像站抓的,那 RPM 包的签名可能就和官方密钥对不上。这时不要图省事直接gpgcheck=0,更稳妥的做法是找到镜像站自己提供的签名公钥,或者直接换回官方源重新抓包。生产环境的包来源必须干净,这是底线。

4.3 dnf 缓存导致升级结果不准确

内网机器之前可能遗留了旧的 dnf 缓存,这些缓存里记录的是旧仓库的元数据,导致dnf check-update显示的结果和离线仓库实际内容不一致。我遇到过最离谱的一次,是内网机器显示“没有可用更新”,但离线仓库里明明有一百多个 RPM。问题就出在dnf makecache没跑成功,或者缓存没刷新。

解决方法是执行一次完整的缓存清理:

dnf clean all rm -rf /var/cache/dnf/* dnf makecache

然后把/etc/yum.repos.d/下所有无关 repo 全部禁用,确保 makecache 只读离线仓库。如果机器上同时存在多个离线目录的 repo,也会引起混乱,一个目标机只保留一个离线仓库配置是最稳的。

4.4 升级过程中途断掉:网络问题还是本地源路径问题

离线升级包从本地 file:// 路径读取,理论上不依赖网络,但如果你的离线包放在 NFS 或 iSCSI 挂载目录上,中途挂载断开,dnf 会报 Unable to read consumer identity 或者下载失败。这看起来像网络问题,实际上根源在共享存储连接不稳定。

我的建议是优先把离线升级包解压到目标机器本地磁盘,比如/opt/offline-updates,而不是直接挂载目录做源。虽然共享存储能省一份拷贝,但升级事务执行时间通常很长,中途存储抖动一次,整个 dnf 事务就会失败,回滚更麻烦。

4.5 内核升级后启动卡在 grub 或直接 panic

升级包打到一半,最常见的高危项就是内核。如果系统中还带了旧内核,grub 通常会保留旧内核作为一个启动项,所以即使新内核有问题,重启时也可以在 grub 菜单里选旧内核进入系统。但有些安全基线会把 grub 菜单调整成“默认第一个启动项直接启动”,一旦新内核有问题,机器就可能卡住。

处理措施是:在执行升级前,确认/boot分区有足够空间,避免内核写入一半就报磁盘满;升级完成后reboot前,检查 grub 配置里的default值和菜单项顺序。稳妥的操作是升级后先不重启,执行:

grub2-mkconfig -o /boot/grub2/grub.cfg

重新生成 grub 配置,确保新老内核都在菜单里。万一真起不来,进 grub 菜单选旧内核,再卸载问题内核包也不迟。

4.6 RPM 包依赖排序错乱:不要用 rpm -Uvh 直接装

这是新手最容易踩的坑。拿到一堆 RPM 文件,习惯性rpm -Uvh *.rpm,结果 rpm 会按字母序安装包,完全不理会依赖关系,很容易报“需要被其他包依赖”然后中断。正确姿势永远是配置好本地 repo 后用dnf upgrade,让 dnf 来做依赖解析和事务排序。离线包的意义也正在于此,它不只是“一堆 RPM 文件”,而是一个带元数据的仓库,dnf 才能体现价值。

5. 离线升级包的扩展应用:Docker、桌面环境和常用软件

离线包弄通之后,你会发现这套思路可以扩展到一个更广阔的领域:不只是升级系统,任何软件都能用同样的模式离线下发。下面以 Docker 和桌面环境为例,讲一下具体做法。

5.1 离线安装 Docker:RPM 包 + 镜像 tar

热搜词里高频出现“openEuler 安装 docker 更新到 28”,这确实是离线场景里最常见的需求之一。在联网中转机上,先配好 Docker 相关的 yum 源(openEuler 官方 EPOL 里通常有 docker 相关包,或者用 Docker 官方源),然后抓取 docker 和全部依赖:

dnf install dnf-plugins-core -y dnf download docker docker-cli containerd.io docker-compose-plugin --resolve --alldeps --destdir=/opt/docker-offline

抓完之后同样用 createrepo 生成仓库元数据,拷到内网机器,配置一个独立的 offline-docker.repo,然后:

dnf --disablerepo='*' --enablerepo=offline-docker install docker-ce docker-ce-cli containerd.io -y systemctl enable --now docker

要注意的是 Docker 版本迭代快,离线包里的版本是快照,内网机器无法随手docker pull新镜像。解决方法是把需要的镜像提前导出来:

docker pull openeuler/openeuler:22.03-lts-sp3 docker save openeuler/openeuler:22.03-lts-sp3 -o openeuler-sp3.tar

内网机器上用docker load -i openeuler-sp3.tar导入。把“RPM 包 + 镜像 tar”放在一起,就是一个完整的离线 Docker 交付物,这两部分缺一不可。

5.2 离线安装桌面环境:直接用 Everything ISO 做源头

如果内网机器要装图形界面,离线包方式依然可行。最简单粗暴的办法是从官方镜像站下载 openEuler 22.03 LTS SP3 Everything ISO,挂载后直接用 ISO 里的仓库安装桌面组。

mount -o loop openEuler-22.03-LTS-SP3-everything-x86_64.iso /mnt

然后在/etc/yum.repos.d/里写一个指向/mnt的 repo,启用后执行:

dnf --enablerepo=iso-everything groupinstall "GNOME" -y

openEuler 的 Everything ISO 里带的软件包比最小化安装多得多,GNOME、UKUI、DDE 这些桌面环境都有对应的 group 名称,可以用dnf group list查。这个方法比手动下载数百个 RPM 更稳,适合一次性部署场景。但对于已经部署好、只想补丁升级的机器,最好还是用独立补丁目录,而不是反复挂 ISO。

5.3 把离线升级包做成周期性维护动作

最后聊一个长期使用的心得。离线升级包不要做成“一次性救火”,而应该当成周期性维护流程。我现在的做法是每两周或每月,在中转机上重新跑一次dnf reposync,把更新目录增量同步到内网的“补丁分发机”上,然后由分发机统一对内网机器做升级。这样内网机器不会一次性累积几百个补丁,风险面小,也方便回溯每次变更。

增量同步用 rsync 比较合适,只传新增和变化的部分:

rsync -av --delete /data/offline-updates/ /内网挂载路径/offline-updates/

但--delete要小心,建议先手动对比一下新旧 repodata 里的包数量,别把内网还没装的旧包误删掉。如果条件允许,每次同步前最好在中转机上跑一次createrepo_c --update,让元数据保持最新。

我个人的经验是,离线升级这件事,最怕的不是技术复杂,而是“临时处理”的侥幸心态。把抓包目录、repo 文件、GPG 密钥、校验值这些要素固定下来,做成标准操作流程,后面每次执行都会非常省心。希望这整套流程能帮你少走点弯路。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询