仓库变更控制
在生产环境中,不加控制地直接从公共仓库更新软件包会带来不可预测的风险。仓库变更控制通过冻结仓库快照、搭建本地镜像和建立分阶段测试流程来保证更新的可靠性。
仓库基础管理
Section titled “仓库基础管理”查看当前启用的仓库
Section titled “查看当前启用的仓库”dnf repolist查看所有仓库(含禁用)
Section titled “查看所有仓库(含禁用)”dnf repolist all查看仓库详细信息
Section titled “查看仓库详细信息”dnf repoinfo baseos启用和禁用仓库
Section titled “启用和禁用仓库”dnf config-manager --disable epeldnf config-manager --enable epelmirrorlist 与 baseurl 固定
Section titled “mirrorlist 与 baseurl 固定”理解 mirrorlist 和 baseurl 的区别
Section titled “理解 mirrorlist 和 baseurl 的区别”- mirrorlist — 从镜像列表服务获取最近的镜像地址,每次可能指向不同的服务器和版本
- baseurl — 固定指向一个特定的仓库 URL,可确保一致性
将 mirrorlist 切换为固定 baseurl
Section titled “将 mirrorlist 切换为固定 baseurl”cat /etc/yum.repos.d/almalinux-baseos.repo# 备份原始配置cp /etc/yum.repos.d/almalinux-baseos.repo /etc/yum.repos.d/almalinux-baseos.repo.bak
# 注释掉 mirrorlist,启用 baseurlsed -i 's/^mirrorlist=/#mirrorlist=/' /etc/yum.repos.d/almalinux-baseos.reposed -i 's/^# *baseurl=/baseurl=/' /etc/yum.repos.d/almalinux-baseos.repo固定到特定版本的仓库(版本快照)
Section titled “固定到特定版本的仓库(版本快照)”AlmaLinux 和 Rocky Linux 的 vault 仓库保留了历史版本快照。
cat > /etc/yum.repos.d/almalinux-baseos-frozen.repo << 'EOF'[baseos-frozen]name=AlmaLinux 9.3 - BaseOS (Frozen)baseurl=https://repo.almalinux.org/vault/9.3/BaseOS/$basearch/os/enabled=1gpgcheck=1gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux-9EOFcat > /etc/yum.repos.d/rocky-baseos-frozen.repo << 'EOF'[baseos-frozen]name=Rocky Linux 9.3 - BaseOS (Frozen)baseurl=https://dl.rockylinux.org/vault/rocky/9.3/BaseOS/$basearch/os/enabled=1gpgcheck=1gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-Rocky-9EOF记得禁用原始仓库:
dnf config-manager --disable baseosdnf config-manager --enable baseos-frozen搭建本地仓库镜像
Section titled “搭建本地仓库镜像”本地镜像是生产环境仓库控制的最佳实践。
安装必要工具
Section titled “安装必要工具”dnf install -y createrepo_c dnf-plugins-core httpd同步上游仓库到本地
Section titled “同步上游仓库到本地”mkdir -p /var/www/html/repos/{baseos,appstream,epel}dnf reposync \ --repoid=baseos \ --download-metadata \ --destdir=/var/www/html/repos/baseos \ --newest-onlydnf reposync \ --repoid=appstream \ --download-metadata \ --destdir=/var/www/html/repos/appstream \ --newest-only生成仓库元数据
Section titled “生成仓库元数据”createrepo_c /var/www/html/repos/baseos/createrepo_c /var/www/html/repos/appstream/配置 HTTP 服务
Section titled “配置 HTTP 服务”cat > /etc/httpd/conf.d/repos.conf << 'EOF'<Directory /var/www/html/repos> Options Indexes FollowSymLinks AllowOverride None Require all granted</Directory>EOF
systemctl enable --now httpdfirewall-cmd --permanent --add-service=httpfirewall-cmd --reloadcat > /etc/yum.repos.d/local-mirror.repo << 'EOF'[local-baseos]name=Local Mirror - BaseOSbaseurl=http://repo-server.internal/repos/baseos/enabled=1gpgcheck=1gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux-9
[local-appstream]name=Local Mirror - AppStreambaseurl=http://repo-server.internal/repos/appstream/enabled=1gpgcheck=1gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux-9EOFdnf config-manager --disable baseos appstream定时同步脚本
Section titled “定时同步脚本”cat > /usr/local/bin/sync-repos.sh << 'SCRIPT'#!/bin/bashset -e
LOG="/var/log/repo-sync.log"REPO_BASE="/var/www/html/repos"DATE=$(date '+%Y-%m-%d %H:%M:%S')
echo "[$DATE] 开始仓库同步" >> "$LOG"
for repo in baseos appstream; do echo "[$DATE] 同步 $repo ..." >> "$LOG" dnf reposync \ --repoid="$repo" \ --download-metadata \ --destdir="$REPO_BASE/$repo" \ --newest-only \ --delete >> "$LOG" 2>&1
createrepo_c --update "$REPO_BASE/$repo/" >> "$LOG" 2>&1done
echo "[$DATE] 仓库同步完成" >> "$LOG"SCRIPT
chmod +x /usr/local/bin/sync-repos.shcat > /etc/cron.d/repo-sync << 'EOF'0 3 * * 0 root /usr/local/bin/sync-repos.shEOF分阶段测试更新
Section titled “分阶段测试更新”环境分层策略
Section titled “环境分层策略”推荐的更新推进路径:
开发环境 (Dev) → 测试环境 (Staging) → 预生产 (Pre-prod) → 生产 (Production)每一层使用不同时间点的仓库快照。
创建带版本标记的仓库快照
Section titled “创建带版本标记的仓库快照”SNAPSHOT_DATE=$(date +%Y%m%d)SNAPSHOT_DIR="/var/www/html/repos/snapshots/$SNAPSHOT_DATE"
mkdir -p "$SNAPSHOT_DIR"
# 使用硬链接创建快照(节省空间)cp -al /var/www/html/repos/baseos/ "$SNAPSHOT_DIR/baseos"cp -al /var/www/html/repos/appstream/ "$SNAPSHOT_DIR/appstream"
echo "快照已创建: $SNAPSHOT_DIR"为不同环境指定仓库快照
Section titled “为不同环境指定仓库快照”# Dev: baseurl=http://repo-server.internal/repos/baseos/cat > /etc/yum.repos.d/production.repo << 'EOF'[prod-baseos]name=Production BaseOS (Snapshot 20260315)baseurl=http://repo-server.internal/repos/snapshots/20260315/baseos/enabled=1gpgcheck=1gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux-9EOF变更管理工作流
Section titled “变更管理工作流”标准变更流程
Section titled “标准变更流程”- 发现 — 监控上游安全公告和更新
- 评估 — 分析更新的影响范围和风险
- 测试 — 在开发/测试环境验证
- 审批 — 经过变更审批流程
- 执行 — 在维护窗口内推送到生产环境
- 验证 — 检查服务和功能正常
- 记录 — 记录变更内容和结果
生成更新报告
Section titled “生成更新报告”#!/bin/bashecho "========================================="echo " 系统更新评估报告"echo " 主机: $(hostname)"echo " 日期: $(date)"echo "========================================="echo ""
echo "--- 当前系统 ---"cat /etc/redhat-releaseecho "内核: $(uname -r)"echo ""
echo "--- 可用更新 ---"dnf check-update 2>/dev/null || trueecho ""
echo "--- 安全更新统计 ---"dnf updateinfo summary 2>/dev/nullecho ""
echo "--- 安全公告详情 ---"dnf updateinfo list security 2>/dev/null记录变更操作
Section titled “记录变更操作”#!/bin/bashCHANGE_LOG="/var/log/change-management.log"TICKET_ID="${1:-UNTRACKED}"
echo "==============================" >> "$CHANGE_LOG"echo "变更工单: $TICKET_ID" >> "$CHANGE_LOG"echo "操作人员: $(whoami)" >> "$CHANGE_LOG"echo "操作时间: $(date)" >> "$CHANGE_LOG"echo "更新前包状态:" >> "$CHANGE_LOG"rpm -qa --qf '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' | sort >> "$CHANGE_LOG"echo "==============================" >> "$CHANGE_LOG"
# 执行更新dnf update -y 2>&1 | tee -a "$CHANGE_LOG"
echo "更新后包状态:" >> "$CHANGE_LOG"rpm -qa --qf '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' | sort >> "$CHANGE_LOG"使用 dnf history 追踪变更
Section titled “使用 dnf history 追踪变更”dnf history listdnf history info <事务ID> > /var/log/change-$(date +%Y%m%d)-txn<事务ID>.logGPG 密钥管理
Section titled “GPG 密钥管理”查看已导入的 GPG 密钥
Section titled “查看已导入的 GPG 密钥”rpm -qa gpg-pubkey* --qf '%{NAME}-%{VERSION}-%{RELEASE}\t%{SUMMARY}\n'导入新的 GPG 密钥
Section titled “导入新的 GPG 密钥”rpm --import https://example.com/RPM-GPG-KEY-example验证包的签名
Section titled “验证包的签名”rpm -K <包文件名>.rpmrpm -qa --qf '%{NAME}-%{VERSION}-%{RELEASE}\t%{SIGPGP:pgpsig}\n' | head -20