makefile - 使用多个目标构建多个文件

时间:2016-04-11 18:27:25

标签: makefile gnu-make dockerfile

我有一个包含多个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))))

2 个答案:

答案 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