Alibaba Cloud Linux 4 制作 Ansible RPM 包实践(离线可复用)
背景:内网 / 信创环境下无法直接访问互联网安装软件,需要把 Ansible 封装成标准 RPM 包,便于使用
yum/dnf统一安装与离线分发。
一、为什么不能直接装官方源 / EPEL 的包
先确认系统基线:
bash
cat /etc/os-release
python3 --version
ls -l /usr/bin/python3.11
结论如下:
- Alibaba Cloud Linux 4(Alinux 4)基于 Anolis OS 23 生态 ,默认 Python 为 3.11 (
/usr/bin/python3.11存在),而不是 CentOS/RHEL 9 的 Python 3.9。 - 官方源中没有 ansible 包。
- EPEL 9 中的
ansibleRPM(如ansible-7.7.0-1.el9.noarch)按照 Python 3.9 打包,在 Alinux 4 上无法安装。
尝试直接下载时出现的典型报错:
text
Error:
Problem: conflicting requests
- nothing provides python(abi) = 3.9 needed by ansible-7.7.0-1.el9.noarch
- nothing provides python3.9dist(ansible-core) >= 2.14.7 needed by ansible-7.7.0-1.el9.noarch
--nobest、--skip-broken 均无法绕过,因为整个依赖链都绑定 Python 3.9。EPEL 8 源同样不适用。
结论:Alinux 4 与 CentOS/RHEL 系组件不能直接互用,需要基于 Python 3.11 自行制作 RPM。
二、方案选型
| 方案 | 可行性 | 说明 |
|---|---|---|
| 官方源直接安装 | 不可行 | 官方源无 ansible 包 |
EPEL RPM 直装 / --downloadonly |
不可行 | 依赖 python(abi)=3.9,与系统 Python 3.11 冲突 |
| EPEL 源码重打包 | 不可行 | 依赖链整体绑定 3.9,需要全部重建,工程量巨大 |
| venv + pip 在线 / 离线安装 | 可用 | 适合单机,但不是 RPM 规范,无法用 yum 统一管理 |
| RPM 外壳 + venv 封装 | 推荐 | RPM 作为外壳,内部用独立 venv + pip 安装 ansible 及全部依赖,满足 yum 安装规范,离线可复用 |
最终采用 RPM 外壳 + venv 封装方案:
- Ansible 与全部 Python 依赖封装进独立虚拟环境
/usr/lib/ansible-venv; - 不污染系统 Python;
- 目标机只要满足
python3 >= 3.11即可直接安装。
版本确认:阿里云 PyPI 镜像上 ansible 最新为 12.3.0 (要求 Python >= 3.11),其核心依赖 ansible-core~=2.19.5 同样要求 Python >= 3.11,且提供 py3-none-any 纯 Python wheel,无需编译,具备打包条件。
三、构建环境准备
bash
# 1. 安装构建工具与 Python 环境
sudo dnf install -y rpm-build rpmdevtools python3 python3-pip
# 2. 确认 Python 3.11 与 venv 可用
python3 --version
python3 -m venv --help >/dev/null && echo "venv OK"
# 3. 生成 rpmbuild 目录结构(等价于手动创建 ~/rpmbuild/{BUILD,BUILDROOT,RPMS,SOURCES,SPECS,SRPMS})
rpmdev-setuptree
# 4. 配置 PyPI 镜像(用户级配置,构建期 pip 会按该配置拉取依赖)
mkdir -p ~/.pip
cat > ~/.pip/pip.conf <<'EOF'
[global]
index-url = https://mirrors.aliyun.com/pypi/simple/
EOF
说明:pip 按
全局 /etc/pip.conf → 用户 ~/.pip/pip.conf → 项目级的优先级读取配置。此处写在~/.pip/pip.conf(用户级配置) ,rpmbuild内部执行的pip install会读取同一$HOME下的配置,同样生效;若以 root 身份构建,实际生效文件为/root/.pip/pip.conf。内网 HTTP 镜像(如mirrors.cloud.aliyuncs.com)可能因不受信任被 pip 忽略,导致No matching distribution found for ansible,建议直接使用 HTTPS 源,无需trusted-host。
如何在 pip 源中查询 ansible 可用版本
bash
# 1. 查看当前 pip 生效的索引地址,确认配置已加载
pip config list
# 2. 查询 pip 源中 ansible 的全部可用版本(需要 pip >= 23.1)
pip index versions ansible
# 输出示例(仅列出兼容当前 Python 3.11 的版本)
# ansible (12.3.0)
# Available versions: 12.3.0, 12.2.0, 11.3.0, ...
要点:
pip index versions ansible会按当前解释器的兼容性 (requires-python)过滤展示可安装版本,可直接确认源内最新版与可用版本列表(当前为 12.3.0)。- 若系统 pip 版本过旧不支持
pip index,可以直接查看镜像的 simple 索引页,含义相同:curl -s https://mirrors.aliyun.com/pypi/simple/ansible/ | grep -oE 'ansible-[0-9]+(\.[0-9]+)+' | sort -Vu | tail -n 20。 - 不加版本直接
pip install ansible会安装源内最新且兼容当前 Python 的版本;需要固定版本时写pip install ansible==12.3.0。
四、编写 spec 文件
保存到 ~/rpmbuild/SPECS/ansible.spec:
spec
Name: ansible
Version: 12.3.0
Release: 1%{?dist}
Summary: Ansible is a radically simple IT automation platform
License: GPL-3.0-or-later
URL: https://www.ansible.com/
BuildRequires: python3 >= 3.11
Requires: python3 >= 3.11
%global ansible_venv %{_prefix}/lib/ansible-venv
%description
基于 Python 3.11(Alinux 4 系统默认)构建的 ansible,
所有 Python 依赖封装在 %{ansible_venv} 虚拟环境中,不污染系统 Python。
%prep
# 无需源码包,ansible 由 pip 在 %build 阶段安装
:
%build
rm -rf %{_builddir}/venv
python3 -m venv %{_builddir}/venv
%{_builddir}/venv/bin/pip install --no-cache-dir ansible==%{version}
%install
mkdir -p %{buildroot}%{ansible_venv} %{buildroot}%{_bindir}
cp -a %{_builddir}/venv/. %{buildroot}%{ansible_venv}/
# 修正 venv/bin 下所有入口脚本的 shebang:构建路径 -> 最终安装路径
# grep 精确命中第一行以构建路径开头的文本脚本,避免误伤二进制/软链接
grep -rl '^#!%{_builddir}/venv/bin/python' %{buildroot}%{ansible_venv}/bin 2>/dev/null | while read -r f; do
sed -i "1s|^#!%{_builddir}/venv/bin/python.*|#!%{ansible_venv}/bin/python|" "$f"
done
# 在 /usr/bin 提供 ansible* 入口
for b in %{buildroot}%{ansible_venv}/bin/ansible*; do
[ -f "$b" ] || continue
ln -s %{ansible_venv}/bin/$(basename "$b") %{buildroot}%{_bindir}/$(basename "$b")
done
%check
%{buildroot}%{ansible_venv}/bin/python %{buildroot}%{ansible_venv}/bin/ansible --version
%files
%{ansible_venv}
%{_bindir}/ansible*
%changelog
* Wed Oct 14 2026 筑梦之路
- 基于 Alinux 4 / Python 3.11 构建 ansible-12.3.0 venv RPM
- 修正 venv 脚本 shebang,消除构建路径硬依赖,支持离线安装复用
- Requires 收紧为 python3 >= 3.11
五、构建
bash
# 构建前校验 spec 关键段落只出现一次(防止粘贴导致重复段落的坑)
grep -c '^%prep$' ~/rpmbuild/SPECS/ansible.spec # 输出必须为 1
grep -c '^%description$' ~/rpmbuild/SPECS/ansible.spec # 输出必须为 1
# 构建
rpmbuild -bb ~/rpmbuild/SPECS/ansible.spec
构建产物:
text
~/rpmbuild/RPMS/x86_64/ansible-12.3.0-1.alnx4.x86_64.rpm
六、踩坑记录
| 现象 | 根因 | 解决办法 |
|---|---|---|
Error: nothing provides python(abi) = 3.9 |
EPEL 9 的 ansible 按 Python 3.9 打包,与 Alinux 4 默认 Python 3.11 不兼容 | 放弃 EPEL,改用 venv 封装自建 RPM |
No matching distribution found for ansible |
内网 HTTP pip 镜像不受信任被忽略,索引为空 | ~/.pip/pip.conf 改用 https://mirrors.aliyun.com/pypi/simple/ |
warning: line 64: second Description / second %prep |
spec 编辑时旧文件未清理,内容重复粘贴了两遍 | 先 rm -f 旧 spec 再整体覆盖写入;构建前 grep -c 校验 |
%check 阶段 cannot execute: required file not found |
脚本 shebang 已改成最终安装路径,但打包前该路径尚不存在 | %check 显式调用 buildroot 内的 python 执行,绕过 shebang |
error: Failed dependencies: /root/rpmbuild/BUILD/venv/bin/python3 is needed by ... |
RPM 自动依赖扫描把 venv 脚本中残留构建机 shebang 当成安装前提;旧 spec 只改了 ansible*,漏掉 pip/pip3 等脚本 |
用 grep -rl 全量定位并改写所有受影响脚本的 shebang |
sed -i ... bin/* 误伤系统 python |
venv/bin 内含 python、python3、pip 等符号链接,sed 跟随软链误改构建机系统 Python |
先 grep -rl 精确定位纯文本脚本,再逐文件 sed |
关键点:不要用
rpm -ivh --nodeps绕过依赖检查------如果包内脚本的 shebang 仍是构建机旧路径,即使装上也无法运行。必须把 shebang 全部改写到最终路径,让依赖检查通过是顺理成章的结果。
七、安装与验证
bash
# 1. 检查 RPM 依赖,确认无构建机路径残留
rpm -qpR ansible-12.3.0-1.alnx4.x86_64.rpm
期望输出只包含:
text
python3 >= 3.11
/usr/lib/ansible-venv/bin/python # 包内自持
/usr/bin/python3.11 # 系统提供
不应再出现任何 /root/rpmbuild 字样。
bash
# 2. 安装(dnf 会自动解决 python3 依赖;root 下可省略 sudo)
sudo dnf install ./ansible-12.3.0-1.alnx4.x86_64.rpm
# 3. 验证
ansible --version
期望显示:
text
ansible [core 2.19.5]
python version = 3.11.x
如果构建机本身无法直连外网(只有内网 PyPI 镜像),也可以先在其他联网机器上用 pip download 缓存 wheel,再在 spec 中改为 --no-index --find-links 安装:
bash
# 联网机器上预下载全部依赖
pip download -d wheels ansible==12.3.0
# 将 wheels/ 放入 ~/rpmbuild/SOURCES/,spec 的 %build 改为:
# %{venv_build}/bin/pip install --no-index --find-links=%{_sourcedir}/wheels 'ansible==%{version}'
八、离线复用注意事项
- 目标机系统要求 :
python3 >= 3.11。Alinux 4 / Anolis 23 默认满足;若目标机不是同源系统,venv 中指向/usr/bin/python3.11的软链可能不兼容,需要按目标机环境调整或重建。 - 不要用
--nodeps强制安装 :依赖检查出现/root/rpmbuild路径说明包内脚本仍有构建机残留,应先修 spec 重建。 - License 合规:ansible 与 ansible-core 均为 GPL-3.0-or-later,spec 中已声明;对内网分发需保留对应许可证文本。
- 本方案同样适用于其他"官方源缺失 + Python 版本偏新"的系统:只需调整
Version与Requires,即可把任意纯 Python 工具打成可离线复用的 RPM。
总结
在 Alibaba Cloud Linux 4 上制作 ansible RPM 的关键链路是:确认系统 Python 3.11 基线 → 排除 EPEL 9 的 Python 3.9 绑定包 → 采用"RPM 外壳 + venv 封装"方案 → 用 grep -rl + sed 全量改写 shebang 规避自动依赖扫描误判 → 构建后用 rpm -qpR 确认无构建机路径残留 。最终产出一个可在离线内网环境用 dnf install 一键安装、且不污染系统 Python 的标准 RPM 包。
