背景

在离线环境下部署业务系统时,RPM 包依赖冲突是最常见也是最棘手的问题之一。由于无法直接访问外网仓库,运维人员往往只能靠手工排查耗时耗力。本文介绍一套在离线环境下自动检测并修复 RPM 依赖冲突的实战方案,适用于 CentOS/RHEL 7/8 系列操作系统。

核心思路

离线环境依赖冲突的本质是:本地仓库中缺少某个 RPM 包所依赖的其他包,或者存在版本不兼容的包。解决方案分为三步:收集→分析→修复

一、生成依赖快照

在联网环境下,先将目标主机的所有 RPM 依赖信息导出备用:

1
2
3
4
5
6
7
8
9
10
11
# 导出当前系统所有已安装包的依赖关系
rpm -qa --queryformat '%{NAME}|%{VERSION}|%{RELEASE}|%{ARCH}\n' | sort > /tmp/rpm_installed.txt

# 导出每个包的完整依赖列表(递归)
mkdir -p /tmp/deps
for pkg in $(rpm -qa --queryformat '%{NAME}\n'); do
rpm -qR "$pkg" 2>/dev/null | grep -v 'rpmlib' > /tmp/deps/${pkg}.txt
done

# 打包带走
tar -czf /tmp/rpm_deps.tar.gz /tmp/rpm_installed.txt /tmp/deps/

这一步在接入网络时执行一次即可,后续离线部署时直接使用。

二、自动检测冲突

将上述快照拷贝到离线环境后,执行以下脚本自动检测冲突:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#!/bin/bash
# check_deps.sh — 离线环境 RPM 依赖冲突检测

REPO_DIR="/mnt/repo" # 离线RPM仓库目录
TMP_WARN="/tmp/deps_warn.txt"
> "$TMP_WARN"

echo "正在扫描RPM包依赖冲突..."

for pkg_file in $(find "$REPO_DIR" -name "*.rpm" -type f); do
pkg_name=$(rpm -qp --queryformat '%{NAME}' "$pkg_file")
requires=$(rpm -qpR "$pkg_file" 2>/dev/null | grep -v 'rpmlib')

for req in $requires; do
# 去除版本号,只比较包名
req_name=$(echo "$req" | sed 's/[<>(=].*//')
if ! rpm -qa | grep -q "^${req_name}-"; then
# 检查本地仓库是否有此包
if ! find "$REPO_DIR" -name "${req_name}-*.rpm" | grep -q .; then
echo "[缺失] $pkg_name 需要 $req_name (无可用包)" >> "$TMP_WARN"
fi
fi
done
done

if [ -s "$TMP_WARN" ]; then
echo "检测到依赖冲突,请查看 /tmp/deps_warn.txt"
sort -u "$TMP_WARN"
else
echo "未检测到明显依赖冲突"
fi

三、自动修复策略

检测到冲突后,通常有两类处理方式:

3.1 补充缺失包

1
2
# 批量安装缺失包(假设已将缺失包补充到 $REPO_DIR)
yum localinstall --disablerepo=* /mnt/repo/*.rpm -y

3.2 版本降级适配

当版本不兼容时,降级到兼容版本:

1
2
3
4
5
# 查找可用的历史版本
yum --disablerepo=* list available "$PKG_NAME" --installroot=/tmp/fake

# 强制降级
rpm -Uvh --oldpackage --force /mnt/repo/${PKG_NAME}-*.rpm

3.3 创建离线镜像仓库

推荐使用 createrepo 维护本地镜像,一劳永逸:

1
2
3
4
5
6
7
8
9
10
11
12
13
# 建立本地仓库索引
createrepo /mnt/repo/

# 使用示例(永久配置)
cat >> /etc/yum.repos.d/local.repo << 'EOF'
[local]
name=Local Repo
baseurl=file:///mnt/repo
enabled=1
gpgcheck=0
EOF

yum makecache

四、实战案例

某业务系统需要部署 Oracle JDK 11,但业务应用依赖 glibc >= 2.18,而离线环境的 CentOS 7 只有 glibc 2.17。传统做法是重装系统,但现在可以:

  1. 从 CentOS 7.9 镜像中提取 glibc-2.18 相关 RPM 包,放入离线仓库
  2. 运行检测脚本,发现冲突来源是 glibc 版本过低
  3. 使用 rpm -Uvh --force 升级 glibc(注意:此操作需评估风险)
  4. 验证:ldd --version 确认版本

注意事项

  • 升级 glibc 等核心包前务必做快照备份,核心库升级有导致系统无法启动的风险
  • 建议所有离线包按 OS 版本分类管理,避免跨版本混用
  • 检测脚本可集成到 Ansible,在批量部署前自动执行,提前发现问题

总结

离线 RPM 依赖冲突的核心是”信息不对称”——不知道缺什么、缺了哪里找。通过建立依赖快照、本地仓库索引和自动化检测机制,可以将原本需要数小时手工排查的工作缩短到几分钟以内,大幅提升离线环境下的运维效率。