RPM(Red Hat Package Manager)是 Linux 系统中最常见的软件包管理器之一,其优势在于用户只需一条命令即可安装预编译的软件。然而,自行构建 RPM 包却并非易事——环境依赖复杂、步骤繁琐,容易出错。本文介绍一种巧妙的思路:借助 Docker 构建可跨平台使用的 RPM 包
RPM包和Docker镜像同时构建方法
时间:2026-07-25
浏览:561
文章目录
RPM(Red Hat Package Manager)是 Linux 系统中最常见的软件包管理器之一,其优势在于用户只需一条命令即可安装预编译的软件。然而,自行构建 RPM 包却并非易事——环境依赖复杂、步骤繁琐,容易出错。本文介绍一种巧妙的思路:借助 Docker 构建可跨平台使用的 RPM 包,使打包过程变得干净且可重复。
手动构建 RPM 包的设想
一直以来,有一个想法:能否不依赖 CI 工具,手动生成 RPM 包?这样可以在本地先测试安装是否正常,同时跑通冒烟测试。而在现有 CI 流程中,Docker 几乎是万能的工具,那么是否可以将 Docker 镜像与 RPM 打包结合起来呢?理想状态下,构建 RPM 包的过程本质就是构建一个 Docker 镜像:RPM 包的 %prep 部分在一个特制的 Docker 镜像中快速完成,最后将生成的 RPM 包原样返回给宿主机。这样一来,打包环境封闭且可重复,为 CentOS、Fedora、RHEL 甚至其他系统构建 RPM 包都变得非常简单。
变通方法对比
当然,变通方法并非没有,例如 chroot 等。但如果能在 RPM 内部直接内建这种机制(通过 chroot、Docker 或其他容器技术抽象出的系统完成打包),无疑是更优雅的方案。由于项目尚未完全落地,此处先验证一个核心想法:简单构建一个包含依赖的镜像。
实现流程概述
这是一个使用 PBR 生成版本号的 Python 项目。大致流程如下:先在 build 目录下生成一个 tarball,获取版本号,然后修改 spec 文件中的版本号,再使用新的 tar 包和 spec 文件构建镜像。最后运行容器,挂载卷到本地目录,等容器内的 start.sh 执行完毕,RPM 包即生成。
容器内脚本说明
start.sh 的逻辑非常直接:构建好 RPM 后,以 root 身份将其拷贝到卷目录,宿主机即可从 output 目录下获取文件。此处未使用对象存储等工具,因为在 CI 流程中本地拷贝已经足够。
SPECS/project.spec 和 SOURCES/* 是标准 RPM 包所需的 spec 文件、源文件和补丁文件。唯一需要注意的是定义 %define_version 宏,并在 spec 文件中引用。下面提供几个关键脚本,虽然不能直接套用,但足以展示该思路的精髓。
主脚本 build.sh
#!/bin/bash
set -exf
PROJECT=myproject
CURDIR=$(dirname $(readlink -f $0))
TOPDIR=$(git rev-parse --show-topklevel 2>/dev/null)
rm -rf ${CURDIR}/.build/rpm
mkdir -p ${CURDIR}/.build/rpm/{BUILD,SRPMS,SPECS,RPMS/noarch}
cp -r ${CURDIR}/SOURCES ${CURDIR}/.build/rpm
pushd ${TOPDIR} >/dev/null
python setup.py sdist --dist-dir ${CURDIR}/.build/rpm/SOURCES/
SALADIER_VERSION=$(sed -n '/^Version/ { s/.* //; p}' ${PROJECT}.egg-info/PKG-INFO)
popd >/dev/null
sed -e "s/%define _version.*/%define _version ${SALADIER_VERSION}/" ${CURDIR}/SPECS/${MYROJECT}.spec > \
${CURDIR}/.build/rpm/SPECS/${MYPROJECT}.spec
docker build -t chmouel/buildrpm ${CURDIR}
docker run -v $CURDIR/.build:/data -it chmouel/buildrpm
if [[ -n ${ARTIFACT_DIR} ]];then
rm -rf ${ARTIFACT_DIR}/rpm
cp -a ${CURDIR}/.build/output ${ARTIFACT_DIR}/rpm
fi
Dockerfile
FROM fedora:21
MAINTAINER Chmouel Boudjnah
RUN yum -y groupinstall 'Development Tools'
RUN yum -y install fedora-packager
RUN yum -y install yum-utils
RUN yum -y install sudo
RUN sed -i.bak -n -e '/^Defaults.*requiretty/ { s/^/# /;};/^%wheel.*ALL$/ { s/^/# / ;} ;/^#.*wheel.*NOPASSWD/ { s/^#[ ]*//;};p' /etc/sudoers
RUN yum install -y https://rdo.fedorapeople.org/rdo-release.rpm
# 利用缓存优化:把spec文件提前放进去,避免每次构建都重跑builddep
ADD SPECS/project.spec /tmp/
RUN yum-builddep -y /tmp/project.spec
ADD bin/start.sh /start.sh
RUN useradd -s /bin/bash -G adm,wheel,systemd-journal -m rpm
WORKDIR /home/rpm
CMD /start.sh
ADD .build/rpm/ /home/rpm/rpmbuild/
RUN chown -R rpm: /home/rpm
USER rpm
容器内执行的 start.sh
#!/bin/bash
# script run inside the container
rpmbuild -ba rpmbuild/SPECS/project.spec || exit 1
[[ -d /data ]] || exit 0
sudo rm -rf /data/output
sudo cp -a rpmbuild/RPMS/noarch /data/output
上述脚本可能无法直接在你的环境中运行,但思路已经明确。使用 Docker 将 RPM 打包环境隔离起来,既干净又易于移植,值得尝试。
实用工具推荐
绿化、压缩、噪点和虚拟水印,自由调节做旧程度。
选择画质和输出格式,预览压缩前后的大小。