本文将详细介绍多种锁定Rocky Linux系统主版本的方法,防止意外升级到新版本。其中,有相当脚本内容由AI生成,并未得到完全验证,特别对于内部升级源的地址、管理脚本需要认真鉴别再使用。

2025.06 陕西·西安·秦汉通航公司

使用dnf版本锁定插件

安装dnf-plugin-versionlock

# 安装版本锁定插件
sudo dnf install -y dnf-plugin-versionlock

# 验证安装
dnf list installed | grep versionlock

锁定整个系统版本

# 方法1:锁定所有已安装的包
sudo dnf versionlock add '*'

锁定特定关键包

# 锁定核心系统包
sudo dnf versionlock add kernel*
sudo dnf versionlock add systemd*
sudo dnf versionlock add glibc*
sudo dnf versionlock add rocky-release*

# 查看已锁定的包
sudo dnf versionlock list

创建锁定脚本

#!/bin/bash
# lock_version.sh - 锁定Rocky Linux主版本

LOCK_FILE="/etc/dnf/plugins/versionlock.list"
BACKUP_DIR="/etc/dnf/plugins/backups"

echo "=== 锁定Rocky Linux系统版本 ==="

# 备份当前锁定列表
if [ ! -d "$BACKUP_DIR" ]; then
sudo mkdir -p "$BACKUP_DIR"
fi
sudo cp "$LOCK_FILE" "$BACKUP_DIR/versionlock.list.$(date +%Y%m%d_%H%M%S)"

# 锁定关键包
echo "锁定核心包..."
sudo dnf versionlock add \
rocky-release \
kernel \
systemd \
glibc \
openssl \
bash \
dnf \
yum \
rpm

# 锁定所有rocky-repo相关包
echo "锁定仓库相关包..."
for pkg in $(dnf list installed "rocky*" | grep -v "Installed Packages" | awk '{print $1}'); do
sudo dnf versionlock add "$pkg"
done

# 锁定所有当前已安装的包(可选,但更彻底)
echo "正在锁定所有已安装包..."
sudo dnf versionlock add '*'

echo "版本锁定完成!"
echo "当前锁定的包数量: $(sudo dnf versionlock list | wc -l)"

使用yum/dnf配置锁定

配置dnf排除列表

# 编辑dnf配置文件
sudo nano /etc/dnf/dnf.conf

# 添加以下排除规则
[main]
excludepkgs=kernel*, rocky-release*, systemd*, glibc*, openssl*

创建版本锁定配置文件

# 创建专门的排除配置文件
sudo tee /etc/dnf/conf.d/version-lock.conf << 'EOF'
# Rocky Linux 主版本锁定配置
# 创建时间: $(date)
# 系统版本: $(cat /etc/rocky-release)

[version-lock]
# 排除所有可能导致主版本升级的包
excludepkgs=kernel*, rocky-release*, systemd*, initscripts, glibc*, openssl*

# 排除所有仓库元数据更新
metadata_timer_sync=0

# 禁用自动更新
automatic=0
EOF

通过仓库配置锁定

禁用自动仓库更新

# 检查当前启用的仓库
sudo dnf repolist enabled

# 禁用所有仓库的自动更新
sudo dnf config-manager --setopt=*.metadata_timer_sync=0 --save

# 禁用特定仓库
sudo dnf config-manager --set-disabled rocky-devel
sudo dnf config-manager --set-disabled rocky-extras

固定仓库版本

# 备份原始仓库配置
sudo cp -r /etc/yum.repos.d /etc/yum.repos.d.backup.$(date +%Y%m%d)

# 修改所有rocky仓库配置,固定到当前版本
CURRENT_VERSION=$(rpm -q rocky-release | sed 's/.*release-//' | cut -d- -f1)

sudo find /etc/yum.repos.d -name "*.repo" -exec sed -i \
"s/\$releasever/$CURRENT_VERSION/g" {} \;

echo "已将仓库版本固定到: $CURRENT_VERSION"

创建自定义锁定仓库配置

# 创建只包含当前版本更新的仓库
sudo tee /etc/yum.repos.d/rocky-locked.repo << EOF
# Rocky Linux 锁定版本仓库
# 仅包含当前主版本的更新

[rocky-baseos-locked]
name=Rocky Linux \$releasever - BaseOS - Locked
baseurl=http://dl.rockylinux.org/pub/rocky/9/BaseOS/\$basearch/os/
enabled=1
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-Rocky-9
metadata_expire=never

