ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Rocky 9.2局域网yum源搭建实战:从最小方案到rsync全量镜像

Rocky 9.2局域网yum源搭建实战:从最小方案到rsync全量镜像 简介在内网隔离环境中Linux服务器无法直接访问互联网软件安装与更新往往依赖人工上传RPM包效率低且难以保证版本一致。这份基于Rocky Linux 9.2的实操文档面向运维工程师与系统管理员完整讲述了借助HTTP服务搭建局域网YUM源的具体过程。部署场景采用YUM服务器192.168.15.100与客户机192.168.15.101的双节点结构详细覆盖ISO镜像挂载至/var/www/html/opt、创建local.repo仓库文件、安装并启动httpd服务、关闭防火墙及SELinux以及客户机修改baseurl并执行yum clean all、yum makecache和yum list验证等环节每一步都配有明确命令便于直接落地。资源包共1个文件为120KB的Word文档结构清晰按服务器端和客户端分步组织适合内网运维团队参考复用。目前已有1692人学习使用该方案不止适用于Rocky Linux稍加调整也能迁移至其他RPM系发行版有效解决内网大批量软件部署与版本一致性问题。1. 为什么在 Rocky 9.2 上还要自建局域网 yum 源一个 http 目录就能解决的事一台离线机器手动 rpm 装 nginx装到怀疑人生。几十台 Rocky 9.2 组成的实验室内网外网访问不通每台机器都要装同样的软件栈靠 U 盘拷包一个个解决依赖效率低到不想说话。Rocky 9.2 基于 http 方式搭建局域网 yum 源本质就是把一台有外网的机器变成内网仓库服务器其他机器用 dnf 直接从内网安装和更新软件全程不碰外网。核心其实很轻一个 http 目录加上正确的 repodata 元数据客户端就能把它当官方源用。区别在于 Rocky 9 的仓库规范比 CentOS 7 时代复杂AppStream 模块、元数据机制都有新坑。这篇文章按原理、最小方案、完整镜像、排错到验证的顺序写适合机房管理员、离线交付项目的人看完能直接照着搭一套能长期维护的源。2. 先搞清 Rocky 9 的仓库结构和 repodata为什么不能照搬 CentOS 7 的教程2.1 Rocky 9 的四个仓库BaseOS、AppStream、extras、CRB 各装什么Rocky 9 的包不再像 CentOS 7 那样堆在一个 os/Packages 目录里让 dnf 自己翻。官方仓库按内容拆成几个逻辑仓库每个仓库都有独立的 repodata 目录。BaseOS 装的是内核、固件、网络工具、shell 这类基础组件系统能跑起来靠它。AppStream 装的是各种应用软件和运行时nginx、python、redis、mysql 都在这里这是和 CentOS 7 最大的区别。extras 是官方不维护但随发行版发布的额外包数量不多。CRB 是 RHEL 9 时代由 PowerTools 改名的仓库主要放构建依赖和开发库一般客户端不用开启但做镜像时建议同步下来留作后手。这对搭建 yum 源的影响非常直接。如果内网只同步了 BaseOS客户端执行 dnf install nginx 大概率报“没有匹配的包”——不是包不存在而是 nginx 的 rpm 在 AppStream 仓库里客户端根本没启用这个仓库dnf 在解析包时只看已启用仓库的元数据。搭建前先明确需求只是给基础系统打补丁BaseOS 一个就够凡是涉及应用软件必须把 BaseOS 和 AppStream 一起做进去。实际部署中我见过不少把 CentOS 7 老教程直接搬过来的人只同步一个 Packages 目录结果客户端装什么都缺包这就是对新仓库结构不熟悉导致的翻车。2.2 为什么用 http 发布而不是 nfs、ftp 或 filefile:// 方式适合单机自用把 repo 文件里的 baseurl 指向本地目录就行但它解决不了局域网内其他机器访问的问题。有人会把目录 NFS 共享出去再写 file:// 路径这在跨网段、跨防火墙环境里容易遇到端口被拦、服务挂掉后 dnf 长时间卡死不推荐作为主方案。FTP 在 dnf 下也能工作但被动模式碰上内网防火墙时经常出现连接建立失败排错成本比 http 高一个量级。http 是最省心的选择nginx 监听一个 80 端口就能服务整个网段dnf 对 http 仓库的元数据缓存行为经过大量生产环境验证客户端用 curl 就能直接调试 URL404 还是 403 一眼看清。还有 http 连接复用这个点容易被忽略局域网里几十台机器同时执行 dnf makecache 时nginx 的 keepalive 可以让客户端复用已有的 TCP 连接而不是每请求一次就重新握手一次。机器少于 20 台时感知不明显超过 50 台后仓库服务器的 CPU 占用和连接数差异会很直观。2.3 repodata 是什么createrepo_c 生成的文件与 dnf 的消费方式一个合格的 yum 源目录里除了 rpm 文件本身还必须有一个 repodata 子目录。repodata 里最关键的是 repomd.xml它是整个仓库的索引签名文件primary.xml.gz 记录每个 rpm 的包名、版本、架构和依赖关系filelists.xml.gz 记录每个包的文件列表供 dnf 按文件路径反查归属other.xml.gz 是 changelog 等杂项。dnf 客户端首次访问仓库时先下载 repomd.xml用其中的校验和去校验后续元数据文件再按需拉取 primary 和 filelists。所以“把 rpm 拷到目录里不生成 repodata”等于没做源客户端只会看到仓库目录存在但无法解析任何包。RHEL 9 和 Rocky 9 上生成元数据的工具是 createrepo_c它是 C 语言实现处理几千个 rpm 时比老的 Python 版 createrepo 快得多命令名也变成了 createrepo_c老教程里直接敲 createrepo 会提示找不到命令这个细节坑了一大批从 CentOS 7 迁移过来的人。createrepo_c 生成的元数据默认带 sha256 校验和被 dnf 直接识别不需要额外配置。理解到这一层就够用了客户端要的是包名、版本、依赖、校验和四类信息createrepo_c 负责把这四类信息从 rpm 头部抽出来建立索引。3. 最小可用方案dnf download createrepo_c nginx 三步把源跑起来3.1 目录规划与基础工具安装最小方案面向的场景是内网机器数量不多需要安装的软件可以提前列出来不需要完整镜像官方仓库。在一台有外网的机器后面叫源机上规划一个目录存放 rpm比如 /data/repo。我习惯把目录按用途分开基础包和业务包各放一个子目录后续生成元数据时互不干扰。先安装工具dnf install -y nginx createrepo_c dnf-plugins-corenginx 用来发布 http 服务createrepo_c 用来生成仓库元数据dnf-plugins-core 提供 dnf download 子命令。这三个包在 Rocky 9 的默认仓库里都有源机能连外网时装起来不会缺依赖。如果源机本身完全离线先用另一台有外网的机器下载这三个 rpm 打成压缩包带进来后续流程不变只是更新 rpm 时多一步人工拷贝。提示Rocky 9 最小安装默认很可能没有 nginx。如果 dnf 提示找不到 nginx先确认是不是把 AppStream 仓库禁用掉了。3.2 用 dnf download 把包和依赖一起拉下来源机要发布哪些软件就提前把它们下载到仓库目录里。dnf download 和 dnf install 的区别是只下载不安装专门用来攒离线包dnf download --destdir/data/repo/base --resolve --alldeps nginx net-tools bash-completion--destdir 指定 rpm 保存目录--resolve 让 dnf 把目标包的所有依赖一起下载--alldeps 在 --resolve 基础上更激进即使某个依赖已经在源机上安装了也会一并下载。这样做的原因是源机和客户端的环境不一定相同源机装过的包客户端可能没有加上 --alldeps 生成的源更完整代价是 rpm 数量多一些但局域网场景完全能接受。如果想做一个通用的基础源把源机系统里所有已安装的包导出可以这样dnf download $(rpm -qa) --destdir/data/repo/base --resolve --alldepsrpm -qa 列出当前系统所有包名dnf download 批量解析下载相当于把一台机器的运行环境打包成仓库。注意这里的前提是仓库里有与当前系统完全一致的 name-version-release如果源机做过升级用 rpm -qa --qf %{NAME}\n 只取包名再下载会拿到仓库里的最新版。3.3 用 createrepo_c 生成元数据rpm 文件放进目录后下一步生成 repodatacreaterepo_c --workers 4 --checksum sha256 /data/repo/base--workers 指定并行线程数源机四核以上就填 4核心少就填 2这个参数直接影响生成速度。--checksum 显式指定元数据校验算法sha256 是 Rocky 9 的默认值写出来是表明意图不写也能正常工作。命令执行完成后目录下出现 repodata 子目录里面有 repomd.xml、primary.xml.gz 等文件。如果按业务分了多个子目录比如 /data/repo/base 和 /data/repo/app要分别对每个目录执行一次 createrepo_c不能把两个目录的 rpm 混在一起生成一份元数据否则出现同名不同版本时 dnf 会把包混为一谈安装时可能拉到错误版本。后续往仓库里追加新 rpm不需要重新跑全量生成用增量模式createrepo_c --update --workers 4 /data/repo/base--update 会对比目录里已有的 repomd.xml只重新解析新增和变更的 rpm。几百个包里加一个包时时间从几十秒缩短到几秒这是最小方案长期维护的关键命令。3.4 nginx 发布目录与 autoindex目录建好了用 nginx 把它变成 http 可访问的资源。在 /etc/nginx/conf.d/repo.conf 里写入server { listen 80; server_name _; root /data/repo; autoindex on; autoindex_exact_size off; autoindex_localtime on; keepalive_timeout 10; }root 指向仓库根目录客户端访问 http://源机IP/base/ 时对应 /data/repo/base/。autoindex 必须打开否则 nginx 找不到 index 文件时直接返回 403而 yum 源目录恰好没有 index.html这是新手最常踩的坑。autoindex_exact_size 和 autoindex_localtime 只是让目录列表显示更友好不设也能用。keepalive_timeout 对应前面说的 http 连接复用调成 10 秒可以让空闲连接更快释放避免大并发时连接数堆积。写好配置执行 nginx -t 检查语法然后systemctl enable --now nginx firewall-cmd --permanent --add-servicehttp firewall-cmd --reloadfirewalld 这步漏掉其他机器访问 80 端口会连接超时而源机自己 curl 却是通的容易让人误以为 nginx 配置有问题。3.5 客户端 repo 文件与冒烟测试在任意一台内网机器上创建 repo 文件指向源机cat /etc/yum.repos.d/local.repo EOF [local-base] nameLocal Rocky Base baseurlhttp://192.168.1.10/base/ enabled1 gpgcheck0 [local-app] nameLocal Rocky App baseurlhttp://192.168.1.10/app/ enabled1 gpgcheck0 EOF这里把 gpgcheck 临时设为 0是因为最小方案里这些 rpm 是 dnf download 出来的没有官方签名链验证强行开启会报签名错误。客户端执行 dnf clean all 和 dnf repolist能看到 local-base 和 local-app 两个仓库就说明源已经通了。验证安装用 dnf install nginx --downloadonly这条命令只解析依赖并下载不实际安装不会把测试机器搞乱。注意gpgcheck0 适合内部临时源。生产环境建议把 gpgkey 配回去客户端系统自带的 /etc/pki/rpm-gpg/RPM-GPG-KEY-Rocky-9 文件可以直接复用或者直接用下一章的官方仓库全量镜像方案。4. 完整方案rsync 同步官方仓库做成自动更新的局域网镜像4.1 最小方案的维护瓶颈在哪里最小方案在包数量变多之后维护成本明显上升。每引入一个新软件包都要在源机上手动 dnf download再跑一次 createrepo_c --update。管理员记不住哪些包下载过、哪些没下载仓库会慢慢出现漏包客户端装到一半报找不到依赖。完整方案是一劳永逸的做法用 rsync 把 Rocky 官方仓库或国内镜像站仓库同步到本地客户端直接按官方仓库路径使用不需要自己维护 rpm 集合。4.2 选镜像站与仓库目录结构同步源建议选网络延迟低的国内镜像站比如中科大镜像的 rocky 目录。保持镜像站原有的目录结构不要自己重新整理/data/rocky/9/BaseOS/x86_64/os/ /data/rocky/9/AppStream/x86_64/os/ /data/rocky/9/extras/x86_64/os/ /data/rocky/9/CRB/x86_64/os/保持结构和镜像站一致有两个好处一是 repodata 不用重新生成同步过来的元数据直接可用二是客户端 repo 文件可以照搬官方文件的写法只把 baseurl 里的主机名换成内网 IP不需要额外适配。如果内网同时存在 x86_64 和 aarch64 机器把路径中的 x86_64 替换成 aarch64 再同步一份即可。4.3 同步命令与参数说明同步单个仓库的命令rsync -avrt --delete \ --excludedebug/ \ --excludesource/ \ --timeout120 \ rsync://rsync.mirrors.ustc.edu.cn/rocky/9/BaseOS/x86_64/os/ \ /data/rocky/9/BaseOS/x86_64/os/-a 保留文件属性并递归-v 输出同步过程首次同步方便观察进度-t 保留时间戳rsync 靠文件大小和 mtime 判断变更时间戳必须保留否则每次都会全量重传。--exclude 排除 debug 和 source 子目录这两类占体积大且内网几乎用不到排除能省 30% 左右同步流量。--timeout 120 防止网络抖动时 rsync 卡死。--delete 让本地删除镜像站已经下线的文件避免陈旧 rpm 残留但这个参数要慎用细节在避坑章节展开。仓库数量多时写一个脚本循环同步顺便记录日志#!/bin/bash REPO_BASE/data/rocky/9 MIRRORrsync://rsync.mirrors.ustc.edu.cn/rocky/9 LOG/var/log/rocky-sync.log for repo in BaseOS AppStream extras CRB; do echo [$(date %F %T)] start sync $repo $LOG rsync -avrt --delete \ --excludedebug/ --excludesource/ \ --timeout120 \ $MIRROR/$repo/x86_64/os/ \ $REPO_BASE/$repo/x86_64/os/ $LOG 21 echo [$(date %F %T)] end sync $repo $LOG done日志里记录时间戳是为了后面排查“客户端报陈旧元数据”时能确认同步到底有没有跑成功。首次同步建议在带宽空闲时段执行四个仓库初始流量约 15 到 20GB具体看镜像站速度和网络条件可能几十分钟到几小时。4.4 nginx 发布与客户端官方风格 repo 文件发布配置和最小方案类似root 指向 /data/rocky 即可。客户端 repo 文件写成官方风格cat /etc/yum.repos.d/lan.repo EOF [lan-BaseOS] nameLAN Rocky BaseOS baseurlhttp://192.168.1.10/rocky/9/BaseOS/$basearch/os/ enabled1 gpgcheck1 gpgkeyfile:///etc/pki/rpm-gpg/RPM-GPG-KEY-Rocky-9 [lan-AppStream] nameLAN Rocky AppStream baseurlhttp://192.168.1.10/rocky/9/AppStream/$basearch/os/ enabled1 gpgcheck1 gpgkeyfile:///etc/pki/rpm-gpg/RPM-GPG-KEY-Rocky-9 EOF$basearch 由 dnf 自动替换成 x86_64 或 aarch64。gpgcheck1 可以放心开因为同步过来的是官方仓库原始 rpm 和官方 repodata签名链完整。客户端系统在安装 rocky-repos 包时已经把官方 GPG key 放到了 /etc/pki/rpm-gpg/ 下所以 gpgkey 用 file:// 路径即可不需要从源机额外下载验证文件。4.5 定时同步与验证用 cron 做每日同步放在凌晨流量低峰chmod x /opt/sync-rocky.sh crontab -e在 crontab 里加一行0 3 * * * /opt/sync-rocky.sh /dev/null 21验证同步是否成功关键是看 repomd.xml 能否从客户端访问curl -I http://192.168.1.10/rocky/9/BaseOS/x86_64/os/repodata/repomd.xml返回 200 且 Content-Length 正常即可。不建议用 dnf makecache 替代 curl 验证因为 dnf 有缓存无法区分“同步正常”和“dnf 还在用旧缓存”这两种状态。5. 局域网 yum 源避坑从 403 到 repodata 损坏的五条记录5.1 客户端访问仓库目录直接 403 Forbidden现象curl 访问 http://源机IP/base/ 返回 403但访问具体 rpm 文件却能下载浏览器打开源目录也显示 Forbidden。原因nginx 对没有 index 文件的目录默认拒绝列出而 yum 源目录恰好没有 index.html。另一个常见原因是 SELinux 没放行自定义目录的访问。解决在 nginx 配置里加 autoindex on 并重启如果还 403检查 SELinux。SELinux 开启状态下nginx 只能读取标记为 httpd_sys_content_t 的目录放 /usr/share/nginx/html 下的目录默认没问题自定义的 /data/repo 需要手动标记semanage fcontext -a -t httpd_sys_content_t /data/repo(/.*)? restorecon -RF /data/reposemanage 在 policycoreutils-python-utils 包里没有就先安装。临时验证可以用 chcon -R -t httpd_sys_content_t /data/repo但 chcon 重启后可能丢失semanage 才是持久方案。5.2 dnf repolist 能看到仓库install 却提示找不到包现象客户端 dnf repolist 正常列出仓库但 dnf install nginx 报“没有匹配的包”而源服务器上明明有 nginx 的 rpm。原因只有 BaseOS 仓库被同步和启用AppStream 没同步或者 repo 文件里没写。nginx、python、redis 这类应用基本都在 AppStreamBaseOS 里只有系统组件。解决检查源机目录下有没有 AppStream 对应的 repodata检查客户端 repo 文件里是否配置 AppStream 条目。这个坑的隐蔽之处在于 repolist 不报错BaseOS 仓库本身是正常的dnf 只是按已启用仓库列表搜索不到目标包而已。5.3 rsync --delete 把仓库同步成了半截毁状态现象同步过程中网络中断客户端 dnf 报“repodata 与磁盘上的不一致”或者 repomd.xml 解析失败。原因rsync 默认逐文件覆盖--delete 删除过期文件时如果中断本地会残留旧 rpm 和新 repodata 混搭的状态repomd.xml 里记录的校验和与实际文件对不上。解决同步到临时目录再切换这是最稳妥的姿势rsync -a --delete rsync://.../BaseOS/x86_64/os/ /data/rocky-tmp/BaseOS/x86_64/os/ mv /data/rocky-tmp /data/rocky先同步到 /data/rocky-tmp完成后用 mv 原子替换客户端在任何时刻看到的都是完整目录。牺牲一点磁盘空间换来的是源永远不出现半截状态。5.4 装 AppStream 里的包报模块定义错误现象AppStream 同步完成dnf install nginx 时报“无法检测 nginx 的模块定义”即使包就在仓库里。原因AppStream 仓库带了模块化流的元数据 modules.yaml.gz如果同步时误排除了模块文件或者用 wget 从 AppStream 手动拉了几个 rpm 自己 createrepo_c模块元数据就丢了。解决AppStream 必须整体同步不要自定义裁剪。如果确认同步完整仍然报错在客户端执行 dnf clean all dnf makecache 清掉旧缓存再试。5.5 客户端 dnf 操作卡顿迟缓现象客户端执行 dnf repolist 或 makecache 要等几十秒甚至更久源服务器负载并不高。原因repo 文件里残留了官方 mirrorlist 路径dnf 会先请求 mirrorlist.rockylinux.org 拿镜像列表再访问 baseurl内网访问外网地址超时后才回退另外系统里如果启用了 fastestmirror 插件局域网下它会反复尝试探测各镜像白白浪费时间。解决repo 文件里只留 baseurl注释或删掉 mirrorlist把 /etc/yum.repos.d/ 下原来的 rocky-*.repo 全部移到备份目录只留内网 repo 文件。然后在 /etc/dnf/dnf.conf 的 [main] 段追加echo fastestmirror0 /etc/dnf/dnf.conf禁用 fastestmirror 后配合 nginx 的 keepalive_timeout 参数客户端并发执行 makecache 时的整体延迟会明显下降。6. 客户端 repo 配置、验证命令与增量更新小技巧完整方案里的客户端 repo 文件还有一种更健壮的写法把四个官方仓库全部定义进去避免后续临时用 CRB 时再去改文件cat /etc/yum.repos.d/lan.repo EOF [lan-BaseOS] nameLAN Rocky BaseOS baseurlhttp://192.168.1.10/rocky/9/BaseOS/$basearch/os/ enabled1 gpgcheck1 gpgkeyfile:///etc/pki/rpm-gpg/RPM-GPG-KEY-Rocky-9 [lan-AppStream] nameLAN Rocky AppStream baseurlhttp://192.168.1.10/rocky/9/AppStream/$basearch/os/ enabled1 gpgcheck1 gpgkeyfile:///etc/pki/rpm-gpg/RPM-GPG-KEY-Rocky-9 [lan-extras] nameLAN Rocky extras baseurlhttp://192.168.1.10/rocky/9/extras/$basearch/os/ enabled1 gpgcheck1 gpgkeyfile:///etc/pki/rpm-gpg/RPM-GPG-KEY-Rocky-9 [lan-CRB] nameLAN Rocky CRB baseurlhttp://192.168.1.10/rocky/9/CRB/$basearch/os/ enabled0 gpgcheck1 gpgkeyfile:///etc/pki/rpm-gpg/RPM-GPG-KEY-Rocky-9 EOF写好后按顺序执行三条验证命令dnf clean all dnf repolist dnf repoquery --whatprovides nginxdnf repoquery --whatprovides 比 dnf install 试装更轻量能直接确认目标包在源里是否可解析还能看到模块化版本的候选。想进一步确认客户端和源服务器元数据一致用 dnf repolist -v 查看仓库元数据时间戳如果和源服务器 repomd.xml 里的时间一致说明客户端读到的就是最新状态。最小方案的增量更新核心是前面提过的 createrepo_c --update。放进 cron 时注意它只能解决本地目录新增 rpm 后的元数据同步不能替代 rsync 全量同步。两条路线的边界很清晰包集合可控、机器数少用最小方案机器多或包范围不固定直接上 rsync 脚本。我维护的几套内网环境里最小方案翻车一般不是命令写错而是懒——新包没往目录里放客户端报缺依赖时才想起补。后来我给自己定了个习惯拿到新需求先判断是一次性交付还是长期滚动前者用最小方案后者直接写 rsync 脚本别让仓库变成只有自己能看懂的半成品。希望帮到你。本文还有配套的精品资源点击获取
返回列表