Habr上已经有关于如何配置docker- container进行项目编译的材料。 例如, 使用Docker构建和运行C ++项目 。 在本文中,与前一篇文章一样,将讨论构建项目的问题,但是在这里,我想超越本教程,更深入地考虑在此类任务中使用容器以及使用docker构建构建基础结构的问题。
关于Docker的一些知识
为了使讨论更加清晰,有必要提供一些docker组件的描述。
图片
Docker映像是一个只读模板,其中包含创建容器的说明。 为了构建映像,您需要创建一个Dockerfile ,它描述了组装的所有步骤。 每个这样的步骤都会在图像内部创建一个单独的层。 每个后续层都叠加在所有先前层之上,并且仅包含需要对先前层进行的更改。
例如,对于Dockerfile :
FROM ubuntu:18.04 ADD app.sh /app ENTRYPOINT /bin/bash /app/app.sh
泊坞窗映像将具有以下结构:

图像内的图层将被缓存,并且如果未检测到更改,则可以重复使用。 如果更改(添加/删除)了图层,则随后的所有图层都是从头开始创建的。 要更改容器映像(并因此更改启动过程的环境),只需修复Dockerfile并开始构建映像即可。
货柜
泊坞窗容器是image的启动实例。 可以创建,启动,停止,删除等操作。默认情况下,容器彼此隔离,并且与主机系统隔离。 在开始时,容器启动一个命令,可以在ENTRYPOINT或CMD中指定该命令,并在完成时停止。 当CMD和ENTRYPOINT同时存在时,这是可以接受的情况,因为它们在文档中 有所 描述 。
创建每个容器时,将在所有现有容器之上添加一个新层。 它在当前容器中可写,并且与容器一起销毁。 在容器的操作过程中,所有写操作,创建新文件的所有操作均应用于此层, 图像始终保持不变。 因此,创建的容器的层结构将如下所示:

使用docker run
,每次都会创建一个新容器,并带有其自己的写入层。 在构建任务中,这意味着每次启动时,都会创建一个新的干净环境,该环境与以前的执行无关。 可以通过运行命令docker container ls -a
来查看已创建容器的列表。
我们将项目收集在容器中
为了清楚起见,我们简要描述了在容器中构建应用程序的过程;此过程在第1条和第2 条中进行了更详细的描述。
在docker中构建应用程序的示意性步骤可以表示如下:

让我们分析显示的步骤:
- 我们使用Dockerfile ,它描述了环境,用于组装和复制结果的命令,并基于此文件创建了容器的映像。
- 我们使用生成的映像通过
docker run
创建并启动容器。 我们安装源文件夹和将汇编结果复制到容器的文件夹。 - 容器完成后,程序集工件将放置在安装目录中。
本文提供了一个示例。
由于此处使用了docker run
,因此每次启动都会创建一个单独的容器,该容器具有自己的写入层 ,因此以前程序集的临时文件不会进入当前容器。 切记清洁停止的容器。
挂载源目录使调试程序集更加容易。 但是它存在风险-您可以从尚未通过质量控制的代码中收集发布,或者根本不将其添加到版本控制系统中。 为了避免这种情况,您可以在每次构建时在容器内克隆git存储库,例如, 在文件中 :
FROM ubuntu:bionic RUN apt-get update \ && apt-get install -y apt-utils RUN apt-get update \ && apt-get install -y make gcc g++ qt5-default git RUN mkdir -p /app/src WORKDIR /app/build # ENTRYPOINT git -C /app/src clone https://github.com/sqglobe/SimpleQtProject.git \ && qmake /app/src/SimpleQtProject/SimpleQtProject.pro \ && make \ && cp SimpleQtProject /app/res/SimpleQtProject-ubuntu-bionic
在这里,由于缓存,克隆是在ENTRYPOINT
完成的,而不是在RUN
语句中完成的。 ENTRYPOINT
总是在容器启动时执行,并且RUN
命令的结果可以从缓存中获取 。
建立基础设施
要为不同的操作系统或Linux 发行版构建项目,可以使用服务器的特定配置(构建机器,具有版本控制系统的服务器等)。 实际上,我必须处理以下基础结构:

