Rocky Linux 9.4 私有Yum仓库:企业级搭建、深度优化与自动化运维实战
最近在帮一家中型企业的IT团队做基础设施优化,他们面临一个典型问题:开发测试环境频繁部署,每次从公网拉取几百兆的RPM包,不仅速度慢得像蜗牛,还时不时因为网络波动导致构建失败。更麻烦的是,有些合规要求严格的业务线,服务器压根不能直接访问外网。折腾了几轮之后,我们决定在内部搭建一个Rocky Linux的私有Yum仓库。这听起来像是系统管理员的常规操作,但真做起来,从目录规划、权限配置到后期的同步策略和性能调优,里面门道不少。今天我就把这次从零搭建到稳定运行的全过程,结合踩过的坑和最终验证有效的方案,详细拆解一遍。无论你是刚开始接触Rocky Linux的新手,还是希望优化现有仓库的老手,这篇文章都能给你提供一套可直接落地的参考。
1. 环境规划与基础准备:不只是安装几个包
在敲下第一条命令之前,合理的规划能避免后期大量的返工。我们这次的目标是搭建一个服务于近百台Rocky Linux 9.4服务器的私有仓库,需要稳定、高效且易于维护。
1.1 硬件与存储考量
私有仓库的核心是I/O操作,尤其是大量小文件的随机读写。直接使用系统根分区往往不是最佳选择。
- 存储空间估算:Rocky Linux 9.4的完整
BaseOS和AppStream仓库,x86_64架构下,初始同步大约需要30GB空间。但你必须为增长预留空间——后续同步更新、可能增加的PowerTools、EPEL等第三方仓库,以及日志文件。我们建议预留至少100GB的专用存储空间。 - 磁盘性能:如果服务器规模较大(超过50台),强烈建议使用SSD或高性能的RAID阵列来存放仓库数据。机械硬盘在
createrepo_c生成元数据时可能会成为瓶颈,导致客户端yum makecache或dnf update操作缓慢。 - 网络隔离:仓库服务器最好部署在内部核心网络区域,确保与所有客户端服务器之间的网络延迟低、带宽充足。千兆网络是起步,有条件的话可以考虑万兆互联。
提示:在虚拟化环境中(如VMware、KVM),确保为仓库虚拟机分配厚置备的磁盘,并避免与其他高I/O负载的虚拟机共享同一物理存储,以减少性能干扰。
1.2 软件包安装与初始配置
很多教程会一股脑儿让你安装所有包,但了解每个包的作用更有助于排错。
# 以root用户执行,安装核心组件
dnf install -y createrepo_c httpd dnf-utils
这里的关键是createrepo_c,它是新一代的仓库元数据创建工具,用C语言重写,比旧的createrepo速度快得多,尤其是在处理大型仓库时。dnf-utils提供了reposync等关键工具。
安装完成后,启动并设置Apache开机自启:
systemctl enable --now httpd
接着配置防火墙,允许HTTP流量。如果你在测试环境或受信任的内网,也可以暂时禁用防火墙,但在生产环境务必精确控制。
# 添加HTTP服务到防火墙永久规则,并重载配置
firewall-cmd --permanent --add-service=http
firewall-cmd --reload
2. 仓库结构设计与首次数据同步
仓库的目录结构设计要有前瞻性,考虑到未来可能的多版本、多架构支持。
2.1 创建清晰的目录树
我们采用一种易于扩展的目录结构:
# 创建主仓库目录,这里/data是一个独立的挂载点
mkdir -p /data/repos/rocky/9.4/{BaseOS,AppStream,extras}/x86_64/os
这个结构一目了然:/data/repos是根,/rocky是发行版,/9.4是主版本,/BaseOS等是仓库组件,/x86_64是架构,/os是最终目录。未来如果需要增加aarch64架构或8.8版本,只需创建对应目录即可。
2.2 配置高效同步源
直接从官方源同步对于国内用户可能很慢。将系统的Yum源临时切换到国内镜像(如阿里云、腾讯云),能极大提升首次同步速度。
# 备份原有repo文件
cp /etc/yum.repos.d/rocky.repo /etc/yum.repos.d/rocky.repo.backup
# 使用sed快速替换为阿里云镜像(示例)
sed -i \
-e 's|^mirrorlist=|#mirrorlist=|g' \
-e 's|^#baseurl=http://dl.rockylinux.org/$contentdir|baseurl=https://mirrors.aliyun.com/rockylinux|g' \
/etc/yum.repos.d/rocky*.repo
# 生成新的缓存
dnf makecache
2.3 执行首次完整同步
使用reposync进行同步。这里有几个关键参数决定了同步的效率和结果:
# 同步BaseOS仓库
reposync --repo=baseos \
--download-path=/data/repos/rocky/9.4/BaseOS/x86_64/os \
--download-metadata \
--newest-only \
--remote-time \
--downloadcomps
# 同步AppStream仓库(包数量多,耗时较长)
reposync --repo=appstream \
--download-path=/data/repos/rocky/9.4/AppStream/x86_64/os \
--download-metadata \
--newest-only \
--remote-time \
--downloadcomps
参数解析:
--download-metadata: 同时下载repomd.xml等元数据文件,这对后续createrepo_c更新很重要。--newest-only: 只下载每个包的最新版本,避免仓库体积无谓膨胀。--remote-time: 将下载的文件时间戳设置为远程服务器上的时间,便于后续增量同步判断。--downloadcomps: 下载comps.xml文件(组件分组信息),在生成仓库元数据时会用到。
首次同步可能需要数小时,取决于你的网络带宽和镜像源速度。可以放到后台执行,或使用screen/tmux会话。
2.4 生成仓库元数据
同步完文件只是第一步,必须用createrepo_c生成客户端能识别的仓库元数据。
# 为BaseOS生成元数据
createrepo_c /data/repos/rocky/9.4/BaseOS/x86_64/os
# 为AppStream生成元数据(包多,耗时稍长)
createrepo_c /data/repos/rocky/9.4/AppStream/x86_64/os
完成后,检查目录下是否生成了repodata文件夹及其内部的repomd.xml等文件。
3. 权限、SELinux与Web服务配置
这是最容易出问题的环节,权限配置不当会导致客户端无法访问或读取文件。
3.1 文件系统权限
Apache进程默认以apache用户和组运行,因此需要将仓库目录的所有权赋予它:
chown -R apache:apache /data/repos
chmod -R 755 /data/repos
755权限确保apache用户有读写执行权,其他用户和组有读和执行权。
3.2 SELinux上下文配置
在启用SELinux的系统上(Rocky Linux默认启用),仅修改文件权限是不够的,必须设置正确的安全上下文。
# 为/data/repos及其所有子目录添加httpd_sys_content_t上下文
semanage fcontext -a -t httpd_sys_content_t "/data/repos(/.*)?"
# 应用新的上下文规则
restorecon -Rv /data/repos/
如果未来仓库脚本需要访问网络(例如从外部源同步),还需要开启一个布尔值:
setsebool -P httpd_can_network_connect 1
注意:不推荐直接禁用SELinux。虽然
setenforce 0可以临时关闭,或修改/etc/selinux/config永久关闭,但这会降低系统安全性。正确配置上下文是更专业的做法。如果遇到权限问题,可以使用ls -Z查看文件上下文,用audit2why分析SELinux日志来定位问题。
3.3 Apache虚拟主机或别名配置
为了让Apache提供仓库文件,需要配置一个访问路径。这里使用Alias别名方式,简单高效。
创建配置文件/etc/httpd/conf.d/yumrepo.conf:
Alias /repos /data/repos
<Directory /data/repos>
Options Indexes FollowSymLinks
AllowOverride None
Require all granted
# 可选:限制特定IP段访问
# Require ip 192.168.1.0/24 10.0.0.0/8
</Directory>
Options Indexes: 当目录下没有index.html时,显示文件列表,方便浏览器直接查看仓库结构。Require all granted: 允许所有请求。在生产环境,建议用Require ip限制为内部IP段。
配置完成后,重启Apache服务:
systemctl restart httpd
现在,你可以通过浏览器访问http://<你的服务器IP>/repos,应该能看到rocky目录结构。
4. 客户端配置与仓库验证
仓库服务端搭建好后,需要在客户端服务器上进行配置和测试。
4.1 编写客户端仓库文件
在需要从这个私有仓库安装软件的Rocky Linux 9.4客户端上,创建一个新的.repo文件,例如/etc/yum.repos.d/local-rocky.repo:
[local-baseos]
name=Local Rocky Linux 9.4 - BaseOS
baseurl=http://192.168.1.100/repos/rocky/9.4/BaseOS/x86_64/os/
enabled=1
gpgcheck=0
priority=10
[local-appstream]
name=Local Rocky Linux 9.4 - AppStream
baseurl=http://192.168.1.100/repos/rocky/9.4/AppStream/x86_64/os/
enabled=1
gpgcheck=0
priority=10
关键点:
baseurl: 指向你的仓库服务器IP和Apache配置的别名路径。gpgcheck=0: 因为我们没有配置GPG密钥签名验证。对于严格的内网环境可以关闭;若需开启,需将公钥导入客户端。priority=10: 设置一个较高的优先级(数字越小优先级越高),确保客户端优先从本地仓库查找软件包。这可以防止意外从公网源安装。
为了确保只从私有仓库安装,可以禁用或备份原有的官方源文件:
mv /etc/yum.repos.d/rocky*.repo /etc/yum.repos.d/backup/
4.2 完整功能测试
现在进行端到端测试:
# 1. 清理旧的yum缓存
dnf clean all
# 2. 建立新缓存(这会从你的私有仓库获取元数据)
dnf makecache
# 3. 搜索一个软件包,确认仓库可用
dnf search nginx
# 4. 尝试安装一个软件包进行验证(例如一个不重要的工具)
dnf -y install htop
# 5. 检查安装的软件包来源
rpm -qi htop | grep -i "source"
如果dnf makecache成功且能安装软件,说明私有仓库工作正常。你可以通过curl -I http://192.168.1.100/repos/rocky/9.4/BaseOS/x86_64/os/repodata/repomd.xml来快速检查元数据文件是否可以访问。
5. 自动化同步与仓库维护
手动同步不可持续。我们需要一个可靠的自动化方案来定期更新仓库,并处理相关维护任务。
5.1 编写健壮的同步脚本
将之前的同步命令封装成一个脚本,增加错误处理和日志功能。创建/usr/local/bin/sync_rocky_repos.sh:
#!/bin/bash
# Rocky Linux 9.4 私有仓库自动同步脚本
# 作者:你的名字
# 日志文件:/var/log/reposync/sync_YYYYMMDD.log
set -euo pipefail # 更严格的错误处理
# ---------- 可配置变量 ----------
REPO_BASE="/data/repos/rocky/9.4"
# 使用国内镜像加速,也可以换成你喜欢的其他镜像
MIRROR_URL="https://mirrors.aliyun.com/rockylinux"
REPOS=("BaseOS" "AppStream")
ARCH="x86_64"
LOG_DIR="/var/log/reposync"
LOG_FILE="${LOG_DIR}/sync_$(date +%Y%m%d_%H%M%S).log"
LOCK_FILE="/tmp/sync_rocky_repos.lock"
# -------------------------------
# 创建日志目录
mkdir -p "${LOG_DIR}"
# 函数:记录日志
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" | tee -a "${LOG_FILE}"
}
# 函数:错误处理
error_exit() {
log "ERROR: $1"
exit 1
}
# 检查是否已存在运行中的实例,防止重复执行
if [ -f "${LOCK_FILE}" ]; then
PID=$(cat "${LOCK_FILE}")
if ps -p "${PID}" > /dev/null 2>&1; then
log "另一个同步进程(PID: ${PID})正在运行,本次退出。"
exit 0
else
log "发现陈旧的锁文件,清理。"
rm -f "${LOCK_FILE}"
fi
fi
echo $$ > "${LOCK_FILE}"
trap 'rm -f ${LOCK_FILE}; log "同步进程结束。"' EXIT
# 检查root权限
if [[ $EUID -ne 0 ]]; then
error_exit "此脚本必须以root权限运行。"
fi
# 检查必要命令
for cmd in reposync createrepo_c; do
if ! command -v $cmd &>/dev/null; then
error_exit "未找到命令: $cmd,请先安装。"
fi
done
log "========== 开始Rocky Linux仓库同步 =========="
# 主同步循环
for REPO in "${REPOS[@]}"; do
REPO_PATH="${REPO_BASE}/${REPO}/${ARCH}/os"
REPO_NAME_LOWER=$(echo "${REPO}" | tr '[:upper:]' '[:lower:]')
# 确保目录存在
mkdir -p "${REPO_PATH}"
log "开始同步仓库: ${REPO} ..."
# 使用reposync同步,--delete 可删除本地已不存在的远程包(谨慎使用)
if reposync --repo="${REPO_NAME_LOWER}" \
--download-path="${REPO_PATH}" \
--download-metadata \
--newest-only \
--remote-time \
--downloadcomps \
--quiet \
--tempcache \
--source; then # --source 可选,同步源码包
log "仓库 ${REPO} 文件同步完成。"
else
log "警告:仓库 ${REPO} 文件同步过程出现错误,跳过元数据生成。"
continue
fi
log "开始为 ${REPO} 生成/更新元数据..."
# 使用--update参数增量更新元数据,比完全重建快得多
if createrepo_c --update --workers=$(nproc) "${REPO_PATH}"; then
log "仓库 ${REPO} 元数据更新完成。"
else
log "错误:仓库 ${REPO} 元数据生成失败。"
fi
done
# 可选:同步完成后,更新仓库索引页面(如果配置了的话)
# log "更新仓库Web索引..."
# /usr/local/bin/update_repo_html.sh
log "========== 所有仓库同步任务完成 =========="
给脚本添加执行权限:chmod +x /usr/local/bin/sync_rocky_repos.sh。可以先手动运行一次测试:/usr/local/bin/sync_rocky_repos.sh。
5.2 配置定时任务(Cron)
我们设定在每天凌晨网络空闲时段进行同步,并做好日志管理。
编辑root用户的crontab:crontab -e
# Rocky Linux 私有仓库同步任务
# 每天凌晨3点执行同步,并记录日志
0 3 * * * /usr/local/bin/sync_rocky_repos.sh > /dev/null 2>&1
# 每周日凌晨2点,清理30天前的同步日志
0 2 * * 0 find /var/log/reposync/ -name "sync_*.log" -mtime +30 -delete
这里将脚本输出重定向到/dev/null是因为脚本内部已经通过tee将日志写入了文件。你也可以将> /dev/null 2>&1改为>> /var/log/reposync/cron.log 2>&1来记录cron自身的输出。
5.3 监控与告警
简单的日志记录还不够,可以增加邮件通知功能。在同步脚本的末尾(log "所有仓库同步任务完成"之后)添加:
# 简单检查本次同步是否有错误(根据你的日志格式调整)
if grep -q "ERROR\|错误" "${LOG_FILE}"; then
mail -s "Rocky仓库同步报告:发现错误" admin@yourcompany.com < "${LOG_FILE}"
elif grep -q "警告" "${LOG_FILE}"; then
mail -s "Rocky仓库同步报告:存在警告" admin@yourcompany.com < "${LOG_FILE}"
else
mail -s "Rocky仓库同步报告:成功完成" admin@yourcompany.com < "${LOG_FILE}"
fi
当然,更成熟的方案是集成到像Zabbix、Prometheus这样的监控系统中,对同步任务的执行状态、仓库目录大小、最后更新时间等进行监控。
6. 高级优化与故障排查指南
仓库运行一段时间后,你可能会遇到一些性能问题或特定需求,这里分享几个进阶技巧。
6.1 性能优化策略
- 使用
reposync的--tempcache参数:它将元数据缓存到/var/cache/dnf,下次同步时只下载变化的部分,能显著减少网络流量和同步时间。 - 为
createrepo_c设置多线程:--workers=$(nproc)会让工具使用所有CPU核心来加速元数据生成。 - 考虑使用
hardlink或rsync:如果你需要为多个Rocky Linux小版本(如9.1, 9.2, 9.3, 9.4)维护仓库,其中大部分包是相同的,可以使用rsync --hard-links或cp -al创建硬链接,节省大量磁盘空间。但要注意,硬链接文件删除时需要特殊处理。 - Apache优化:对于大型仓库,可以调整Apache的
MaxKeepAliveRequests和KeepAliveTimeout,并启用mod_deflate压缩文本传输(如repomd.xml)。
6.2 常见问题与解决方案
| 问题现象 | 可能原因 | 排查步骤与解决方案 |
|---|---|---|
客户端dnf makecache失败,报404错误 | 1. Apache配置的Alias路径错误。 2. 仓库目录权限或SELinux上下文不正确。 3. createrepo_c未成功运行,缺少repodata目录。 | 1. 在服务器用curl http://localhost/repos/rocky/.../repomd.xml测试。2. 检查目录所有权( ls -ld /data/repos)、权限和SELinux上下文(ls -Z)。3. 确认 repodata目录存在且内有文件。 |
客户端能makecache但安装软件包时报错“找不到包” | 1. 仓库元数据损坏或未更新。 2. 客户端 .repo文件中baseurl路径不完整(少了/os/)。3. 同步未完成或中断。 | 1. 在服务器端重新运行createrepo_c --update。2. 仔细检查客户端 baseurl,确保指向包含repodata的目录。3. 检查同步日志,确认所有包已下载。 |
| 同步脚本执行缓慢,占用大量I/O | 1. 磁盘性能瓶颈(特别是机械硬盘)。 2. 未使用 --newest-only,同步了所有历史版本。3. 网络延迟高。 | 1. 考虑使用SSD或调整I/O调度器。 2. 确认脚本使用了 --newest-only。3. 更换更快的国内镜像源。 |
Apache日志出现Permission denied (13)错误 | SELinux阻止了Apache访问文件。 | 使用audit2why < /var/log/audit/audit.log分析SELinux拒绝信息,并正确设置上下文(semanage fcontext, restorecon)。 |
6.3 扩展:集成第三方仓库
企业内部往往还需要EPEL、Remi或自定义的RPM包。只需为每个第三方仓库创建独立的目录,并编写相应的同步脚本片段即可。例如,同步EPEL 9:
# 创建目录
mkdir -p /data/repos/epel/9/Everything/x86_64
# 在/etc/yum.repos.d/下配置一个临时的epel.repo,指向官方或镜像源
# 使用reposync同步,注意repo名称为 epel
reposync --repo=epel --download-path=/data/repos/epel/9/Everything/x86_64 ...其他参数
# 生成元数据
createrepo_c /data/repos/epel/9/Everything/x86_64
然后在客户端的.repo文件中增加对应的[epel]段落,baseurl指向这个新路径。
最后,别忘了定期检查仓库服务器的磁盘使用情况,df -h和du -sh /data/repos/*是你的好朋友。一套规划良好、自动化程度高的私有Yum仓库,就像给企业内部搭建了一条稳定的软件供应链高速公路,能极大提升系统部署、更新的效率和稳定性。
&spm=1001.2101.3001.5002&articleId=152649824&d=1&t=3&u=dc7ba1c401a14e23b751ff0aae7c4b1f)
411

被折叠的 条评论
为什么被折叠?



