1. 为什么需要自建DNF仓库并用NFS分发:内网统一软件源的业务场景
有个场景我估计不少运维都遇到过:内网几十台服务器,不能直接访问外网源,每次装软件都要先跑到能上网的机器上把rpm包一个个拉下来,再拷进去。更麻烦的是,不同机器要装同一个软件,过程得重复好几遍,拷贝过程中偶尔还会混入不兼容的包版本,装出来的环境五花八门,排查问题的时候人都要裂开。我这次要说的,就是针对这种场景的一套解决方案——在内网服务器上部署一个DNF仓库,然后通过NFS共享服务把仓库目录分发给所有客户端。
这里稍微解释一下两个名词。DNF仓库(dnf repository)本质上就是一个有特殊目录结构的软件包集合:里面放着rpm包文件,还有一个叫repodata的元数据目录,里面记录了rpm包的名称、版本、依赖关系、文件清单等信息。dnf或者yum通过读取这些元数据,就能知道从哪个包开始装、依赖哪些包、去哪里下载。而NFS(Network File System)是一种基于RPC(Remote Procedure Call)机制的网络文件系统,它可以让客户端像访问本地目录一样访问服务端共享出来的目录。
把两者结合起来的思路很直接:先在服务端用createrepo把一堆rpm包做成一个标准DNF仓库,再通过NFS把整个仓库目录共享出去。客户端挂载NFS后,把dnf仓库的baseurl指向挂载目录,就能直接dnf install任意软件包,依赖自动解析,版本统一管理,不用再一台台手动拷贝。
那有人会问,走HTTP协议共享仓库不是更常见吗?确实,很多公网软件源都是走HTTP,比如阿里云镜像、清华镜像。但内网场景下,NFS有几个很实际的优势:
- 不需要额外部署nginx/apache,系统自带的nfs-utils就够用,架构简单。
- 客户端挂载后,仓库就是一个本地目录,dnf的
file://协议读取非常稳定,不会出现网络源偶尔连接超时、下载中断这类问题。 - 如果后续想把某些rpm包手工放进仓库,直接在客户端挂载目录里操作即可(需要在服务端开放写权限),不用走HTTP上传工具。
- 内网环境网络可控,NFS的传输速度和稳定性都很好。
当然,NFS也不是万能的。如果客户端数量巨大(几十台以上)、分布在不同网段,或者仓库需要跨公网访问,那还是建议走HTTP。我这次环境是同一个二层网段内的十几台机器,NFS就是最省事的选择。
下面这张图可以概括整体架构:
| 角色 | 机器 | 作用 |
|---|---|---|
| NFS服务端 + DNF仓库宿主机 | 192.168.1.10 | 存放rpm包,生成repodata,共享目录 |
| NFS客户端 + DNF客户端 | 192.168.1.x(若干台) | 挂载NFS目录,配置local仓库,dnf install |
| 仓库目录 | /data/repo | 按base/updates/extras等子目录组织 |
这套方案最适合的场景是:内网离线环境、需要统一软件版本的中小型集群、没有外部软件源权限的机房。只要准备好一批rpm包,服务端一次搭好,客户端配置一次,后续所有装软件的操作都变得非常丝滑。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 服务端准备:仓库目录结构与基础环境规划
2.1 环境规划表
动手之前,先把环境规划清楚。我这次用的是CentOS Stream 9作为服务端,客户端也是同一个大版本的系统。这里建议,如果可能的话,客户端和服务端的发行版大版本尽量保持一致,否则rpm包在跨版本安装时容易出现依赖不兼容的问题。
| 项目 | 规划值 | 说明 |
|---|---|---|
| 服务端系统 | CentOS Stream 9 x86_64 | 仓库宿主机 |
| 服务端IP | 192.168.1.10 | 静态IP,固定不变 |
| 客户端系统 | CentOS Stream 9 / Rocky Linux 9 | 同版本即可 |
| 客户端网段 | 192.168.1.0/24 | NFS共享范围 |
| 仓库根目录 | /data/repo | 建议单独分区或独立磁盘 |
| 仓库子目录 | base / updates / extras | 按用途分目录,避免元数据混杂 |
| 挂载点(客户端) | /mnt/dnf-repo | 客户端统一路径 |
这里特别提醒一下:仓库目录的可用空间一定要提前估算。一个base仓库全量同步下来,大约需要10GB到20GB,如果加上updates,可能到30GB以上。我这次因为只做基础环境,所以只放了base和updates两个子集,一共约15GB。建议用df -h确认空间后,再决定同步节奏。
2.2 安装createrepo_c、nfs-utils、rpcbind
服务端需要安装的工具主要是三个:createrepo_c(用于生成DNF仓库元数据)、nfs-utils(提供NFS服务端程序)、rpcbind(NFS依赖的RPC端口映射服务)。
bash复制dnf install -y createrepo_c nfs-utils rpcbind
关于createrepo的版本,这里多说一句。老版本里叫createrepo,是一个Python写的工具,createrepo_c是它的C语言重写版,性能差异非常明显。我对比过,在一个包含3000多个rpm包的目录上,createrepo_c生成元数据大概只要10秒左右,而createrepo可能要一两分钟。而且createrepo_c生成的元数据格式与dnf完全兼容,所以新环境直接装createrepo_c就好,不用纠结。
如果你用的系统是Ubuntu/Debian,对应的包名是createrepo-c和nfs-kernel-server,安装命令不同但思路一致。整个方案本质上是跨发行版通用的,只是dnf在Debian系里要换成apt,这部分就不展开了。
2.3 创建仓库目录结构
目录结构的设计我建议一步到位,因为后续改起来很麻烦。根目录/data/repo下面,我按base、updates、extras分了三个子目录,每个子目录里面再放一个Packages目录放rpm包,元数据则由createrepo生成在子目录根部。
bash复制mkdir -p /data/repo/base/Packages
mkdir -p /data/repo/updates/Packages
mkdir -p /data/repo/extras/Packages
为什么要这样分?因为base、updates、extras在发行版里面对应不同的软件源类别,它们的rpm包来源不同、更新频率不同、依赖关系也可能交错。如果全塞在一个目录里,createrepo会把所有包当作一个整体来生成元数据,依赖解析会变得混乱。分开之后,客户端可以针对每个子仓库独立启用或禁用,灵活性高很多。
除了这些子目录,我还在`/data/repo
