makefile - 构建具有多个目标的多个文件
makefile - build mulitple files with multiple targets
我有一个包含多个 Docker 文件的项目,每个文件都位于我用作 Docker 图像标签的命名目录中。我需要为每个 Docker 文件构建、测试和推送每个 docker 图像。我需要做什么才能使用 GNU Make 制作诸如以下的作品?
# BUILDS needs to be a list of directories, not a list of Dockerfiles
BUILDS := $(wildcard */Dockerfile)
VERSION := $(shell git rev-parse --short=12 --verify HEAD)
DOCKER_REPO_URL := quay.io/reponame
define docker_build =
$(1):
@echo "Building $$@"
docker build -t $$@ --force-rm $$@
endef
define docker_test =
$(1):
@echo "Testing $$@"
docker inspect $$@
docker run --rm $$@ help
endef
define docker_push =
$(1):
@echo "Pushing $$@"
docker tag $$@ $(DOCKER_REPO_URL):$$@-$(VERSION)
docker push $(DOCKER_REPO_URL):$$@-$(VERSION)
docker tag $$@ $(DOCKER_REPO_URL):$$@
docker push $(DOCKER_REPO_URL):$$@
endef
.PHONY: all build test release clean
all: build test release
build: $(BUILDS)
$(foreach build,$(BUILDS),$(eval $(call docker_build,$(build))))
test: $(BUILDS)
$(foreach test,$(BUILDS),$(eval $(call docker_test,$(test))))
release:
$(foreach image,$(BUILDS),$(eval $(call docker_push,$(image))))
我不确定这是否是您想要的,但是...
首先考虑BUILD
变量。如果我们有三个 Dockerfile:
foo/Dockerfile
bar/Dockerfile
baz/Dockerfile
那么我们希望BUILDS
包含foo bar baz
这里有一些尝试:
BUILDS := $(wildcard */Dockerfile) # this is foo/Dockerfile bar/Dockerfile baz/Dockerfile
BUILDS := $(dir $(wildcard */Dockerfile)) # this is foo/ bar/ baz/
BUILDS := $(patsubst %/,%, $(dir $(wildcard */Dockerfile))) # this is foo bar baz
简陋但有效。
现在是规则。通常,规则的目标是规则构建的文件的名称。在这种情况下,我们必须打破这个约定,因为我们不知道图像文件的名称是什么。因此,如果目录是 foo/
,我们可以有一个名为 build_foo
:
的规则
build_foo:
@echo "Building foo"
@echo docker build -t foo --force-rm foo
由于我们不想为每个可能的目录编写规则,我们将使用自动变量并创建 pattern rule:
build_%:
@echo "Building $$@"
@echo docker build -t $* --force-rm $*
现在“制定 build_foowill work correctly. And we could write a
build` 构建所有这些的规则:
build: $(addprefix build_,$(BUILDS))
但这不是很正确的方法。我们希望按此顺序构建、测试、推送每个映像。所以我们想要这样的东西:
push_foo: test_foo
test_foo: build_foo
我们可以用模式规则来做到这一点:
test_%: build_%
...
push_%: test_%
...
release: $(addprefix push_,$(BUILDS))
现在 "make release" 会做所有事情。 (如果您将 release:
作为 makefile 中的第一条规则,它将成为默认规则,并且 "make" 就足够了。)
和@Beta一样,我不明白你为什么要构建所有图像,然后
测试所有图像,然后推送所有图像,而不是
构建、测试和推送每个镜像;后一种方法适合自己
到一个更简单、更正常的 makefile。
如果您有理由必须以第一种方式进行操作,那么您需要一个
makefile 是这样的:
# Assuming each subdirectory `foobar` containing a Dockerfile
# is where we `docker build` the image `foobar`
IMAGES := $(patsubst %/,%,$(dir $(wildcard */Dockerfile)))
BUILD_TARGS = $(patsubst %,build_%,$(IMAGES))
TEST_TARGS = $(patsubst %,test_%,$(IMAGES))
PUSH_TARGS = $(patsubst %,push_%,$(IMAGES))
VERSION := 1 # $(shell git rev-parse --short=12 --verify HEAD)
DOCKER_REPO_URL := quay.io/reponame
define docker_build =
build_$(1):
@echo "Building $(1)"
#docker build -t $(1) --force-rm $(1)
endef
define docker_test =
test_$(1):
@echo "Testing $(1)"
#docker inspect $(1)
#docker run --rm $(1) help
endef
define docker_push =
push_$(1):
@echo "Pushing $(1)"
#docker tag $(1) $(DOCKER_REPO_URL):$(1)-$(VERSION)
#docker push $(DOCKER_REPO_URL):$(1)-$(VERSION)
#docker tag $$@ $(DOCKER_REPO_URL):$(1)
#docker push $(DOCKER_REPO_URL):$(1)
endef
.PHONY: all build test release clean $(IMAGES) $(BUILD_TARGS) $(TEST_TARGS) $(PUSH_TARGS)
all: build test release
build: $(BUILD_TARGS)
test: $(TEST_TARGS)
release: $(PUSH_TARGS)
$(foreach image,$(IMAGES),$(eval $(call docker_build,$(image))))
$(foreach image,$(IMAGES),$(eval $(call docker_test,$(image))))
$(foreach image,$(IMAGES),$(eval $(call docker_push,$(image))))
显然,取消注释 docker
命令使它们成为 运行,并恢复
VERSION
.
的正确定义
就目前而言,它会给你这样的东西:
$ make
Building foo
#docker build -t foo --force-rm foo
Building bar
#docker build -t bar --force-rm bar
Testing foo
#docker inspect foo
#docker run --rm foo help
Testing bar
#docker inspect bar
#docker run --rm bar help
Pushing foo
#docker tag foo quay.io/reponame:foo-1
#docker push quay.io/reponame:foo-1
#docker tag push_foo quay.io/reponame:foo
#docker push quay.io/reponame:foo
Pushing bar
#docker tag bar quay.io/reponame:bar-1
#docker push quay.io/reponame:bar-1
#docker tag push_bar quay.io/reponame:bar
#docker push quay.io/reponame:bar
我有一个包含多个 Docker 文件的项目,每个文件都位于我用作 Docker 图像标签的命名目录中。我需要为每个 Docker 文件构建、测试和推送每个 docker 图像。我需要做什么才能使用 GNU Make 制作诸如以下的作品?
# BUILDS needs to be a list of directories, not a list of Dockerfiles
BUILDS := $(wildcard */Dockerfile)
VERSION := $(shell git rev-parse --short=12 --verify HEAD)
DOCKER_REPO_URL := quay.io/reponame
define docker_build =
$(1):
@echo "Building $$@"
docker build -t $$@ --force-rm $$@
endef
define docker_test =
$(1):
@echo "Testing $$@"
docker inspect $$@
docker run --rm $$@ help
endef
define docker_push =
$(1):
@echo "Pushing $$@"
docker tag $$@ $(DOCKER_REPO_URL):$$@-$(VERSION)
docker push $(DOCKER_REPO_URL):$$@-$(VERSION)
docker tag $$@ $(DOCKER_REPO_URL):$$@
docker push $(DOCKER_REPO_URL):$$@
endef
.PHONY: all build test release clean
all: build test release
build: $(BUILDS)
$(foreach build,$(BUILDS),$(eval $(call docker_build,$(build))))
test: $(BUILDS)
$(foreach test,$(BUILDS),$(eval $(call docker_test,$(test))))
release:
$(foreach image,$(BUILDS),$(eval $(call docker_push,$(image))))
我不确定这是否是您想要的,但是...
首先考虑BUILD
变量。如果我们有三个 Dockerfile:
foo/Dockerfile
bar/Dockerfile
baz/Dockerfile
那么我们希望BUILDS
包含foo bar baz
这里有一些尝试:
BUILDS := $(wildcard */Dockerfile) # this is foo/Dockerfile bar/Dockerfile baz/Dockerfile
BUILDS := $(dir $(wildcard */Dockerfile)) # this is foo/ bar/ baz/
BUILDS := $(patsubst %/,%, $(dir $(wildcard */Dockerfile))) # this is foo bar baz
简陋但有效。
现在是规则。通常,规则的目标是规则构建的文件的名称。在这种情况下,我们必须打破这个约定,因为我们不知道图像文件的名称是什么。因此,如果目录是 foo/
,我们可以有一个名为 build_foo
:
build_foo:
@echo "Building foo"
@echo docker build -t foo --force-rm foo
由于我们不想为每个可能的目录编写规则,我们将使用自动变量并创建 pattern rule:
build_%:
@echo "Building $$@"
@echo docker build -t $* --force-rm $*
现在“制定 build_foowill work correctly. And we could write a
build` 构建所有这些的规则:
build: $(addprefix build_,$(BUILDS))
但这不是很正确的方法。我们希望按此顺序构建、测试、推送每个映像。所以我们想要这样的东西:
push_foo: test_foo
test_foo: build_foo
我们可以用模式规则来做到这一点:
test_%: build_%
...
push_%: test_%
...
release: $(addprefix push_,$(BUILDS))
现在 "make release" 会做所有事情。 (如果您将 release:
作为 makefile 中的第一条规则,它将成为默认规则,并且 "make" 就足够了。)
和@Beta一样,我不明白你为什么要构建所有图像,然后 测试所有图像,然后推送所有图像,而不是 构建、测试和推送每个镜像;后一种方法适合自己 到一个更简单、更正常的 makefile。
如果您有理由必须以第一种方式进行操作,那么您需要一个 makefile 是这样的:
# Assuming each subdirectory `foobar` containing a Dockerfile
# is where we `docker build` the image `foobar`
IMAGES := $(patsubst %/,%,$(dir $(wildcard */Dockerfile)))
BUILD_TARGS = $(patsubst %,build_%,$(IMAGES))
TEST_TARGS = $(patsubst %,test_%,$(IMAGES))
PUSH_TARGS = $(patsubst %,push_%,$(IMAGES))
VERSION := 1 # $(shell git rev-parse --short=12 --verify HEAD)
DOCKER_REPO_URL := quay.io/reponame
define docker_build =
build_$(1):
@echo "Building $(1)"
#docker build -t $(1) --force-rm $(1)
endef
define docker_test =
test_$(1):
@echo "Testing $(1)"
#docker inspect $(1)
#docker run --rm $(1) help
endef
define docker_push =
push_$(1):
@echo "Pushing $(1)"
#docker tag $(1) $(DOCKER_REPO_URL):$(1)-$(VERSION)
#docker push $(DOCKER_REPO_URL):$(1)-$(VERSION)
#docker tag $$@ $(DOCKER_REPO_URL):$(1)
#docker push $(DOCKER_REPO_URL):$(1)
endef
.PHONY: all build test release clean $(IMAGES) $(BUILD_TARGS) $(TEST_TARGS) $(PUSH_TARGS)
all: build test release
build: $(BUILD_TARGS)
test: $(TEST_TARGS)
release: $(PUSH_TARGS)
$(foreach image,$(IMAGES),$(eval $(call docker_build,$(image))))
$(foreach image,$(IMAGES),$(eval $(call docker_test,$(image))))
$(foreach image,$(IMAGES),$(eval $(call docker_push,$(image))))
显然,取消注释 docker
命令使它们成为 运行,并恢复
VERSION
.
就目前而言,它会给你这样的东西:
$ make
Building foo
#docker build -t foo --force-rm foo
Building bar
#docker build -t bar --force-rm bar
Testing foo
#docker inspect foo
#docker run --rm foo help
Testing bar
#docker inspect bar
#docker run --rm bar help
Pushing foo
#docker tag foo quay.io/reponame:foo-1
#docker push quay.io/reponame:foo-1
#docker tag push_foo quay.io/reponame:foo
#docker push quay.io/reponame:foo
Pushing bar
#docker tag bar quay.io/reponame:bar-1
#docker push quay.io/reponame:bar-1
#docker tag push_bar quay.io/reponame:bar
#docker push quay.io/reponame:bar