docker debian
构建Debian软件包并不总是很有趣。 如果您曾经尝试将某些软件转换为.deb软件包,则可能是由于大量可用的构建工具和文件格式而感到不知所措,或者是为了满足软件包的所有依赖关系而弄乱了系统。 有很多事情可以而且最初会出错。
幸运的是,自动化和虚拟化的正确组合可以带来很大的不同。 在本文中,我将告诉您我在Jimdo开发的Debian软件包构建系统背后的故事,该系统解决了我们多年来面临的许多难题 。
包装制造的黑暗时代
当我2013年开始在Jimdo工作时,我们在构建Debian软件包时遇到了自己的问题。 从第一天开始,我们就依靠Debian操作系统为服务器供电。 Debian本身已经带有成千上万的可安装软件包。 但是,如果捆绑的软件已过时,我们仍然需要自己重新编译较新的版本。 此外,我们也希望将自己的工具作为.deb文件分发。 因此,能够构建和维护Debian软件包对我们一直很重要。
为了那时可以创建软件包,工程师必须登录一个专用的构建服务器,恰当地命名为buildhost02,然后以特殊的“ buildmaster”用户身份运行几个Shell命令。 这个过程有几个缺点:通常很难弄清楚是谁构建了特定的软件包,或者为什么要首先构建它。 最糟糕的是,有时我们不知道如何创建软件包。 除了松散的shell脚本集合外,没有统一的方法来创建软件包,更不用说它们来源的默认位置了。
问题列表清楚地表明,此构建系统不会永远持续下去。 我们的构建服务器buildhost02很难理解和修改,并且设置具有相同功能的另一台服务器非常麻烦(尽管其名称以“ 02”结尾,如果出现问题,则没有其他服务器)。 此外,由于构建通常涉及安装多个依赖项,因此随着时间的流逝,主机越来越受到污染。 综上所述,buildhost02是所谓的独特雪花 。
包装2.0
2014年5月,我有机会开始致力于我们所谓的“包装2.0”里程碑。 里程碑的目标是根据我们过去的经验开发一个新的更好的构建系统。 后来,该项目被称为buildbox 。
使用buildbox时,软件包构建应该是:
- 自动化的。 工程师应该能够通过在本地计算机上运行单个命令来构建用于分发Y的软件包X。
- 记录下来。 很明显,如何以及为什么要构建软件包以及由谁来维护它。
- 可重复的。 应该有可能复制软件包的每个内部版本。
- 简单。 工程师,或者实际上任何人,都应该能够建造这座建筑。
为了完成里程碑,我们同意,我不仅必须使用buildbox重建所有100多个自定义Debian软件包(此过程需要大量的逆向工程),而且我还必须重新部署每个软件包以确保所有内容仍然如预期般运作。
输入buildtasks gem
在打包软件方面,没有一种千篇一律的工具可以支持每种编程语言。
在Jimdo,我们使用多种语言,最主要的是PHP,Python,Ruby和Go。 每种语言都有自己的包装标准和工具(这很可悲)。 结果,在很多地方都可以找到构建说明,例如Makefile, debian/rules
文件,shell脚本等,它们通常取决于事先安装的其他软件。
这种多样性代表了我必须尽早解决的挑战。 我知道必须支持不同的构建机制将需要某种形式的抽象。
这就是buildtasks库的形式。 Buildtasks是一个Rubygem,它允许您通过一组Rake任务来构建Debian软件包。 目前,它支持两种构建方式:
前者是构建已经带有debian/
目录的软件包的理想选择(就像所有Debian上游软件包一样)。 后者对于从各种尚未“去Debian化”的代码轻松创建包很有用。 在Jimdo,我们大量使用这两种方法。
buildtasks gem提供了一个方便的Ruby DSL,以抽象出包构建中涉及的实际步骤。 这是一个示例Rakefile
利用了gem对git-buildpackage的支持:
# Rakefile
require "buildtasks"
BuildTasks::GitBuildpackage.define do
name "periodicnoise"
version "debian/1.1"
source "https://github.com/Jimdo/periodicnoise"
end
该Ruby代码将自动生成一些Rake任务,以为给定项目periodicnoise创建一个Debian软件包。 您可以通过以下方式列出任务:
$ rake -T
rake build # Build packages
rake clean # Remove any temporary products
rake clobber # Remove any generated file
rake clone # Clone Git repository and checkout version
rake deps # Install build dependencies
rake patch # Apply any patches
rake publish # Publish built packages
完成这些任务后,下面是触发程序包构建的方法:
$ rake build publish PUBLISH_DIR=/some/path
在后台,buildtasks库将从GitHub克隆定义的Git存储库,签出指定的版本(debian / 1.1),安装debian/control
列出的所有构建依赖项,最后调用git-buildpackage来构建软件包。 然后,将包复制到PUBLISH_DIR
环境变量指定的目录中。 所有这些复杂性对用户都是隐藏的,用户的工作是为Rakefile
提供适当的属性。
但是buildtasks不仅抽象出了构建步骤,而且还提供了一个通用接口。 不管您选择哪种构建机制(git-buildpackage或fpm-cookery或将来添加的其他工具),生成的Rake任务将始终包括两个易于理解且对人和机器自动化的操作: build
和publish
。 实际上,您不一定需要构建任务来满足此接口。 您也可以提供自己的具有相同名称的Rake任务。
Buildtasks是开源的。 您可以通过gem install buildtasks
安装它,并阅读GitHub上的完整文档。
Docker的隔离构建
尽管buildtasks提供了创建Debian软件包的逻辑,但它只是buildbox的一个组成部分,尽管很重要。 另一个至关重要的部分是用于建筑的环境。 最重要的是,需要隔离此环境-最少安装目标OS,并尽可能减少预装的软件包。 (特定于程序包的构建依赖项应在实际构建过程中安装,而不是在此之前安装。只有这样,您才会发现损坏或丢失的依赖项。)
由于这些原因,将构建任务与某种形式的服务器虚拟化配对是一个好主意。 虚拟机是一次性的,通常可以在数分钟内完成配置。 更重要的是,它们提供了一个干净的隔离环境,非常适合构建包装。
当我实现buildbox的第一个版本时,我决定将Vagrant与VirtualBox一起使用。 随着时间的流逝,很明显,VM并不是最适合我们的需求。
当我最终决定尝试Docker时,我意识到了这一点。 无需等待几分钟就可以使新的VM投入使用(我们使用Puppet来配置基本的VirtualBox VM),可以立即通知Docker容器。 甚至更好:对于每个构建,都保证环境是原始的。 我们不再需要采用丑陋的解决方法,例如重用现有的VM并在内部版本之间共享依赖关系,以加快整个过程。 Docker是缺少的一环,它使我们能够以可预测和可复制的方式快速构建软件包。
演示:使用Docker Compose
我们配备了buildtasks gem,并且我们知道Docker是适合当前任务的正确技术。 现在,我们要做的就是将两者结合起来。 接下来的演示向您展示了如何使用Docker Compose实现这一目标。 Compose是用于描述,构建和运行Docker应用程序的有用工具。 它专为管理多容器应用程序而设计,但是与单个容器(如我们将在演示中使用的容器)一样,可以很好地工作。
首先,我们需要编写一个Dockerfile
定义用于包构建的环境。 请记住,我们努力将预装软件减少到最少。 因此,我们将仅将buildtasks gem与git-buildpackage和fpm-cookery以及其他一些必需的依赖项一起安装。 为了这个演示的目的,我们的Docker映像将基于Docker Hub上官方“ debian”存储库中的debian:jessie
映像。 通常,您应该使用要为其构建软件包的操作系统的映像。
这是最终的Dockerfile
:
# Dockerfile
FROM debian:jessie
ENV DEBIAN_FRONTEND noninteractive
RUN apt-get update && apt-get install -y \
build-essential \
curl \
devscripts \
equivs \
git-buildpackage \
git \
lsb-release \
make \
openssh-client \
pristine-tar \
rake \
rsync \
ruby \
ruby-dev \
rubygems \
wget
RUN echo "gem: --no-ri --no-rdoc" >/etc/gemrc
RUN gem install fpm -v 1.4.0
RUN gem install fpm-cookery -v 0.29.0
RUN gem install buildtasks -v 0.0.1
RUN gem install bundler -v 1.10.0
下一步,我们创建一个名为docker-compose.yml
的文件,该文件告诉Compose该做什么。 该文件如下所示:
# docker-compose.yml
demo:
build: .
command: rake build publish PUBLISH_DIR=/pkg
volumes:
- .:/data
- pkg:/pkg
working_dir: /data
最后但并非最不重要的一点是,我们需要一个带有构建指令的Rakefile
。 为了简单起见,我们将使用我之前向您展示的一种用于周期噪声的方法:
# Rakefile
require "buildtasks"
BuildTasks::GitBuildpackage.define do
name "periodicnoise"
version "debian/1.1"
source "https://github.com/Jimdo/periodicnoise"
end
有了这三个文件,我们最终可以指示Compose构建并运行我们的演示容器应用程序。 这个过程实质上可以归结为创建Docker映像,然后根据该映像在容器内执行rake build publish
。 通过使用两个数据量,我们确保当前Rakefile
在容器内(位于/data/Rakefile
) /data/Rakefile
,并且所有构建的软件包最终位于主机系统上的pkg/
。
这是Compose的输出:
$ docker-compose build
Building demo...
...
Successfully built a5d21c6f8085
$ docker-compose run demo
git clone https://github.com/Jimdo/periodicnoise git-debian-1.1
...
cd git-debian-1.1
git checkout -qf debian/1.1
...
DEBIAN_FRONTEND=noninteractive mk-build-deps -i -r -t 'apt-get -y' debian/control
...
git-buildpackage --git-ignore-branch --git-ignore-new --git-builder=debuild -i.git -I.git -uc -us -b
...
dpkg-deb: building package `periodicnoise' in`../periodicnoise_1.1_amd64.deb'.
...
mkdir -p /pkg
cp periodicnoise_1.1_amd64.deb /pkg
之后,我们可以验证该软件包是否已成功构建并保存到我们的本地pkg/
文件夹中:
$ ls -1 pkg/
periodicnoise_1.1_amd64.deb
结论
在本文中,我向您展示了buildbox的两个主要组成部分-Jimdo的Debian软件包构建系统-以及如何将它们一起使用:有一个buildtasks gem,它可以自动化并抽象化构建步骤,还有Docker ,它提供了一个隔离的环境立即可用于构建。
Buildbox本身还不是开源的,但实际上它是一个Git存储库,其中包含Dockerfile,Rakefile和Makefile的集合,以及将所有内容粘合在一起的shell脚本。 使用buildbox时,工程师只需一个命令即可为Debian发行版Y生成项目X的软件包,而仅需一条命令即可将结果推送到我们的内部Debian软件包存储库。
我希望阅读完本文后,您也能够开发出使打包构建更有趣的东西。 该技术已经存在-准备好好使用。
翻译自: https://www.javacodegeeks.com/2015/08/using-docker-to-build-debian-packages.html
docker debian