[rocky-appstream-locked]
name=Rocky Linux \$releasever - AppStream - Locked
baseurl=http://dl.rockylinux.org/pub/rocky/9/AppStream/\$basearch/os/
enabled=1
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-Rocky-9
metadata_expire=never

# 禁用其他所有仓库
[rocky*]
enabled=0
EOF

使用systemd定时任务监控和防止升级

创建版本监控脚本

#!/bin/bash
# monitor_version.sh - 监控并防止系统版本升级

LOG_FILE="/var/log/version-monitor.log"
ALERT_EMAIL="admin@example.com"
LOCK_FILE="/etc/.rocky-version-locked"

# 记录日志
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> "$LOG_FILE"
}

# 检查是否有版本升级尝试
check_upgrade_attempt() {
# 检查最近的dnf/yum日志
if tail -100 /var/log/dnf.log 2>/dev/null | grep -q "Upgrading.*rocky-release"; then
log "检测到rocky-release升级尝试!"
return 1
fi

# 检查是否有新版本的仓库元数据
if [ -f /var/cache/dnf/rocky*.xml.gz ]; then
TIMESTAMP=$(stat -c %Y /var/cache/dnf/rocky*.xml.gz 2>/dev/null | head -1)
NOW=$(date +%s)
if [ $((NOW - TIMESTAMP)) -lt 3600 ]; then
log "检测到新的仓库元数据更新"
return 1
fi
fi

return 0
}

# 阻止升级操作
prevent_upgrade() {
log "执行阻止升级操作"

# 清除新的仓库缓存
sudo rm -f /var/cache/dnf/rocky*.xml.gz

# 重置版本锁定
if [ -f /etc/dnf/plugins/versionlock.list ]; then
# 重新锁定关键包
for pkg in rocky-release kernel systemd; do
if ! grep -q "^$pkg" /etc/dnf/plugins/versionlock.list; then
sudo dnf versionlock add "$pkg*" >/dev/null 2>&1
fi
done
fi

# 发送警报
echo "检测到系统版本升级尝试!已阻止。" | mail -s "Rocky Linux版本升级警报" "$ALERT_EMAIL"
}

# 主函数
main() {
log "开始版本监控检查"

if check_upgrade_attempt; then
log "未检测到升级尝试"
else
log "检测到升级尝试,正在阻止..."
prevent_upgrade
fi
}

# 执行主函数
main

创建systemd服务

# 创建服务文件
sudo tee /etc/systemd/system/version-protect.service << 'EOF'
[Unit]
Description=Rocky Linux Version Protection Service
After=network-online.target
Wants=network-online.target

[Service]
Type=oneshot
ExecStart=/usr/local/bin/monitor_version.sh
User=root
Group=root

[Install]
WantedBy=multi-user.target
EOF

创建systemd定时器

sudo tee /etc/systemd/system/version-protect.timer << 'EOF'
[Unit]
Description=Run version protection every 5 minutes

[Timer]
OnBootSec=5min
OnUnitActiveSec=5min

[Install]
WantedBy=timers.target
EOF

启用监控服务

sudo cp monitor_version.sh /usr/local/bin/
sudo chmod +x /usr/local/bin/monitor_version.sh
sudo chmod 700 /usr/local/bin/monitor_version.sh

sudo systemctl daemon-reload
sudo systemctl enable version-protect.timer
sudo systemctl start version-protect.timer

# 查看状态
sudo systemctl status version-protect.timer

使用rpm包验证和防护

创建rpm包验证脚本

#!/bin/bash
# verify_packages.sh - 验证关键包未被更改

KEY_PACKAGES="rocky-release kernel systemd glibc"
DATABASE="/var/lib/rpm/Packages"
VERIFY_LOG="/var/log/rpm-verify.log"

echo "=== 关键包完整性验证 $(date) ===" | tee -a "$VERIFY_LOG"

for pkg in $KEY_PACKAGES; do
# 获取包名
FULL_PKG=$(rpm -qa | grep "^$pkg" | head -1)

if [ -n "$FULL_PKG" ]; then
echo "验证包: $FULL_PKG" | tee -a "$VERIFY_LOG"

# 验证包完整性
rpm -V "$FULL_PKG" 2>&1 | tee -a "$VERIFY_LOG"

if [ ${PIPESTATUS[0]} -ne 0 ]; then
echo "警告: $FULL_PKG 已被修改!" | tee -a "$VERIFY_LOG"

# 记录到系统日志
logger -t version-lock "关键包 $FULL_PKG 已被修改"
fi
fi
done

echo "=== 验证完成 ===" | tee -a "$VERIFY_LOG"

