夏有乔木 發表於 2015-6-30 17:11:32

创建RPM包的同时构建Docker镜像的方法

<p>RPM(Red Hat Package Manager)是用于 Linux 分发版的最常见的软件包管理器。因为它允许分发已编译的软件,所以用户只用一个命令就可以安装软件。而RPM包的构建相当繁琐,并且对环境的要求比较高, 本文作者介绍了如何借助Docker来构建可以适用多个平台的RPM包。</p>
<p>在一个内部项目中,我一直在思考如何通过非CI工具/流程生成RPM包,我想手动生成RPM包,这样我可以测试它们是否能正常安装,并用于正常的<a target="_blank" href="http://97741.blog.51cto.com/87741/102515">冒烟测试</a>(译者注:冒烟测试就是在每日构建完成后,对系统的基本功能进行简单的测试。这种测试强调功能的覆盖率,而不对功能的正确性进行验证)。</p>
<p>在我们的CI流程中,Docker算是个全能手,所以我也在想能否将Docker镜像和RPM结合起来。理想的情况下,让RPM与Docker集成, 这样,创建RPM包的过程其实就是在构建一个Docker镜像。基本上,RPM包的%prep部分的构建可以在一个特殊的Docker镜像中快速完成,然 后将生成的RPM包返回给主机。</p>
<p>这种方式的的优点在于,你的RPM包是在一个相对封闭且可再生的环境中构建的,所以你可以快速的为CentOS、Fedora、RHEL等其它系统构建RPM包。</p>
<p>我相信还有其它的一些变通方法也可以完成这样的工作,比如chroot之类的。但如果在RPM中内建这种打包机制(通过chroot/Docker或者别的容器技术抽象而来的系统来完成打包工作)的话,我想会更好。</p>
<p>由于我的项目还没有完成,所以我只是对我的想法进行了验证:简单构建一个包含依赖的镜像。</p>
<p>这是一个使用<a target="_blank" href="http://docs.openstack.org/developer/pbr/">PBR</a>生成版本 的Python项目。 首先我在build目录中生成一个tarball,然后得到生成的版本号,紧接着修改spec文件中的版本号,然后开始用新的tar包和spec文件构建 镜像。最后运行镜像,并挂载卷(Volume)到本地目录。当运行容器中的start.sh脚本之后,镜像就运行起来了。</p>
<p>start.sh相当简单。 它构建好RPM包后,以root身份把它拷贝到卷目录下, 还可以从主机上将它拷贝到output目录。我没有将它拷贝或者说更新到类似swift之类的对象存储系统,因为我还要在CI中使用它,所以就使用本地文件拷贝了。</p>
<p>在SPECS/project.spec以及 SOURCES/* 是标准RPM包需要的spec文件,源文件和patch文件。需要做的唯一一件事是定义%define_version宏,并在spec文件中使用它。下面是我的一些脚本。</p>
<p>主脚本build.sh。 可以从CI中运行。</p>
<p><br><div class="msgheader"><div class="right"><span style="CURSOR: pointer" class="copybut"><u>复制代码</u></span></div>代码如下:</div><div class="msgborder" id="phpcode9">#!/bin/bash<br />set -exf<br />PROJECT=myproject&lt;/p&gt;
&lt;p&gt;CURDIR=$(dirname $(readlink -f $0))<br />TOPDIR=$(git rev-parse --show-topklevel 2&gt;/dev/null)&lt;/p&gt;
&lt;p&gt;rm -rf ${CURDIR}/.build/rpm<br />mkdir -p ${CURDIR}/.build/rpm/{BUILD,SRPMS,SPECS,RPMS/noarch}<br />cp -r ${CURDIR}/SOURCES ${CURDIR}/.build/rpm&lt;/p&gt;
&lt;p&gt;pushd ${TOPDIR} &gt;/dev/null<br />python setup.py sdist --dist-dir ${CURDIR}/.build/rpm/SOURCES/<br />SALADIER_VERSION=$(sed -n '/^Version/ { s/.* //; p}' ${PROJECT}.egg-info/PKG-INFO)<br />popd &gt;/dev/null&lt;/p&gt;
&lt;p&gt;sed -e "s/%define _version.*/%define _version ${SALADIER_VERSION}/" ${CURDIR}/SPECS/${MYROJECT}.spec &gt; \<br />      ${CURDIR}/.build/rpm/SPECS/${MYPROJECT}.spec&lt;/p&gt;
&lt;p&gt;docker build -t chmouel/buildrpm ${CURDIR}<br />docker run -v $CURDIR/.build:/data -it chmouel/buildrpm&lt;/p&gt;
&lt;p&gt;if [[ -n ${ARTIFACT_DIR} ]];then<br />    rm -rf ${ARTIFACT_DIR}/rpm<br />    cp -a ${CURDIR}/.build/output ${ARTIFACT_DIR}/rpm<br />fi</div></p>
<p>DockerFile,为Docker 缓存做了一些优化:</p>
<p><br><div class="msgheader"><div class="right"><span style="CURSOR: pointer" class="copybut"><u>复制代码</u></span></div>代码如下:</div><div class="msgborder" id="phpcode10">FROM fedora:21<br />MAINTAINER Chmouel Boudjnah &lt;chmouel@enovance.com&gt;&lt;/p&gt;
&lt;p&gt;RUN yum -y groupinstall 'Development Tools'<br />RUN yum -y install fedora-packager<br />RUN yum -y install yum-utils&lt;/p&gt;
&lt;p&gt;RUN yum -y install sudo<br />RUN sed -i.bak -n -e '/^Defaults.*requiretty/ { s/^/# /;};/^%wheel.*ALL$/ { s/^/# / ;} ;/^#.*wheel.*NOPASSWD/ { s/^#[ ]*//;};p' /etc/sudoers&lt;/p&gt;
&lt;p&gt;RUN yum install -y https://rdo.fedorapeople.org/rdo-release.rpm&lt;/p&gt;
&lt;p&gt;# This is an optimisation for caching, since using the auto generated one will<br /># make docker always run the builddep steps since new file<br />ADD SPECS/project.spec /tmp/<br />RUN yum-builddep -y /tmp/project.spec&lt;/p&gt;
&lt;p&gt;ADD bin/start.sh /start.sh&lt;/p&gt;
&lt;p&gt;RUN useradd -s /bin/bash -G adm,wheel,systemd-journal -m rpm&lt;/p&gt;
&lt;p&gt;WORKDIR /home/rpm<br />CMD /start.sh&lt;/p&gt;
&lt;p&gt;ADD .build/rpm/ /home/rpm/rpmbuild/<br />RUN chown -R rpm: /home/rpm&lt;/p&gt;
&lt;p&gt;USER rpm</div></p>
<p>以及从容器中运行的start.sh脚本:</p>
<p><br><div class="msgheader"><div class="right"><span style="CURSOR: pointer" class="copybut"><u>复制代码</u></span></div>代码如下:</div><div class="msgborder" id="phpcode11">#!/bin/bash<br /># script run inside the container<br />rpmbuild -ba rpmbuild/SPECS/project.spec || exit 1&lt;/p&gt;
&lt;p&gt;[[ -d /data ]] || exit 0&lt;/p&gt;
&lt;p&gt;sudo rm -rf /data/output<br />sudo cp -a rpmbuild/RPMS/noarch /data/output</div></p>
<p>脚本可能无法直接在你的环境中使用,但至少能让你了解这个idea。<br /></p>
頁: [1]
查看完整版本: 创建RPM包的同时构建Docker镜像的方法