我希望使用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>
make
的构建依赖性。Dockerfile
尚未更改。如果第二次或第三次发生,是否有比将make
命令放入Dockerfile
内更好的选择?我应该将其作为docker run
的一部分执行并将源代码目录安装到Docker容器上吗?
谢谢。
答案 0 :(得分:1)
Docker再次复制并找出make的构建依赖项
是。它将把您的源复制到容器中的指定目的地
Docker不会执行任何操作,因为Dockerfile尚未更改。
否。即使您不更改Dockerfile
,Docker也会重新构建您的代码。这是因为您更改了代码库。如果您不更改代码库,尽管它可能什么也不做,因为它只能检索所构建的最后一层。 (请注意,命令的顺序可能会更改此处的缓存逻辑)
Docker从一开始就构建整个代码库。
默认为是。如果您没有将预编译的工件复制到您的容器中(您不应该这样做),那么它将从头开始重新构建代码。
有没有比将make命令放入Dockerfile更好的选择了?
在此处将make
命令放入Dockerfile
是更好的选择。人们使用Docker的最重要原因之一(如果不是最重要的话)是拥有可预测的版本
一种可能的“更好的方式” 是使用multi-stage builds来分隔您的“生成器容器” 和您的“保存二进制文件的容器” 。这也为您提供了较小的“最终” 图像,因为您可以从alpine或scratch构建它们。这样,您的“最终” 容器将不必包含不必要的库/软件。
答案 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)
非常感谢所有答案。
因此,我自己做了一些实验。以下是我得出的结论
COPY
命令,Docker使用校验和机制来验证文件是否已更改。因此,Docker能够准确地确定是否需要重新复制,并使make
层之后的所有缓存层(包括COPY
构建)失效。