设置rpm验证定时任务

# 添加cron定时任务
sudo crontab -l > /tmp/cron.bak
echo "0 */6 * * * /usr/local/bin/verify_packages.sh" | sudo crontab -

# 或使用systemd timer
sudo tee /etc/systemd/system/package-verify.timer << 'EOF'
[Unit]
Description=Verify critical packages every 6 hours

[Timer]
OnCalendar=*-*-* */6:00:00

[Install]
WantedBy=timers.target
EOF

网络安全防护

配置防火墙规则限制外部更新

# 允许必要的更新源,阻止其他
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="152.19.134.142" port port="80" protocol="tcp" accept'
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="152.19.134.198" port port="80" protocol="tcp" accept'

# 阻止其他所有到更新服务器的连接
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" destination address="dl.rockylinux.org" drop'
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv6" destination address="dl.rockylinux.org" drop'

# 重新加载防火墙
sudo firewall-cmd --reload

使用本地镜像仓库

# 设置本地镜像源
sudo tee /etc/yum.repos.d/rocky-local.repo << 'EOF'
[local-baseos]
name=Rocky Linux Local - BaseOS
baseurl=file:///var/www/html/rocky/BaseOS
enabled=1
gpgcheck=0

[local-appstream]
name=Rocky Linux Local - AppStream
baseurl=file:///var/www/html/rocky/AppStream
enabled=1
gpgcheck=0
EOF

# 禁用官方仓库
sudo dnf config-manager --set-disabled rocky*

完整版本锁定脚本

主锁定脚本

#!/bin/bash
# rocky-version-lock.sh - 完整的Rocky Linux版本锁定脚本

set -e

# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color

# 日志文件
LOG_FILE="/var/log/rocky-version-lock.log"
LOCK_FILE="/etc/.rocky-version-locked"

# 记录日志
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"
}

# 打印带颜色的消息
print_status() {
echo -e "${GREEN}[✓]${NC} $1" | tee -a "$LOG_FILE"
}

print_warning() {
echo -e "${YELLOW}[!]${NC} $1" | tee -a "$LOG_FILE"
}

print_error() {
echo -e "${RED}[✗]${NC} $1" | tee -a "$LOG_FILE"
}

# 检查是否已锁定
check_lock() {
if [ -f "$LOCK_FILE" ]; then
CURRENT_VERSION=$(cat "$LOCK_FILE")
log "系统已锁定到版本: $CURRENT_VERSION"
return 0
fi
return 1
}

# 获取当前版本
get_current_version() {
if [ -f /etc/rocky-release ]; then
grep -oP 'release \K[0-9.]+' /etc/rocky-release
else
echo "unknown"
fi
}

# 安装必要的工具
install_tools() {
log "安装必要的工具..."

# 安装dnf版本锁定插件
if ! rpm -q dnf-plugin-versionlock >/dev/null 2>&1; then
dnf install -y dnf-plugin-versionlock 2>&1 | tee -a "$LOG_FILE"
print_status "已安装dnf-plugin-versionlock"
else
print_status "dnf-plugin-versionlock 已安装"
fi

# 安装其他必要工具
dnf install -y yum-utils rpm-utils 2>&1 | tee -a "$LOG_FILE"
}

# 锁定核心包
lock_core_packages() {
log "锁定核心系统包..."

# 备份当前锁定列表
if [ -f /etc/dnf/plugins/versionlock.list ]; then
cp /etc/dnf/plugins/versionlock.list /etc/dnf/plugins/versionlock.list.backup.$(date +%Y%m%d_%H%M%S)
fi

# 定义关键包列表
CORE_PACKAGES="
rocky-release
kernel
systemd
glibc
openssl
bash
dnf
yum
rpm
initscripts
grub2
firewalld
NetworkManager
"

# 锁定每个关键包
for pkg in $CORE_PACKAGES; do
# 获取完整的包名
FULL_PKG=$(rpm -qa | grep "^$pkg" | head -1)
if [ -n "$FULL_PKG" ]; then
dnf versionlock add "$FULL_PKG" 2>&1 | tee -a "$LOG_FILE"
print_status "已锁定: $FULL_PKG"
fi
done

# 锁定所有rocky*包
for pkg in $(rpm -qa | grep "^rocky"); do
dnf versionlock add "$pkg" 2>&1 | tee -a "$LOG_FILE"
done

print_status "核心包锁定完成"
}

