Alibaba Cloud Linux 4 制作 Ansible RPM包实践(离线可复用)——筑梦之路

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 中的 ansible RPM(如 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}'

八、离线复用注意事项

  1. 目标机系统要求 :python3 >= 3.11。Alinux 4 / Anolis 23 默认满足;若目标机不是同源系统,venv 中指向 /usr/bin/python3.11 的软链可能不兼容,需要按目标机环境调整或重建。
  2. 不要用 --nodeps 强制安装 :依赖检查出现 /root/rpmbuild 路径说明包内脚本仍有构建机残留,应先修 spec 重建。
  3. License 合规:ansible 与 ansible-core 均为 GPL-3.0-or-later,spec 中已声明;对内网分发需保留对应许可证文本。
  4. 本方案同样适用于其他"官方源缺失 + 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 包。

相关推荐
承渊政道1 小时前
Linux网络学习【应用层自定义协议与序列化实战:从手写序列化与反序列化到深入理解进程间关系与守护进程】
linux·网络·学习·ubuntu·json·序列化与反序列化
无垠的广袤1 小时前
【ED-CLAWBOX】智能家居枢纽
linux·物联网·docker·智能家居·树莓派·aiot·home assistant
玩AI的奶茶1 小时前
什么情况适合租算力?一张场景对照表,加三个自测问题
大数据·linux·服务器·数据库·人工智能·python
IT利刃出鞘1 小时前
Linux权限--adduser和useradd的区别
linux·运维·服务器
天意__1 小时前
Android手机上部署Linux服务器 在Termux里安装Ubuntu
android·linux·服务器
Ruiery1 小时前
Linux 6.6内核内存管理深度解析(五):page cache(页缓存)— 读缓存在内存、写延迟回写
linux·运维·服务器·缓存
研发小能1 小时前
金融行业 DevOps 流水线解决方案:从环境准备到发布门禁的全链路提效
运维·金融·devops
海宇大数据1 小时前
零信任架构实战:基于海宇企业综合风险报告构建自动化供应链保理对公尽调网关
运维·人工智能·架构·自动化
星恒随风1 小时前
Linux进程信号(一):从Ctrl+C到kill、raise、alarm,深入理解信号的概念与产生原理
linux·c语言·笔记·学习·状态模式