用户在这里访问Web服务器,通过该Web服务器在使用Ubuntu和Red Hat的计算机上构建项目。 接下来,在每台机器上,将git存储库与项目一起克隆到一个临时目录中,然后程序集开始。 用户可以从开始整个过程的同一页面下载结果文件。
这样的程序集是可重复的,因为开发人员使用相同的环境。
缺点-必须维护整个基础架构,管理多台服务器,消除脚本和Web应用程序中的错误等。
使用Docker简化
支持上述基础设施需要一定的成本,无论是金钱还是人力。 如果您的团队正在一家小型创业公司上工作,或者您是唯一的开发人员,则可以使用Docker容器来实现构建基础架构。
考虑一个使用qmake - SimpleQtProject构建的普通Qt项目。 指定项目的docker文件夹包含许多文件:
这些文件实现了在容器内部克隆源代码的想法。
整个程序集使用Makefile启动。 它很短,包含足够的注释。 它的基础是图像的创建和容器的启动:
%: %.docker docker build -t simple-qt-$(strip $(subst .docker,, $< )) --file $< . docker run --mount type=bind,source=$(RELEASE_DIR),target=/app/res simple-qt-$(strip $(subst .docker,, $< ))
在组装的此阶段,将创建容器的映像,其名称由前缀simple-qt-和系统名称组成(对于centos 7 ,它将是simple-qt-centos7 )。 作为Dockerfile ,使用具有.docker权限的相应文件。 接下来,根据创建的映像启动容器,并在其上安装一个文件夹以复制组件工件。
在docker目录中运行make
后, docker / releases文件夹将包含多个平台的构建结果。
因此,我们用于构建SimpleQtProject的基础结构将如下所示:

这种配置的优点:
- 地方性 。 开发人员可以在其本地计算机上为多个平台收集一个项目,从而无需包含服务器群,通过网络在服务器之间配置复制工件,发送和处理网络命令。
- 隔离环境 。 容器为构建特定应用程序提供了完全隔离的环境。 可以在同一台机器上构建具有不兼容环境的项目(例如,那些需要同一库的不同版本的项目)。
- 版本控制 通过将Dockerfile放置在git仓库中,您可以通过新版本的发布来跟踪构建环境中的更改,回滚到构建环境的先前版本等。
- 流动性 。 如有必要,可以在另一台计算机上毫无问题地部署此基础结构。 创建容器映像的技术使您可以非常轻松地更改映像本身-只需更新Dockerfile并开始构建映像即可。
- 自我记录 。 本质上, Dockerfile包含用于部署程序集环境的步骤。 因此,如有必要,部署这样的环境,但是已经在常规系统中,则可以使用其中的命令。
- 轻便 。 容器在组件开始的那一刻开始,并在完成时自动停止。 这不会浪费CPU时间和RAM。
但是,有一个很大的缺点-项目的组装将需要容器图像的组装。 首次启动时可能会花费很长时间。 但是对于重复的文件,尤其是在Dockerfile不变的情况下 ,使用高速缓存收集映像的速度要快很多倍。
还需要记住清洁停止的容器。
结论
总而言之,我想指出docker不是唯一的容器化技术。 但是有一些功能使它可以很好地区别于同一LXC的组装任务:
- 您可以使用文本Dockerfile创建容器。 这是一个语法简单的文件,您可以将其添加到项目存储库中(就像我经常做的那样),并且随时可以使用。
- 每次通过使用
docker run
启动docker容器docker run
我们都会得到一个干净的环境,就像我们第一次做所有事情一样。 程序集之间的临时文件不会保存。 - 该容器不会启动整个操作系统,而只会启动必要的组装过程。