# 配置仓库锁定
lock_repositories() {
log "配置仓库锁定..."

# 备份原始仓库配置
REPO_BACKUP="/etc/yum.repos.d.backup.$(date +%Y%m%d_%H%M%S)"
cp -r /etc/yum.repos.d "$REPO_BACKUP"
print_status "仓库配置已备份到: $REPO_BACKUP"

# 固定当前版本
CURRENT_VERSION=$(get_current_version)

# 更新所有仓库配置,固定版本号
find /etc/yum.repos.d -name "*.repo" -type f | while read repo_file; do
sed -i "s/\$releasever/$CURRENT_VERSION/g" "$repo_file"
sed -i "s/\$basearch/x86_64/g" "$repo_file" # 固定架构
done

# 禁用元数据自动更新
echo -e "[main]\ngpgcheck=1\ninstallonly_limit=3\nclean_requirements_on_remove=True\nmetadata_timer_sync=0" | tee /etc/dnf/dnf.conf

print_status "仓库锁定配置完成"
}

# 创建防护服务
setup_protection_services() {
log "设置防护服务..."

# 创建监控脚本
cat > /usr/local/bin/rocky-monitor.sh << 'EOF'
#!/bin/bash
# 监控脚本 - 防止意外升级

LOCK_FILE="/etc/.rocky-version-locked"
LOG="/var/log/rocky-monitor.log"

check_upgrade() {
# 检查是否有升级尝试
if journalctl -u dnf-makecache --since "1 hour ago" | grep -q "Metadata cache created"; then
echo "[$(date)] 检测到仓库缓存更新" >> "$LOG"
return 1
fi
return 0
}

if check_upgrade; then
echo "[$(date)] 系统状态正常" >> "$LOG"
else
echo "[$(date)] 警告:检测到可能的升级尝试" >> "$LOG"
# 可以添加通知逻辑
fi
EOF

chmod +x /usr/local/bin/rocky-monitor.sh

# 创建systemd服务
cat > /etc/systemd/system/rocky-protect.service << EOF
[Unit]
Description=Rocky Linux Version Protection
After=network.target

[Service]
Type=oneshot
ExecStart=/usr/local/bin/rocky-monitor.sh
User=root
EOF

cat > /etc/systemd/system/rocky-protect.timer << EOF
[Unit]
Description=Run version protection hourly

[Timer]
OnBootSec=15min
OnUnitActiveSec=1h

[Install]
WantedBy=timers.target
EOF

systemctl daemon-reload
systemctl enable rocky-protect.timer
systemctl start rocky-protect.timer

print_status "防护服务已设置"
}

# 主函数
main() {
echo "=== Rocky Linux 版本锁定工具 ===" | tee -a "$LOG_FILE"

# 检查root权限
if [ "$EUID" -ne 0 ]; then
print_error "请使用root权限运行此脚本"
exit 1
fi

# 检查是否已锁定
if check_lock; then
print_warning "系统已被锁定,是否重新锁定?(y/N)"
read -r response
case "$response" in
[yY][eE][sS]|[yY])
print_status "继续锁定操作..."
;;
*)
print_status "退出"
exit 0
;;
esac
fi

# 获取当前版本
CURRENT_VERSION=$(get_current_version)
log "当前系统版本: $CURRENT_VERSION"

# 执行锁定步骤
install_tools
lock_core_packages
lock_repositories
setup_protection_services

# 创建锁定标记
echo "$CURRENT_VERSION" > "$LOCK_FILE"
chmod 600 "$LOCK_FILE"

# 显示锁定状态
echo -e "\n${GREEN}=== 版本锁定完成 ===${NC}" | tee -a "$LOG_FILE"
echo "锁定版本: $CURRENT_VERSION" | tee -a "$LOG_FILE"
echo "锁定包数量: $(dnf versionlock list | wc -l)" | tee -a "$LOG_FILE"
echo "日志文件: $LOG_FILE" | tee -a "$LOG_FILE"
echo "锁定标记: $LOCK_FILE" | tee -a "$LOG_FILE"

# 最终建议
echo -e "\n${YELLOW}=== 重要提示 ===${NC}" | tee -a "$LOG_FILE"
echo "1. 定期检查系统安全更新" | tee -a "$LOG_FILE"
echo "2. 需要升级时,运行解锁脚本" | tee -a "$LOG_FILE"
echo "3. 监控日志文件: $LOG_FILE" | tee -a "$LOG_FILE"
}

