我在玩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执行构建任务?
编写时:
run: build
docker run -v $(CURDIR)/project:/project app-server
在makefile中,make期望该配方将创建一个名为run
的文件。make将根据其先决条件文件的时间戳检查该文件的时间标记,以确定下次是否需要运行该配方。
与makefile中的build
目标类似。
build: Dockerfile
docker build -t app-server .
然而,这两个配方都不会创建具有目标名称的文件。这意味着make不能使用该文件的时间戳来确定是否需要重新运行配方。因此,make必须假设它需要重新运行配方(因为如果不这样做,则意味着规则永远不会运行)。
如果你运行make -rRd
,你会看到make的想法,你应该看到我刚才说的内容。
因此,解决问题的方法是在每个目标中创建stamp文件。
只需向每个目标添加touch $@
(可选地以@
为前缀,以使其运行的命令的默认make回显静音)就足以让它为您工作。
话虽如此,如果您不希望stamp文件也作为root拥有,那么将sudo
放在每个需要它的配方行上可能是有意义的,而不是使用sudo
运行make
。
为了记录在案,这在GNU Make手册中作为4.8 Empty Target Files to Record Events
节进行了讨论。
您的"目标"default
run
和build
是"虚假"目标。这是一个抽象的概念,而不是一个真实的文件。这种虚假的目标,不应该有一个配方(因为你做不到)。相反,它们应该依赖于真实的文件,或者其他虚假的目标,等等,但一切最终都必须只依赖于真实文件。
你的假目标应该标记为这样的
.PHONY: default run build
另一方面,真正的目标应该有一个配方——配方就是目标。
因此,首先,在没有配方的情况下,将你的虚假目标依赖于真实目标。
然后有真正的目标有食谱。
我在上发布了一些指南makefile强制库依赖排序