资讯详情

自建DNF仓库与NFS共享:内网Linux服务器软件分发与文件共享实践

📅 2026/10/11 18:55:47 | 华诺云谱 👁 阅读
自建DNF仓库与NFS共享:内网Linux服务器软件分发与文件共享实践
1. 项目概述与方案选型1.1 为什么需要自建DNF仓库和NFS共享做运维的朋友尤其是负责企业内部Linux服务器管理的大概率都遇到过这么几个让人头疼的场景第一内网服务器无法访问外网。出于安全合规要求生产环境的服务器往往放在隔离的网段里不能直接上外网。可装软件总是要的吧今天要装个nginx明天要装个php-fpm后天可能还要升级openssl。每次都用U盘拷贝rpm包依赖关系能让你折腾到怀疑人生。我见过有同事为了装一个软件包手动下载了十几个依赖rpm最后因为版本不匹配还是装不上那种痛苦我相信不少人都体会过。第二即使能上外网直接从官方源拉取的速度也让人崩溃。尤其是某些跨境服务器下载速度能让你一杯咖啡喝完还没下载完一个几十MB的包。而且如果几十台服务器同时从外网拉取带宽直接被占满业务响应变慢老板还以为是应用出问题了。第三版本一致性难以保证。今天A服务器装的是nginx 1.20明天B服务器装的是nginx 1.22后天C服务器装的是nginx 1.18到了排查问题时不同环境的行为完全不一致很难复现问题。如果内部有一套统一的软件仓库所有机器都从这套仓库安装软件版本自然统一交付和运维的标准化程度能提升不少。第四离线环境下的补丁升级需求。等保测评、安全加固经常会要求升级某个存在漏洞的软件版本内网环境没有源怎么升自建仓库是最靠谱的解法。NFS共享服务的价值同样很直接。运维工作中经常需要批量分发配置、传递日志压缩包、共享安装介质、共享备份目录。假设你有一个200GB的数据库备份文件要拷贝到另外两台服务器上你要是拿硬盘拷来回折腾一上午如果有NFS直接把目录挂载过去几分钟完事。而且NFS还可以用来共享镜像文件、共享代码发布包甚至可以作为简单的无盘启动环境的基础存储。在集群环境中NFS也是应用共享数据目录的常见方案比如微服务上传的文件可以统一存放在NFS上多个应用实例读到的都是同一份数据。一句话总结自建DNF仓库解决的是“软件从哪里来、怎么统一装”的问题NFS共享解决的是“文件怎么在多台机器间高效传递”的问题。两者结合起来就是一套完整的内网基础设施服务交付给开发和测试环境使用效率提升立竿见影。1.2 仓库服务方案对比与选型思路搭建DNF软件仓库常见的有三种思路我这里把优劣都摊开来说第一种是用Web服务器Nginx/Apache提供仓库访问。服务器上用createrepo生成仓库元数据然后通过HTTP协议对外提供服务客户端配置baseurlhttp://repo.example.com/rhel9/即可。这种方式的好处是客户端配置简单支持远程访问不受公网IP限制而且Nginx处理并发下载的能力很强。缺点是需要额外安装和配置Web服务但这一步本身难度不大。第二种是直接把仓库目录通过NFS共享出去客户端挂载后再作为本地仓库源使用。这种方式的优势在于内网机器可以通过NFS直接挂载仓库目录不需要走HTTP对于老旧系统或者不想开放HTTP端口的环境很友好而且由于数据是本地文件系统访问部分场景下读取速度比HTTP更快另外没有Web服务这一层少一个攻击面。缺点是NFS本身对网络质量要求较高跨网段大规模访问可能会出现性能瓶颈而且NFS版本如果不匹配还会有一堆权限兼容的坑。第三种是同时提供HTTP和NFS两种访问方式。仓库数据先存放在某台服务器上通常是一台独立的存储机或仓库机NFS把仓库目录共享给网内其他机器同时这台机器自己也跑一个Nginx提供HTTP访问。这种方式最灵活但配置工作量也最大。我在实际项目中通常推荐第二种或第三种组合。原因很简单很多内网服务器都是云主机或者虚拟机本身就挂载了数据盘用NFS把仓库数据挂在某个数据盘上再通过NFS共享给其他机器省去Web服务的配置如果后续有需要再叠加Nginx做HTTP访问也不迟。本项目的标题是“部署DNF仓库及NFS共享服务”很自然就是走“NFS共享仓库之实HTTP访问为辅”的路线仓库数据存储在NFS共享目录中客户端既可以NFS挂载后直接使用本地仓库源也可以在这台机器上额外搭建Nginx作为HTTP源。为什么这样设计核心考量有三个性能NFS共享直接走文件系统协议仓库元数据repodata读取的效率比HTTP要快尤其是dnf makecache生成缓存和检查更新时NFS响应更快。灵活性DNF仓库本质上就是一组目录和元数据文件NFS共享不会破坏原有目录结构同时还可以共享其他运维目录如备份目录、软件包目录一举多得。易于扩展后续如果仓库数据量变大可以直接在NFS存储后端挂更大的磁盘不需要改动客户端配置。2. 环境规划与基础准备2.1 服务器与客户端规划动手之前先把环境想清楚避免做到一半才发现IP、目录、挂载点全都乱成一团。以我常用的一个模版为例角色主机名系统版本IP地址说明仓库服务端repo-serverRocky Linux 9.2192.168.1.10存放DNF仓库数据、跑Nginx、提供NFS共享仓库客户端Aapp-server-aRocky Linux 9.2192.168.1.21内网业务服务器需要通过DNF仓库安装软件包仓库客户端Bapp-server-bAlmalinux 9.1192.168.1.22另一台业务服务器同时挂载NFS共享目录系统版本这里我选的是Rocky Linux 9系和AlmaLinux 9系这两个都是RHEL的完全兼容重建版特别适合企业内部使用没有订阅费用稳定性也好。如果你们还在用CentOS 7DNF可能还需要额外安装CentOS 7默认使用YUM但可以装DNF包不过核心流程大同小异。我建议新业务系统尽量上RHEL 9或Rocky 9毕竟CentOS 7已经停止维护很久了安全漏洞不会有人再修。注意一点服务端和数据盘要有足够的空间。DNF仓库如果只是同步基础ISO和软件包几十GB就够了如果要同步整个官方仓库的扩展包AppStream、Extras等建议准备至少200GB的磁盘空间。我不会做全量同步一般只同步企业常用的软件包比如nginx、php、python、mysql相关的包以及对应的安全更新包。数据盘建议单独挂载比如挂载到/data目录DNF仓库数据放在/data/repoNFS共享目录用/data/exports这样后续扩容和管理都方便。2.2 防火墙与安全策略配置前置检查很多人部署NFS和仓库服务时前面一切顺畅最后客户端挂载时却发现连不上、超时十有八九就是防火墙拦截了。所以准备工作里防火墙策略要提前想好。Rocky Linux 9系列默认使用firewalld仓库服务端需要放行NFS相关端口和如果做HTTP源80端口。NFS服务涉及的服务端口并不固定这里提及的主要端口包括端口用途2049/TCPNFS服务主端口nfsd111/TCP、UDPRPC端口映射portmapper20048/TCP、UDPNFS v3的mountd服务v4通常不在固定端口视系统配置而定我建议把nfs、rpc-bind、mountd这类服务组件统一在服务端加入白名单避免客户端挂载时因端口不通而在排查上耗费时间。一个简单的做法是在服务器上执行firewall-cmd --permanent --add-servicenfs firewall-cmd --permanent --add-servicerpc-bind firewall-cmd --permanent --add-servicemountd firewall-cmd --permanent --add-servicehttp firewall-cmd --reload如果你们环境里用的是iptables就别执行以上命令了直接加对应的规则原理一致。另外SELinux对NFS共享的影响也必须提前考虑。RHEL系默认开启SELinuxNFS挂载到一个目录后HTTP服务和DNF访问都有对应的布尔值开关。比如如果用Nginx提供HTTP仓库访问就要setsebool -P httpd_use_nfs 1 setsebool -P httpd_read_user_content 1这两条是允许Nginx读取NFS挂载的仓库目录内容。如果不设置你在浏览器或curl测试时可能能看到目录列表但下载rpm包时却返回403原因就在这里。2.3 必备软件安装仓库服务端需要安装的软件有dnf-utils提供reposync、createrepo等实用命令nfs-utilsNFS服务的核心工具nginx可选做HTTP源时用rsync如果后续要从外网镜像同步文件。安装命令很简单dnf install -y dnf-utils nfs-utils rsync nginxdnf-utils中的reposync命令是从远端仓库同步软件包到本地的利器后面章节会用到。createrepo单独一个命令也可以直接用dnf install createrepo_c安装C语言版本性能更好尤其适合仓库包量很大时生成元数据。至此基础的准备工作就完成了。接下来进入正题一步一步搭建DNF仓库。3. 构建DNF仓库核心环节3.1 仓库数据的两种来源方式同步镜像与本地ISO构建DNF仓库先得有“货”。有两条路线可选路线A从上游仓库同步。服务器能访问外网的情况下直接用reposync把软件包同步到本地即可。以Rocky Linux 9为例先确认本机的repo源配置正常然后同步BaseOS和AppStream两个仓库这两个是企业服务器最常用的软件来源reposync --repoidbaseos --repoidappstream --download-path/data/repo --download-metadata这里--download-path指定软件包下载存放目录--download-metadata表示同时下载仓库元数据包括repodata目录、comps.xml组信息等。同步过程时间较长主要取决于网络质量和仓库大小。我建议第一次只同步baseos和appstream后续需要其他仓库再加避免同步量过大导致磁盘空间吃紧。同步完成之后因为reposync虽然下载了元数据但有时元数据不完整或者与实际包列表有出入稳妥起见还是要用createrepo重新生成一遍createrepo_c --update /data/repo/baseos createrepo_c --update /data/repo/appstream--update参数是增量的只在有包变化时才更新元数据速度很快。路线B基于本地ISO构建离线仓库。如果服务器完全离线或者只想做一个最小仓库比如只需要操作系统安装盘里自带的那些包可以用安装ISO来构建。把ISO挂载到某个目录然后把BaseOS和AppStream两个目录复制到仓库目录再生成元数据即可mount -o loop /path/to/Rocky-9.2-x86_64-dvd.iso /mnt/iso mkdir -p /data/repo cp -a /mnt/iso/BaseOS /data/repo/ cp -a /mnt/iso/AppStream /data/repo/ createrepo_c /data/repo/BaseOS createrepo_c /data/repo/AppStream走ISO路线生成的仓库包数量比在线同步要少得多只有安装盘包含的包但胜在快速、离线可用适合那些只需要基础软件包的环境。两种路线不冲突可以先从ISO建一个基础仓库后续有条件了再用reposync增量同步补充。我这里有一个建议哪怕服务器能访问外网也建议优先通过内网镜像站同步。把上游地址改成国内镜像站或者你们公司的代理镜像地址速度和稳定性都会好很多。同步一次之后后续再做增量同步就非常快了。3.2 分组信息comps.xml的生成与仓库元数据重建DNF仓库和YUM仓库有一个差异需要特别注意DNFYUM 4支持仓库分组groups安装时可以按组安装比如dnf groupinstall Development Tools。这些组的定义信息就写在comps.xml中。如果仓库里没有这个文件dnf groupinstall会报错说找不到组甚至dnf grouplist都不正常。从上游同步或从ISO复制时comps.xml通常会一起带过来。但如果你发现仓库目录下没有repodata/*-comps-*.xml文件就需要手动处理。createrepo_c提供了-g参数可以直接把组信息注入# 如果仓库目录下已经有comps.xml文件直接执行 createrepo_c -g /data/repo/AppStream/repodata/*-comps-*.xml /data/repo/AppStream注意comps.xml文件的位置不固定一般与仓库同级目录或repodata目录下。我在实际操作中还会额外保存一份纯内容版本便于后续排查find /data/repo -name *comps* -exec ls -lh {} \;如果确实没有comps.xml可以用下面命令从系统自带的元数据抽取dnf group list ids但这样做比较麻烦更省事的是从上游仓库直接下载该仓库对应的comps.xml文件。例如Rocky 9的AppStream仓库一般可以通过HTTP直接访问http://mirror.../Rocky/9/x86_64/AppStream/repodata/目录找到*comps*.xml文件下载即可。生成完元数据后记得检查一下repodata目录是否存在以及repomd.xml是否生成了这是客户端识别仓库的关键文件。3.3 仓库目录结构与文件权限设置细节仓库目录的结构我建议这样规划假设数据盘挂载到/data/data/repo/ ├── baseos/ │ ├── Packages/ │ ├── repodata/ ├── appstream/ │ ├── Packages/ │ ├── repodata/ ├── extras/ │ ├── Packages/ │ ├── repodata/Packages目录下通常有大量rpm文件reposync默认会用Packages目录存储某些版本会放到/data/repo/baseos/Packages/下。如果你的仓库同步方式包名比较混乱可以用--download-metadata选项让目录结构更规范。权限方面仓库目录的Owner建议设置为一个专用用户比如nginx用户或者root文件权限建议为755。因为NFS共享时客户端的root默认会被映射为nobody即root_squash如果目录Owner是root且权限是700客户端普通用户就无法读取仓库内容即使挂载成功也只在root用户下读取时可能碰壁。我一般直接chown -R root:root /data/repo chmod -R 755 /data/repo这里强调一下/data本身不要给755以上的危险权限否则NFS共享出去会暴露更多目录。3.4 同步过程中常见的坑GPG密钥与元数据不对齐同步仓库时最容易踩的坑有两个第一GPG密钥缺失或GPG校验失败。客户端配置仓库源时如果设置为gpgcheck1而仓库中没有对应的GPG公钥安装软件时会报GPG key retrieval failed或者public key not available。同步时最好把发行版官方的GPG KEY文件一并放到仓库目录比如mkdir -p /data/repo/keys curl -o /data/repo/keys/RPM-GPG-KEY-rockyofficial https://dl.rockylinux.org/pub/rocky/RPM-GPG-KEY-Rocky-9客户端配置时加上gpgkeyfile:///data/repo/keys/RPM-GPG-KEY-rockyofficial即可。也可以直接把gpgcheck0但那是在绝对信任内网环境的前提下不建议长期这么干尤其是有等保要求的环境。第二元数据与包列表不对齐。有时你同步到一半中断了Packages目录下的部分rpm文件是残损的但repodata却显示正常结果客户端dnf install时可能遇到“package not found”或者“checksum mismatch”的报错。这种情况最简单的处理方式是把对应仓库目录下的repodata整个删除重新执行createrepo_c让它重新递归扫描生成元数据rm -rf /data/repo/baseos/repodata createrepo_c /data/repo/baseos如果磁盘空间紧张还可以用dnf clean all配合dnf repolist判断元数据缓存是否有问题。4. NFS共享服务的部署与配置4.1 NFS版本选择与内核参数注意事项NFS协议目前主要使用NFS v4和v4.2版本v3在旧系统上还在用但如果两边都支持建议直接用v4/v4.2。原因很直接NFS v4有状态化的锁网络重连后能恢复文件状态而不像v3那样容易产生锁残留或者半连接问题。v4.2支持服务端复制、稀疏文件改进等新特性对性能和功能都有提升。v4通过单一端口2049通信简化了防火墙配置。在/etc/nfs.conf中RHEL系默认支持NFSv4无需额外指定协议版本。但有个参数值得关注rdma和rdma-port如果内核和网卡支持RDMA可以把NFS跑在RDMA上获得极低延迟但这依赖硬件一般场景下不需要开启。普通TCP场景下我建议至少确认网络是千兆以上否则NFS同步大文件时速度会成为瓶颈。另外/etc/sysconfig/nfs文件中有个RPCNFSDARGS参数可以传额外内核参数一般保持默认即可。4.2 exports文件配置详解共享目录、权限组合、匿名映射NFS的核心配置就是/etc/exports每一行定义一个共享目录和允许访问的客户端。以我的仓库服务器为例假设要共享/data/repo给整个内网192.168.1.0/24网段同时共享/data/exports给指定的客户端A/data/repo 192.168.1.0/24(rw,sync,no_root_squash,no_subtree_check) /data/exports 192.168.1.21(rw,sync,no_root_squash,no_subtree_check) 192.168.1.22(ro,sync,no_root_squash,no_subtree_check)这里几个参数逐项解释一下rw/ro可读写或只读。仓库目录必须rw因为客户端创建缓存时需要写权限实际上DNF仓库作为本地源使用时客户端会写自己的/var/cache/dnf不需要写仓库目录所以理论上仓库目录可以是ro。但如果你还想通过NFS往仓库放新包比如直接上传rpm到仓库那就要rw。我实际场景中给了rw便于后台上传包。安全要求高的场景建议给ro需要更新仓库时服务端操作或临时挂载rw。sync服务端需要将数据写盘后才响应客户端的写请求。这是最稳妥的做法避免宕机丢数据。生产环境一定不要用async。no_root_squash默认情况下NFS会把客户端root用户映射为匿名用户nobody/nfsnobody加上这个参数后客户端的root可以以root身份操作共享目录便于管理。这个选项从安全角度来看有争议但在内网完全可控的环境下为了减少麻烦我通常开启。如果你希望更严格就保留默认的root_squash。no_subtree_check关闭子树检查避免目录重命名时产生报错。如果共享目录下面还有其他子目录挂载点或不同导出这个参数尤其有用。修改完/etc/exports后执行exportfs -arv使配置生效。-a表示导出所有条目-r重新导出-v显示详细过程。4.3 启动服务与开机自启设置在Rocky/Alma 9上启动NFS服务依赖以下几个systemd服务systemctl enable --now rpcbind nfs-server注意rpcbind是NFS v3及以前版本需要的v4不依赖它但系统默认都装了保持启动没坏处。另外还有nfs-mountd和nfs-idmapd通常会被nfs-server自动拉起。确认状态systemctl status nfs-server如果一切正常可以看到Active: active (exited)和相关的导出信息。再用showmount -e localhost查看本机导出的共享目录列表[rootrepo-server ~]# showmount -e localhost Export list for repo-server: /data/exports 192.168.1.21,192.168.1.22 /data/repo 192.168.1.0/24showmount能正常列出目录说明共享配置已经下发到内核了。另外建议打开NFS的访问日志便于后续排查客户端挂载失败的问题。方法是在/etc/exports参数中加fsid0其实更重要的是开启rpcdebug功能但这有点高级。大多数场景下journalctl -u nfs-server查看NFS服务日志就够了。如果挂载有问题服务端日志会输出类似nfsd: connect from unprivileged port等提示这些信息对定位端口/防火墙问题很有价值。4.4 客户端挂载NFS共享目录客户端需要先安装dnf install -y nfs-utils然后手动挂载测试mkdir -p /mnt/repo mount -t nfs 192.168.1.10:/data/repo /mnt/repo注意这里的服务器IP必须与/etc/exports中允许的网段一致如果客户端在192.168.1.21而共享只允许了192.168.1.21/32其他IP挂在时会直接报Permission denied。挂载成功后用df -h能看到挂载信息也可以直接读取目录ls /mnt/repo/appstream/repodata/repomd.xml能看到repomd.xml说明元数据文件可读仓库可以使用。更推荐的做法是配置/etc/fstab实现开机自动挂载。在/etc/fstab中加一行192.168.1.10:/data/repo /mnt/repo nfs defaults,_netdev,noatime 0 0其中_netdev很重要它告诉系统在网络就绪后再执行挂载避免开机时因网络未就绪导致挂载失败。如果服务端NFS导出的是子树比如共享/data/repo/subdir那挂载路径也要相应调整。挂载完成后还要验证权限。以客户端A为例先确认元数据目录可读test -r /mnt/repo/appstream/repodata/repomd.xml echo readable接着直接尝试用DNF读取这个本地仓库。5. DNF客户端仓库配置与功能验证5.1 本地仓库repo文件编写与参数逐项解读客户端挂载好NFS后就可以配置DNF仓库了。在/etc/yum.repos.d/下新建一个专属repo文件比如local.repo[local-baseos] nameLocal BaseOS Repository baseurlfile:///mnt/repo/baseos enabled1 gpgcheck1 gpgkeyfile:///mnt/repo/keys/RPM-GPG-KEY-rockyofficial [local-appstream] nameLocal AppStream Repository baseurlfile:///mnt/repo/appstream enabled1 gpgcheck1 gpgkeyfile:///mnt/repo/keys/RPM-GPG-KEY-rockyofficial逐项说明一些容易被忽视的参数baseurlfile:///mnt/repo/baseos因为是本地挂载目录用file://协议注意路径要写NFS挂载点而不是服务端原始路径。gpgcheck1开启GPG校验配gpgkey指向公钥文件路径。如果客户端没有导入过该GPG公钥系统会自动提示导入。你可以提前手动导入rpm --import file:///mnt/repo/keys/RPM-GPG-KEY-rockyofficial。enabled1表示该仓库启用如果设置为0则默认禁用需要--enablerepo手动启用。如果客户端之前配置了官方源或者第三方源建议把这些源设为enabled0避免DNF并行访问外网源和本地源既混乱又慢。在许多教程中还会推荐加一个参数cost10用于提高该仓库的优先级。DNF在多个仓库都提供同一个软件包时会优先选择cost值更低的仓库。默认cost是1000你本地仓库设为cost10相当于强制DNF优先从本地NFS仓库取包。5.2 验证仓库连通性与软件安装先跑一下仓库列表确认本地仓库被正确识别dnf repolist如果输出中出现了local-baseos和local-appstream说明仓库已经生效。接下来验证软件安装和更新。选择一个常见的工具包比如htopdnf install -y htop注意htop在BaseOS里没有是在AppStream里正好可以验证appstream仓库是否正常。观察输出中下载的包的来源那一行如果显示file:///mnt/repo/...说明包确实从本地仓库拉取的。还可以验证更新流程dnf check-update dnf update -y 某个包名在dnf check-update这一步你会发现速度极快本地仓库元数据读取对比外网源的缓慢令人心情舒畅。5.3 通过HTTP方式访问DNF仓库虽然标题重点在DNF仓库和NFS共享但实际部署中HTTP访问也是一个非常刚需的补充。我把这部分一起讲了因为它属于同一套基础设施的自然延伸。服务端安装并启动Nginx后在配置文件中加一个server块指向仓库目录server { listen 80; server_name repo.example.com; root /data/repo; autoindex on; autoindex_exact_size off; autoindex_localtime on; location / { index repomd.xml; } }autoindex on开启目录列表这样客户端可以方便地浏览所有rpm包autoindex_localtime on让目录列表显示本地时间格式方便对比更新。然后客户端本地源repo文件就可以写为[local-baseos-http] nameLocal BaseOS via HTTP baseurlhttp://192.168.1.10/baseos enabled1 gpgcheck1 gpgkeyfile:///mnt/repo/keys/RPM-GPG-KEY-rockyofficial应用场景差异NFS方式适合服务器数量少、且本来就需要NFS共享目录做其他用途的环境HTTP方式适合服务器数量多、需要统一走一套标准Web访问协议的环境。两种方式可以共存客户端自由选择用哪种。6. 常见问题与故障排查实录6.1 NFS挂载失败的典型原因与对应解法挂载NFS不成功是最常见的问题几乎每个运维都遇到过。我把典型的故障现象和排错步骤理了一遍1mount.nfs: access denied by server while mounting这个报错最直接的原因是服务端/etc/exports配置里没有允许客户端IP。排查顺序确认客户端IP确实在允许范围内ip addr show看本机IP。检查服务端配置cat /etc/exports和exportfs -v输出。确认没有写错网段或IP注意192.168.1.0/24不能写成192.168.1.*这种形式虽然某些系统支持通配符但规范写法还是CIDR。如果修改了exports记得执行exportfs -arv重新导出。2挂载命令卡住长时间无响应常见原因是rpcbind或nfs-server没启动或者防火墙在阻止。先确认服务端服务状态systemctl status rpcbind nfs-server ss -lntup | grep -E 2049|111如果端口没监听那就是服务没起来。再检查防火墙是否放行了NFS相关服务和端口。客户端可以先用telnet 192.168.1.10 2049测试到2049端口的TCP连通性。3挂载成功后普通用户读取目录显示Permission denied这个基本是root_squash和目录权限的问题。客户端root被映射为nobody而共享目录权限是700 root那非root用户进来自然没权限。解法要么在exports中对该客户端加no_root_squash要么把共享目录的权限放开为755或改用其他权限策略。4NFS挂载后目录为空检查挂载点是否与其他目录重叠了。如果挂载点本地原本有内容比如/mnt/repo下之前放了一个空目录挂载后新内容会遮挡本地内容看起来就像“空目录”。用mount | grep /mnt/repo确认挂载是否生效df -h看容量变化。6.2 DNF仓库客户端常见报错排查速查表报错现象可能原因排查/解决Failed to download metadata for repo local-baseos仓库路径不可读或repo文件路径拼写错误检查baseurl路径是否正确、目录是否存在、SELinux布尔值是否放开Errors during downloading metadata for repository元数据缺失或损坏服务端重新执行createrepo_c生成元数据Public key for xxx.rpm is not installedgpgcheck1但GPG公钥未导入rpm --import导入公钥或临时gpgcheck0验证Package xxx doesnt belong to a valid repository仓库元数据与包列表不一致服务端清空repodata重建The downloaded RPM package was not signedrpm包未签名或签名被破坏检查包完整性重新从上游同步或确认GPG公钥版本Nothing to do目标包已被安装或仓库中没有该包先用dnf search或dnf provides确认包名再看dnf list --availablerepodata/repomd.xml does not existfor NFS挂载源挂载的NFS目录不是仓库根目录或元数据确实没生成挂载点路径是否指向了/data/repo上一层ls确认repodata目录实战中我遇到最多的确实是repodata/repomd.xml does not exist仔细一看客户端repo文件里写的是baseurlfile:///mnt/repo而挂载点映射到服务端的/data/repo两者对应关系没问题但服务端仓库根目录下并没有repodata因为元数据在/data/repo/baseos/repodata子目录中——一个路径层级疏忽就会导致整条链路不可用。解决方式是检查服务端目录结构客户端repo的baseurl精确指向包含repodata的仓库子目录。6.3 根文件系统与数据目录的使用率管理DNF仓库的磁盘空间是一个“温水煮青蛙”的问题。一开始只有几个GB随着同步的仓库增加几个月后可能膨胀到上百GB。运维上我做了这几件事定时脚本定期清理旧版本包。dnf-utils里有个repomanage命令可以清理目录中的旧包repomanage --old /data/repo/baseos会列出旧版本配合| xargs rm -f可以清理。注意清理完后要重新生成元数据。监控磁盘占用。写一个简单的cron脚本统计各仓库目录大小超过阈值就告警。#!/bin/bash REPO_SIZE$(du -sh /data/repo 2/dev/null | awk {print int($1)}) if [ $REPO_SIZE -gt 200 ]; then echo $(date %Y-%m-%d %H:%M:%S) repo size ${REPO_SIZE}GB over threshold /var/log/repo_monitor.log fi这只是一个极简版生产环境建议配合监控平台。6.4 使用过程中遇到的元数据过期问题DNF仓库更新后客户端本地缓存的元数据会过期。常见现象是客户端执行dnf install时提示Next metadata expiration check然后等待一段时间去重新获取元数据如果仓库较大这个等待时间可能长达几分钟甚至还会报超时。解决方法是客户端提前主动刷新dnf makecache或者让DNF在仓库元数据更新后自动检测。服务端在每次更新仓库元数据后可以更新一下repomd.xml中的时间戳其实DNF默认会比较本地元数据缓存时间和服务端repomd.xml的修改时间如果客户端时钟与服务端不一致会出现元数据误判。所以务必保证客户端和服务端时间同步所有服务器配置NTP/chronydnf install -y chrony systemctl enable --now chronyd这是整个服务稳定性的一个隐形基础。7. 基于NFS共享目录的运维扩展与实用技巧7.1 共享软件分发目录与备份目录的设计NFS不只是用来挂仓库更多时候我用它来共享运维工作目录。举例软件包回收站开发和测试同学经常需要把某版本的软件包分发给多台服务器此时把分发包放到NFS共享的/data/exports/software目录各服务器挂载后直接使用即可。备份目录数据库备份、日志备份集中放在NFS共享的/data/exports/backup目录然后各服务器写cron任务把本地备份推送上去。集中备份的好处是方便统一做异地存储或磁带归档。配置分发目录大多数配置变更通过配置管理工具分发但临时下发一批配置文件比如nginx.conf更新包NFS共享目录是最快的路径。设计共享目录时注意按用途分类建子目录并单独设置权限位。我常用的结构/data/exports/ ├── software/ (rw, 仅运维网段可写) ├── backup/ (rw, 所有客户端可写) ├── install-iso/ (ro, 安装镜像)这样不同共享目录的授权范围不同避免一次共享所有权限。7.2 利用NFS共享目录快速批量安装软件包结合DNF仓库与NFS共享我有一个非常顺手的批量操作流程新服务器到位后先手动挂载NFS共享的/data/exports/software目录里面放一个批量安装脚本bootstrap.sh然后执行脚本自动完成导入GPG公钥配置本地仓库repo文件从共享目录拷贝安装常用工具集合htop、vim、tree、tcpdump等配置chrony时间同步关闭或调整不需要的系统服务这个脚本用NFS共享目录分发的好处是所有新机器拿到的都是同一个版本、同一套配置不会出现“A同学装的脚本和B同学不一样”的问题。这正是基础设施标准化带来的直接收益。7.3 定期同步脚本与仓库更新自动化仓库数据不是同步一次就一劳永逸的上游软件包会持续更新安全补丁更是必须及时跟进。我写了一个简单的cron脚本每周日凌晨执行一次增量同步#!/bin/bash LOG/var/log/repo_sync.log exec $LOG 21 echo $(date %Y-%m-%d %H:%M:%S) repo sync start reposync --repoidbaseos --repoidappstream --download-path/data/repo --download-metadata --newest-only createrepo_c --update /data/repo/baseos createrepo_c --update /data/repo/appstream exportfs -arv echo sync end --newest-only这个参数很重要它只同步每个软件包的最新版本避免历史版本堆积导致仓库体积无限膨胀。把这个脚本放到/etc/cron.d/repo-sync或者用systemd timer定时执行。执行日志可以通过/var/log/repo_sync.log查看。同步之前我还建议先看下上游仓库的更新频率。官方仓库一般每天都有更新如果你内网带宽有限每两天或每周一次完全够用。安全补丁类更新应该优先同步可以在脚本里单独拉取security仓库如果有的话。7.4 客户端缓存清理与仓库切换注意事项客户端从NFS挂载仓库切换到HTTP仓库或者反之时一定要先清理DNF缓存否则可能出现“明明配置改成了HTTP源但下载包时还是从file://拉取”的怪象。dnf clean all dnf makecache切换完记得再dnf repolist确认仓库列表已更新。另外如果客户端曾经通过yum或dnf操作过旧的源/etc/yum.repos.d/下会残留其他repo文件。建议统一管理把不需要的repo文件加个.bak后缀或移动到/etc/yum.repos.d/backup/始终保持仓库环境干净。8. 项目总结与后续优化空间8.1 整套方案的收益回顾整套DNF仓库NFS共享服务部署完之后我在实际运维中感受到的收益非常实际新服务器初始化从“一天调研手动装包”缩短到“半小时自动化配置”大量时间被节省下来。所有服务器的软件版本统一不再出现各种“只有这台机器这样”的诡异问题排障工作量明显减少。离线环境下的补丁升级不再依赖U盘拷贝安全合规工作推进顺畅很多。备份分发和配置下发用NFS共享文件传递效率直线提升。这套方案很适合中小规模内网几十台到几百台服务器而且成本极低——只需要一台带数据盘的普通服务器不需要额外购买商业软件纯开源组件组合就能完成。8.2 可继续扩展的方向建议我个人在实际推进项目时后续还会考虑几个优化方向增加仓库高可用目前单台仓库服务端如果宕机整个内网软件的安装分发就中断了。可以考虑再做一台备用仓库机通过rsync定时镜像数据客户端repo文件中配置多个baseurlDNF支持多URL当第一个失败时自动切换到备用地址。这一步实施成本不高但能显著提高基础设施稳定性。接入文件完整性校验使用createrepo_c已经会生成各rpm的校验值但最好定期执行一次全量verify防止磁盘静默错误导致仓库数据损坏。与配置管理工具整合如果公司有自动化配置工具可以把仓库repo文件、NFS挂载配置等封装成标准配置项新机器上线自动拉取避免手动维护。增加仓库访问统计Nginx访问日志可以统计哪些包下载量大、哪些软件的更新频率高为后续裁减或扩充仓库包列表提供数据参考。8.3 最后分享一点实操心得项目做到末尾我还是想以个人经验的角度多说一点。这类“基础服务”项目看似简单真正做好却不容易。我从实操中总结出几个值得反复强调的原则第一文档比记忆可靠。服务的所有目录结构、配置路径、同步脚本、密钥文件位置一定要写清楚、放好位置。我后来看很多问题的排查时间都花在“想起来当时是怎么配置的”上了。一个简单的README文件放在/opt/apps/readme/目录都行关键是内容要准确。第二变更要有记录。仓库添加了什么包、NFS共享目录调整过什么权限、GPG密钥何时更新过这些变更建议用简单的变更记录文件哪怕是一个TXT记录下来。问题出现时回溯思路会清晰很多。第三测试环境先验证。无论是仓库元数据重建还是NFS exports修改都先在测试客户端验证一遍再应用到生产。有一次我在生产端直接执行createrepo_c重建元数据因为当天包量较大构建时间较长期间客户端正好在安装软件就出现了短暂的“元数据获取失败”虽然影响不大但完全可以在维护窗口期操作来规避。这些经验也许不能帮你省掉所有坑但能让你在踩坑时更从容。基础设施服务就是这样前期把细节琢磨透后期才会稳定省心。
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