Docker和Makefile构建

时间:2019-02-19 08:28:59

标签: docker

我希望使用Dockerfile从源代码构建相当大的代码库。源代码用C ++编写,构建系统用 Makefile 编写。目前,我的Dockerfile如下所示:

FROM ubuntu:16.04

RUN apt-get update && \
    apt-get install -y --no-install-recommends \
        vim g++ make && \
    rm -rf /var/lib/apt/lists/*

COPY src /src # `src` folder contains the source code
WORKDIR /src
RUN make && make all

我对此Dockerfile的主要关注是-假设稍后我修改大型代码库的一小部分并重新执行docker build命令时,将会发生以下哪些情况? / p>

  1. Docker再次进行复制,并找出make的构建依赖性。
  2. Docker不会执行任何操作,因为Dockerfile尚未更改。
  3. Docker从一开始就构建了整个代码库。

如果第二次或第三次发生,是否有比将make命令放入Dockerfile内更好的选择?我应该将其作为docker run的一部分执行并将源代码目录安装到Docker容器上吗?

谢谢。

3 个答案:

答案 0 :(得分:1)

  

Docker再次复制并找出make的构建依赖项

。它将把您的源复制到容器中的指定目的地

  

Docker不会执行任何操作,因为Dockerfile尚未更改。

。即使您不更改Dockerfile,Docker也会重新构建您的代码。这是因为您更改了代码库。如果您不更改代码库,尽管它可能什么也不做,因为它只能检索所构建的最后一层。 (请注意,命令的顺序可能会更改此处的缓存逻辑)

  

Docker从一开始就构建整个代码库。

默认为是。如果您没有将预编译的工件复制到您的容器中(您不应该这样做),那么它将从头开始重新构建代码。

  

有没有比将make命令放入Dockerfile更好的选择了?

在此处将make命令放入Dockerfile 是更好的选择。人们使用Docker的最重要原因之一(如果不是最重要的话)是拥有可预测的版本

注意

一种可能的“更好的方式” 是使用multi-stage builds来分隔您的“生成器容器” 和您的“保存二进制文件的容器” 。这也为您提供了较小的“最终” 图像,因为您可以从alpinescratch构建它们。这样,您的“最终” 容器将不必包含不必要的库/软件。

答案 1 :(得分:0)

对此有两个可能的答案。

如果您有一个包含.dockerignore的{​​{1}}文件,或者您设置了单独的构建树,那么当您到达*.o行时,该图像将包含所有源文件,没有目标文件,构建将完全从头开始运行。这是“最好的”答案–您应该获得非常一致的构建输出–但实际上可能需要一段时间。

如果您没有此功能,那么您在本地构建的任何内容都将被复制到映像中,包括其时间戳,您将获得增量生成。但是,这意味着从相同的部分源代码树构建相同应用程序的不同人员将获得不同的结果。在基于Autoconf的项目中,可以根据特定开发人员的主机上是否安装了某些库来控制整个应用程序功能。

如果您已经有一个主要基于Make的构建系统,那么我可能会坚持使用它,并且更喜欢“在Make中进行所有操作”模型而不是“在Docker中进行所有操作”模型。在GNU Make中,您可以编写如下片段:

RUN make

这还为您提供了多阶段构建的实际效果(您已经预编译了应用程序,因此您无需在Docker管道中的任何地方使用工具链。就像现在DOCKER_TAG := $(shell date +%Y%m%d) .PHONY: docker docker: $(MAKE) install DESTDIR=docker/dist cp Dockerfile docker docker build -t me/myapp:$(DOCKER_TAG) docker ,您将sudo make install生成Docker映像。

答案 2 :(得分:0)

非常感谢所有答案。

因此,我自己做了一些实验。以下是我得出的结论

  • @molamk回答, Docker将复制文件并从头开始构建。。原因是因为对于COPY命令,Docker使用校验和机制来验证文件是否已更改。因此,Docker能够准确地确定是否需要重新复制,并使make层之后的所有缓存层(包括COPY构建)失效。
  • 在我要修改大型代码库的部分(包括Dockerfile内部的构建)的情况下,这是一个糟糕的主意,因为这意味着每次我都需要等待几个小时才能使更改生效。因此,我只将构建先决条件包括在Dockerfile中,并将源目录安装到通过运行先决条件映像获得的容器中。