我玩Docker并制作实用程序并尝试编写仅在Dockerfile更改时重建docker镜像的规则。
我的项目结构如下:
tree .
.
├── Dockerfile
├── Makefile
└── project
└── 1.js
我的Dockerfile非常简单:
FROM ubuntu
RUN apt-get update
RUN apt-get install -y curl
RUN curl -sL https://deb.nodesource.com/setup | sudo bash -
RUN apt-get update
RUN apt-get install -y build-essential nodejs
VOLUME ["/project"]
ENTRYPOINT ["cat"]
CMD ["project/1.js"]
它只是用nodejs安装创建简单的ubuntu映像,并从共享目录运行脚本。
现在我想从Makefile运行这个图像。当我更改Dockerfile时,我想重建图像。 Makefile看起来像:
default: run
run: build
docker run -v $(CURDIR)/project:/project app-server
build: Dockerfile
docker build -t app-server .
现在,当我执行sudo make
命令时,它每次都会重建一个图像。
如果仅在Dockerfile更改时强制make执行构建任务?
答案 0 :(得分:10)
当你写:
run: build
docker run -v $(CURDIR)/project:/project app-server
makefile中的期望该配方将创建一个名为run
的文件。然后make会根据其先决条件文件的时间戳检查该文件的时间戳,以确定下次是否需要运行该配方。
与makefile中的build
目标类似。
build: Dockerfile
docker build -t app-server .
然而,这些食谱都没有创建具有目标名称的文件。这意味着make不能使用该文件的时间戳来确定是否需要重新运行配方。因此,make必须假设它需要重新运行配方(因为否则意味着该规则永远不会运行)。
如果你运行make -rRd
,你会看到make think会发生什么,你应该看到我刚才所说的内容。
因此,问题的解决方案是在每个目标中创建戳记文件。
只需添加touch $@
(可选地以@
为前缀,以使其运行的命令的默认回显)应该足以使其适用于您。
据说,如果你不想要邮票,那么将sudo
放在需要它的每个食谱行上而不是用make
运行sudo
可能是有意义的文件也将作为root拥有。
对于记录,这在GNU制作手册中作为4.8 Empty Target Files to Record Events
部分进行了讨论。
答案 1 :(得分:6)
你的目标" default
run
和build
是"假的"目标。这是一个抽象概念,而不是真正的文件。这样的虚假目标,不应该有一个配方(因为你不能制作它们)。它们应该依赖于真实文件,或者其他虚假目标等等,但是一切都必须最终只依赖于真实文件。
你的虚假目标应该标记为
.PHONY: default run build
另一方面,真正的目标应该有一个配方 - 配方制定目标。
所以,首先要将你的虚假目标,没有食谱,放在真正的目标上。
然后让真正的目标有食谱。
我已经发布了一些指南 makefile enforce library dependency ordering