thockin/go-build-template

Multiple registry support

alok87 opened this issue · 3 comments

Some open repos like to push to multiple container registries.
Like we are now going to support GCE container registry, recently released AWS public container registry and dockerhub.

This needs to be done multiple times at present for each registry:
make REGISTRY=public.ecr.aws/abc push

There are a few ways you could go about this;

  1. call make REGISTRY=foo && make REGISTRY=bar from your own build

  2. add an OTHER_REGISTRIES variable, iterate that in the final container-related rules

  3. Remove some of the existing uses of REGISTRY and turn it into a list

I started to implement this to see how messy it would be and it started easy, but it got unpleasant enough that I prefer the workarounds. Sorry for now.

For posterity, here's the first cut at a patch. The problem is that it needs to expand the DOTFILES to cover each registry, and that's more complex than I like for something too few people need (I think):

diff --git a/Makefile b/Makefile
index b4ded02..0960bbf 100644
--- a/Makefile
+++ b/Makefile
@@ -16,7 +16,7 @@
 BINS := myapp-1 myapp-2
 
 # Where to push the docker image.
-REGISTRY ?= example.com
+REGISTRIES ?= example.com
 
 # This version-strategy uses git tags to set the version string
 VERSION ?= $(shell git describe --tags --always --dirty)
@@ -160,52 +160,60 @@ shell: $(BUILD_DIRS)
 	    $(BUILD_IMAGE)                                          \
 	    /bin/sh $(CMD)
 
-CONTAINER_DOTFILES = $(foreach bin,$(BINS),.container-$(subst /,_,$(REGISTRY)/$(bin))-$(TAG))
+CONTAINER_DOTFILES = $(foreach bin,$(BINS),.container-$(subst /,_,img$(PWD)/$(bin))-$(TAG))
 
 container containers: # @HELP builds containers for one platform ($OS/$ARCH)
 container containers: $(CONTAINER_DOTFILES)
-	@for bin in $(BINS); do              \
-	    echo "container: $(REGISTRY)/$$bin:$(TAG)"; \
+	@for bin in $(BINS); do                                          \
+	    for reg in $(REGISTRIES); do                                 \
+	        docker tag img$(PWD)/$(BIN):$(TAG) $$reg/$(BIN):$(TAG);  \
+	        id=$$(docker images -q $$reg/$$bin:$(TAG));              \
+	        echo "container: $$reg/$$bin:$(TAG) $$id";               \
+	    done;                                                        \
 	done
 
 # Each container-dotfile target can reference a $(BIN) variable.
 # This is done in 2 steps to enable target-specific variables.
-$(foreach bin,$(BINS),$(eval $(strip                                 \
-    .container-$(subst /,_,$(REGISTRY)/$(bin))-$(TAG): BIN = $(bin)  \
+$(foreach bin,$(BINS),$(eval $(strip                               \
+    .container-$(subst /,_,img$(PWD)/$(bin))-$(TAG): BIN = $(bin)  \
 )))
-$(foreach bin,$(BINS),$(eval                                         \
-    .container-$(subst /,_,$(REGISTRY)/$(bin))-$(TAG): bin/$(OS)_$(ARCH)/$(bin)$(BIN_EXTENSION) Dockerfile.in  \
+$(foreach bin,$(BINS),$(eval                                       \
+    .container-$(subst /,_,img$(PWD)/$(bin))-$(TAG): bin/$(OS)_$(ARCH)/$(bin)$(BIN_EXTENSION) Dockerfile.in  \
 ))
 # This is the target definition for all container-dotfiles.
 # These are used to track build state in hidden files.
 $(CONTAINER_DOTFILES):
-	@sed                                          \
-	    -e 's|{ARG_BIN}|$(BIN)$(BIN_EXTENSION)|g' \
-	    -e 's|{ARG_ARCH}|$(ARCH)|g'               \
-	    -e 's|{ARG_OS}|$(OS)|g'                   \
-	    -e 's|{ARG_FROM}|$(BASEIMAGE)|g'          \
+	@sed                                           \
+	    -e 's|{ARG_BIN}|$(BIN)$(BIN_EXTENSION)|g'  \
+	    -e 's|{ARG_ARCH}|$(ARCH)|g'                \
+	    -e 's|{ARG_OS}|$(OS)|g'                    \
+	    -e 's|{ARG_FROM}|$(BASEIMAGE)|g'           \
 	    Dockerfile.in > .dockerfile-$(BIN)-$(OS)_$(ARCH)
-	@docker build -t $(REGISTRY)/$(BIN):$(TAG) -f .dockerfile-$(BIN)-$(OS)_$(ARCH) .
-	@docker images -q $(REGISTRY)/$(BIN):$(TAG) > $@
+	@docker build -t img$(PWD)/$(BIN):$(TAG) -f .dockerfile-$(BIN)-$(OS)_$(ARCH) .
+	@docker images -q img$(PWD)/$(BIN):$(TAG) > $@
 	@echo
 
 push: # @HELP pushes the container for one platform ($OS/$ARCH) to the defined registry
 push: $(CONTAINER_DOTFILES)
-	@for bin in $(BINS); do                    \
-	    docker push $(REGISTRY)/$$bin:$(TAG);  \
+	@for bin in $(BINS); do                  \
+	    for reg in $(REGISTRIES); do         \
+	        docker push $$reg/$$bin:$(TAG);  \
+	    done;                                \
 	done
 
 manifest-list: # @HELP builds a manifest list of containers for all platforms
 manifest-list: all-push
-	@for bin in $(BINS); do                                   \
-	    platforms=$$(echo $(ALL_PLATFORMS) | sed 's/ /,/g');  \
-	    manifest-tool                                         \
-	        --username=oauth2accesstoken                      \
-	        --password=$$(gcloud auth print-access-token)     \
-	        push from-args                                    \
-	        --platforms "$$platforms"                         \
-	        --template $(REGISTRY)/$$bin:$(VERSION)__OS_ARCH  \
-	        --target $(REGISTRY)/$$bin:$(VERSION)
+	@for bin in $(BINS); do                                       \
+	    for reg in $(REGISTRIES); do                              \
+	        platforms=$$(echo $(ALL_PLATFORMS) | sed 's/ /,/g');  \
+	        manifest-tool                                         \
+	            --username=oauth2accesstoken                      \
+	            --password=$$(gcloud auth print-access-token)     \
+	            push from-args                                    \
+	            --platforms "$$platforms"                         \
+	            --template $$reg/$$bin:$(VERSION)__OS_ARCH        \
+	            --target $$reg/$$bin:$(VERSION);                  \
+	    done
 
 version: # @HELP outputs the version string
 version:
@@ -250,7 +258,7 @@ help:
 	@echo "  BINS = $(BINS)"
 	@echo "  OS = $(OS)"
 	@echo "  ARCH = $(ARCH)"
-	@echo "  REGISTRY = $(REGISTRY)"
+	@echo "  REGISTRIES = '$(REGISTRIES)'"
 	@echo
 	@echo "TARGETS:"
 	@grep -E '^.*: *# *@HELP' $(MAKEFILE_LIST)    \

No problem workaround is better, if it is getting complicated here.