# 解锁函数
unlock_version() {
echo "=== 解锁系统版本 ==="

# 移除版本锁定
dnf versionlock clear

# 恢复原始仓库配置
if [ -d "/etc/yum.repos.d.backup."* ]; then
LATEST_BACKUP=$(ls -td /etc/yum.repos.d.backup.* | head -1)
if [ -n "$LATEST_BACKUP" ]; then
rm -rf /etc/yum.repos.d
cp -r "$LATEST_BACKUP" /etc/yum.repos.d
print_status "已恢复仓库配置"
fi
fi

# 删除锁定标记
rm -f "$LOCK_FILE"

# 禁用防护服务
systemctl stop rocky-protect.timer
systemctl disable rocky-protect.timer

print_status "系统版本已解锁"
}

# 参数处理
case "$1" in
lock)
main
;;
unlock)
unlock_version
;;
status)
if check_lock; then
print_status "系统已被锁定"
else
print_status "系统未锁定"
fi
;;
*)
echo "使用方法: $0 {lock|unlock|status}"
exit 1
;;
esac

使用脚本

# 赋予执行权限
chmod +x rocky-version-lock.sh

# 锁定系统版本
sudo ./rocky-version-lock.sh lock

# 查看状态
sudo ./rocky-version-lock.sh status

# 解锁系统版本
sudo ./rocky-version-lock.sh unlock

手动验证和监控

创建验证报告脚本

#!/bin/bash
# version-report.sh - 生成版本锁定报告

REPORT_FILE="/var/log/version-lock-report-$(date +%Y%m%d).txt"

echo "=== Rocky Linux 版本锁定状态报告 ===" > "$REPORT_FILE"
echo "生成时间: $(date)" >> "$REPORT_FILE"
echo "" >> "$REPORT_FILE"

# 1. 系统信息
echo "1. 系统信息:" >> "$REPORT_FILE"
echo " Rocky版本: $(cat /etc/rocky-release 2>/dev/null || echo '未知')" >> "$REPORT_FILE"
echo " 内核版本: $(uname -r)" >> "$REPORT_FILE"
echo " 系统架构: $(uname -m)" >> "$REPORT_FILE"
echo "" >> "$REPORT_FILE"

# 2. 锁定包状态
echo "2. 版本锁定状态:" >> "$REPORT_FILE"
echo " 锁定包数量: $(dnf versionlock list | wc -l 2>/dev/null || echo '未安装插件')" >> "$REPORT_FILE"
echo "" >> "$REPORT_FILE"

# 3. 关键包版本
echo "3. 关键包版本:" >> "$REPORT_FILE"
for pkg in rocky-release kernel systemd glibc; do
version=$(rpm -q "$pkg" 2>/dev/null || echo "未安装")
echo " $pkg: $version" >> "$REPORT_FILE"
done
echo "" >> "$REPORT_FILE"

# 4. 仓库状态
echo "4. 仓库配置:" >> "$REPORT_FILE"
grep -h "^\[" /etc/yum.repos.d/*.repo 2>/dev/null | sed 's/^/ /' >> "$REPORT_FILE"
echo "" >> "$REPORT_FILE"

# 5. 监控状态
echo "5. 监控服务状态:" >> "$REPORT_FILE"
systemctl status rocky-protect.timer 2>/dev/null | grep -E "(Active|Loaded)" | sed 's/^/ /' >> "$REPORT_FILE"

echo "报告已生成: $REPORT_FILE"

注意事项

安全更新处理

虽然锁定版本,但仍需关注安全更新:

# 定期检查安全更新(不自动安装)
sudo dnf check-update --security

# 手动应用关键安全更新
sudo dnf update --security --skip-broken

备份策略

# 备份关键配置
sudo tar -czf /backup/rocky-lock-backup-$(date +%Y%m%d).tar.gz \
/etc/yum.repos.d \
/etc/dnf/ \
/etc/systemd/system/rocky-*.service \
/etc/systemd/system/rocky-*.timer

解锁时的注意事项

  • 解锁前确保系统有完整备份
  • 逐步测试更新,避免大规模升级
  • 监控系统稳定性

最佳实践

分层锁定策略

  • 第一层:dnf versionlock 锁定核心包
  • 第二层:仓库配置固定版本
  • 第三层:监控服务防止意外更新

定期审计

# 每周生成报告
0 0 * * 0 /usr/local/bin/version-report.sh

文档记录

  • 记录锁定原因和时间
  • 记录解锁流程
  • 记录测试结果

通过以上方法,您可以有效地锁定Rocky Linux系统的主版本,防止意外升级,同时保持系统的稳定性和安全性


参考内容

  1. Docker稳定性保障:Ubuntu环境版本锁定方案
  2. Ubuntu Linux内核版本升级指南:mainline