我有一个包含多个Dockerfiles的项目,每个Dockerfiles都位于一个命名目录中,我用它作为Docker图像标记。我需要为每个Dockerfile构建,测试和推送每个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))))
答案 0 :(得分:0)
我不确定这是你想要的,但是......
首先考虑BUILD
变量。如果我们有三个Dockerfiles:
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 $*
现在“make build_foo will 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”就足够了。)
答案 1 :(得分:0)
就像@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