Build multi-arch container images across stack
diff --git a/apps/bwolf-gandi/.gitignore b/apps/bwolf-gandi/.gitignore
index fcff3af..b90f1c2 100644
--- a/apps/bwolf-gandi/.gitignore
+++ b/apps/bwolf-gandi/.gitignore
@@ -1,2 +1,3 @@
 cert-manager-webhook-gandi
-webhook
+webhook_arm64
+webhook_amd64
diff --git a/apps/bwolf-gandi/Dockerfile b/apps/bwolf-gandi/Dockerfile
index 6fee6aa..df46fc1 100644
--- a/apps/bwolf-gandi/Dockerfile
+++ b/apps/bwolf-gandi/Dockerfile
@@ -1,8 +1,10 @@
 FROM alpine:3.9
 
+ARG TARGETARCH
+
 RUN apk add --no-cache ca-certificates
 
-COPY webhook /usr/local/bin/webhook
+COPY webhook_${TARGETARCH} /usr/local/bin/webhook
 RUN chmod +x /usr/local/bin/webhook
 
 ENTRYPOINT ["webhook"]
diff --git a/apps/bwolf-gandi/Makefile b/apps/bwolf-gandi/Makefile
index cdfc936..2a09874 100644
--- a/apps/bwolf-gandi/Makefile
+++ b/apps/bwolf-gandi/Makefile
@@ -2,23 +2,26 @@
 IMAGE_TAG := "v0.2.0"
 
 checkout:
-	git clone --depth 1 --branch v0.2.0 https://github.com/bwolf/cert-manager-webhook-gandi.git
+	git clone --depth 1 --branch $(IMAGE_TAG) https://github.com/bwolf/cert-manager-webhook-gandi.git
 
 clean:
-	rm -f webhook
+	rm -f webhook_*
 
-build: export CGO_ENABLED=0
-build: export GO111MODULE=on
-build: clean
-	cd cert-manager-webhook-gandi && go build -o ../webhook -ldflags '-w -extldflags "-static"' .
+build_arm64: export CGO_ENABLED=0
+build_arm64: export GO111MODULE=on
+build_arm64: export GOOS=linux
+build_arm64: export GOARCH=arm64
+build_arm64: clean
+	cd cert-manager-webhook-gandi && go build -o ../webhook_arm64 -ldflags '-w -extldflags "-static"' .
 
-image: build
-	docker build --tag=$(IMAGE_NAME):$(IMAGE_TAG) . --platform=linux/arm64
+build_amd64: export CGO_ENABLED=0
+build_amd64: export GO111MODULE=on
+build_amd64: export GOOS=linux
+build_amd64: export GOARCH=amd64
+build_amd64: clean
+	cd cert-manager-webhook-gandi && go build -o ../webhook_amd64 -ldflags '-w -extldflags "-static"' .
 
-push: image
-	docker push $(IMAGE_NAME):$(IMAGE_TAG)
+build: clean build_arm64 build_amd64
 
-
-push_arm64: export GOOS=linux
-push_arm64: export GOARCH=arm64
-push_arm64: push
+push: build
+	docker buildx build --tag=$(IMAGE_NAME):$(IMAGE_TAG) . --platform=linux/arm64,linux/amd64 --push
diff --git a/apps/maddy/auth/.gitignore b/apps/maddy/auth/.gitignore
index cd8d050..824d9a9 100644
--- a/apps/maddy/auth/.gitignore
+++ b/apps/maddy/auth/.gitignore
@@ -1 +1,2 @@
-auth-smtp
+auth-smtp_amd64
+auth-smtp_arm64
diff --git a/apps/maddy/auth/Dockerfile b/apps/maddy/auth/Dockerfile
index 3b1168d..342f121 100644
--- a/apps/maddy/auth/Dockerfile
+++ b/apps/maddy/auth/Dockerfile
@@ -1,3 +1,6 @@
 FROM giolekva/maddy:v0.4.4
 
-COPY auth-smtp /usr/bin/auth-smtp
+ARG TARGETARCH
+
+COPY auth-smtp_${TARGETARCH} /usr/bin/auth-smtp
+RUN chmod +x /usr/bin/auth-smtp
diff --git a/apps/maddy/auth/Makefile b/apps/maddy/auth/Makefile
index 7bd9ea3..2d7d61f 100644
--- a/apps/maddy/auth/Makefile
+++ b/apps/maddy/auth/Makefile
@@ -1,17 +1,21 @@
 clean:
-	rm -f auth-smtp
+	rm -f auth-smtp_*
 
-build: clean
-	go build -o auth-smtp *.go
+build_arm64: export CGO_ENABLED=0
+build_arm64: export GO111MODULE=on
+build_arm64: export GOOS=linux
+build_arm64: export GOARCH=arm64
+build_arm64:
+	go build -o auth-smtp_arm64 *.go
 
-image: build
-	docker build --tag=giolekva/maddy-auth-smtp:v0.4.4 . --platform=linux/arm64
+build_amd64: export CGO_ENABLED=0
+build_amd64: export GO111MODULE=on
+build_amd64: export GOOS=linux
+build_amd64: export GOARCH=amd64
+build_amd64:
+	go build -o auth-smtp_amd64 *.go
 
-push: image
-	docker push giolekva/maddy-auth-smtp:v0.4.4
+build: clean build_arm64 build_amd64
 
-push_arm64: export GOOS=linux
-push_arm64: export GOARCH=arm64
-push_arm64: export CGO_ENABLED=0
-push_arm64: export GO111MODULE=on
-push_arm64: push
+push: build
+	docker buildx build --tag=giolekva/maddy-auth-smtp:v0.4.4 . --platform=linux/arm64,linux/amd64 --push
diff --git a/apps/maddy/web/.gitignore b/apps/maddy/web/.gitignore
index 797200e..06ccfe3 100644
--- a/apps/maddy/web/.gitignore
+++ b/apps/maddy/web/.gitignore
@@ -1 +1,2 @@
-maddy-web
+maddy-web_arm64
+maddy-web_amd64
diff --git a/apps/maddy/web/Dockerfile b/apps/maddy/web/Dockerfile
index 8c057e1..0b38e18 100644
--- a/apps/maddy/web/Dockerfile
+++ b/apps/maddy/web/Dockerfile
@@ -1,4 +1,6 @@
 FROM giolekva/maddy:v0.4.4 AS maddy
 
-COPY maddy-web /usr/bin
+ARG TARGETARCH
+
+COPY maddy-web_${TARGETARCH} /usr/bin/maddy-web
 RUN chmod +x /usr/bin/maddy-web
diff --git a/apps/maddy/web/Makefile b/apps/maddy/web/Makefile
index 2054935..4ab1785 100644
--- a/apps/maddy/web/Makefile
+++ b/apps/maddy/web/Makefile
@@ -1,17 +1,21 @@
 clean:
-	rm -f maddy-web
+	rm -f maddy-web_*
 
-build: clean
-	go build -o maddy-web *.go
+build_arm64: export CGO_ENABLED=0
+build_arm64: export GO111MODULE=on
+build_arm64: export GOOS=linux
+build_arm64: export GOARCH=arm64
+build_arm64:
+	go build -o maddy-web_arm64 *.go
 
-image: build
-	docker build --tag=giolekva/maddy-web:latest . --platform=linux/arm64
+build_amd64: export CGO_ENABLED=0
+build_amd64: export GO111MODULE=on
+build_amd64: export GOOS=linux
+build_amd64: export GOARCH=amd64
+build_amd64:
+	go build -o maddy-web_amd64 *.go
 
-push: image
-	docker push giolekva/maddy-web:latest
+build: clean build_arm64 build_amd64
 
-push_arm64: export GOOS=linux
-push_arm64: export GOARCH=arm64
-push_arm64: export CGO_ENABLED=0
-push_arm64: export GO111MODULE=on
-push_arm64: push
+push: build
+	docker buildx build --tag=giolekva/maddy-web:latest . --platform=linux/arm64,linux/amd64 --push
diff --git a/apps/matrix/capture-config/.gitignore b/apps/matrix/capture-config/.gitignore
index 1ebbf4c..82a3515 100644
--- a/apps/matrix/capture-config/.gitignore
+++ b/apps/matrix/capture-config/.gitignore
@@ -1 +1,2 @@
-capture-config
+capture-config_arm64
+capture-config_amd64
diff --git a/apps/matrix/capture-config/Dockerfile b/apps/matrix/capture-config/Dockerfile
index 87f358c..bcecf7b 100644
--- a/apps/matrix/capture-config/Dockerfile
+++ b/apps/matrix/capture-config/Dockerfile
@@ -1,4 +1,6 @@
 FROM alpine:latest
 
-COPY capture-config /usr/bin
+ARG TARGETARCH
+
+COPY capture-config_${TARGETARCH} /usr/bin/capture-config
 RUN chmod +x /usr/bin/capture-config
diff --git a/apps/matrix/capture-config/Makefile b/apps/matrix/capture-config/Makefile
index 6e3ddec..c05687d 100644
--- a/apps/matrix/capture-config/Makefile
+++ b/apps/matrix/capture-config/Makefile
@@ -1,17 +1,21 @@
 clean:
-	rm -f capture-config
+	rm -f capture-config_*
 
-build: clean
-	go build -o capture-config *.go
+build_arm64: export CGO_ENABLED=0
+build_arm64: export GO111MODULE=on
+build_arm64: export GOOS=linux
+build_arm64: export GOARCH=arm64
+build_arm64:
+	go build -o capture-config_arm64 *.go
 
-image: build
-	docker build --tag=giolekva/capture-config:latest . --platform=linux/arm64
+build_amd64: export CGO_ENABLED=0
+build_amd64: export GO111MODULE=on
+build_amd64: export GOOS=linux
+build_amd64: export GOARCH=amd64
+build_amd64:
+	go build -o capture-config_amd64 *.go
 
-push: image
-	docker push giolekva/capture-config:latest
+build: clean build_arm64 build_amd64
 
-push_arm64: export GOOS=linux
-push_arm64: export GOARCH=arm64
-push_arm64: export CGO_ENABLED=0
-push_arm64: export GO111MODULE=on
-push_arm64: push
+push: build
+	docker buildx build --tag=giolekva/capture-config:latest . --platform=linux/arm64,linux/amd64 --push
diff --git a/core/auth/hydra-maester/Dockerfile b/core/auth/hydra-maester/Dockerfile
index 072d9b2..585f9af 100644
--- a/core/auth/hydra-maester/Dockerfile
+++ b/core/auth/hydra-maester/Dockerfile
@@ -1,4 +1,5 @@
 FROM gcr.io/distroless/static:latest
-COPY hydra-maester/manager .
+ARG TARGETARCH
+COPY hydra-maester/manager_${TARGETARCH} /manager
 USER 1000
 ENTRYPOINT ["/manager"]
diff --git a/core/auth/hydra-maester/Makefile b/core/auth/hydra-maester/Makefile
index 970da58..98453ac 100644
--- a/core/auth/hydra-maester/Makefile
+++ b/core/auth/hydra-maester/Makefile
@@ -1,15 +1,23 @@
+clean: rm -rf hydra-maester/manager_*
+
 clone:
 	git clone --depth 1 --branch v0.0.20 https://github.com/ory/hydra-maester.git
 
-push_arm64: export GOOS=linux
-push_arm64: export GOARCH=arm64
-push_arm64: export CGO_ENABLED=0
-push_arm64: export GO111MODULE=on
-build:
-	cd hydra-maester && go build -o manager main.go
+build_arm64: export CGO_ENABLED=0
+build_arm64: export GO111MODULE=on
+build_arm64: export GOOS=linux
+build_arm64: export GOARCH=arm64
+build_arm64:
+	cd hydra-maester && go build -o manager_arm64 main.go
 
-image_arm64: build
-	docker build --tag=giolekva/ory-hydra-maester:latest . --platform=linux/arm64
+build_amd64: export CGO_ENABLED=0
+build_amd64: export GO111MODULE=on
+build_amd64: export GOOS=linux
+build_amd64: export GOARCH=amd64
+build_amd64:
+	cd hydra-maester && go build -o manager_amd64 main.go
 
-push_arm64: image_arm64
-	docker push giolekva/ory-hydra-maester:latest
+build: clean build_arm64 build_amd64
+
+push: build
+	docker buildx build --tag=giolekva/ory-hydra-maester:latest . --platform=linux/arm64,linux/amd64 --push
diff --git a/core/auth/hydra/Dockerfile b/core/auth/hydra/Dockerfile
index 96ec8fa..ba49668 100644
--- a/core/auth/hydra/Dockerfile
+++ b/core/auth/hydra/Dockerfile
@@ -1,5 +1,7 @@
 FROM alpine:3.14.2
 
+ARG TARGETARCH
+
 RUN addgroup -S ory; \
     adduser -S ory -G ory -D -u 10000 -h /home/ory -s /bin/nologin; \
     chown -R ory:ory /home/ory
@@ -7,7 +9,13 @@
 RUN apk add -U --no-cache ca-certificates
 
 WORKDIR /downloads
-RUN wget https://github.com/ory/hydra/releases/download/v1.10.6/hydra_1.10.6_linux_arm64.tar.gz -O hydra.tar.gz
+RUN if [[ "${TARGETARCH}" == "amd64" ]]; \
+    then \
+      wget https://github.com/ory/hydra/releases/download/v1.10.6/hydra_1.10.6_linux_64bit.tar.gz -O hydra.tar.gz ; \
+    else \
+      wget https://github.com/ory/hydra/releases/download/v1.10.6/hydra_1.10.6_linux_${TARGETARCH}.tar.gz -O hydra.tar.gz ; \
+    fi
+
 RUN tar -xvf hydra.tar.gz
 RUN mv hydra /usr/bin
 
diff --git a/core/auth/hydra/Makefile b/core/auth/hydra/Makefile
index 6a91678..b0914b7 100644
--- a/core/auth/hydra/Makefile
+++ b/core/auth/hydra/Makefile
@@ -1,5 +1,2 @@
-image_arm64:
-	docker build --tag=giolekva/ory-hydra:latest . --platform=linux/arm64
-
-push_arm64: image_arm64
-	docker push giolekva/ory-hydra:latest
+push:
+	docker buildx build --tag=giolekva/ory-hydra:latest . --platform=linux/arm64,linux/amd64 --push
diff --git a/core/auth/kratos/Dockerfile b/core/auth/kratos/Dockerfile
index 9dea8e3..6b60233 100644
--- a/core/auth/kratos/Dockerfile
+++ b/core/auth/kratos/Dockerfile
@@ -1,12 +1,20 @@
 FROM alpine:3.14.2
 
+ARG TARGETARCH
+
 RUN addgroup -S ory; \
     adduser -S ory -G ory -D -u 10000 -h /home/ory -s /bin/nologin; \
     chown -R ory:ory /home/ory
 
 RUN apk add -U --no-cache ca-certificates
 
-RUN wget https://github.com/ory/kratos/releases/download/v0.7.6-alpha.1/kratos_0.7.6-alpha.1_linux_arm64.tar.gz -O kratos.tar.gz
+RUN if [[ "${TARGETARCH}" == "amd64" ]]; \
+    then \
+      wget https://github.com/ory/kratos/releases/download/v0.7.6-alpha.1/kratos_0.7.6-alpha.1_linux_64bit.tar.gz -O kratos.tar.gz ; \
+    else \
+      wget https://github.com/ory/kratos/releases/download/v0.7.6-alpha.1/kratos_0.7.6-alpha.1_linux_${TARGETARCH}.tar.gz -O kratos.tar.gz ; \
+    fi
+
 RUN tar -xvf kratos.tar.gz
 RUN mv kratos /usr/bin
 
diff --git a/core/auth/kratos/Makefile b/core/auth/kratos/Makefile
index ab5043a..3b803ed 100644
--- a/core/auth/kratos/Makefile
+++ b/core/auth/kratos/Makefile
@@ -1,12 +1,2 @@
-image:
-	docker build --tag=giolekva/ory-kratos:latest . --platform=linux/arm64
-
-push: image
-	docker push giolekva/ory-kratos:latest
-
-
-push_arm64: export GOOS=linux
-push_arm64: export GOARCH=arm64
-push_arm64: export CGO_ENABLED=0
-push_arm64: export GO111MODULE=on
-push_arm64: push
+push:
+	docker buildx build --tag=giolekva/ory-kratos:latest . --platform=linux/arm64,linux/amd64 --push
diff --git a/core/auth/ui/.gitignore b/core/auth/ui/.gitignore
index 254defd..dc33f72 100644
--- a/core/auth/ui/.gitignore
+++ b/core/auth/ui/.gitignore
@@ -1 +1,2 @@
-server
+server_arm64
+server_amd64
diff --git a/core/auth/ui/Dockerfile b/core/auth/ui/Dockerfile
index 8a76b08..980e40e 100644
--- a/core/auth/ui/Dockerfile
+++ b/core/auth/ui/Dockerfile
@@ -1,4 +1,6 @@
 FROM alpine:latest
 
-COPY server /usr/bin
+ARG TARGETARCH
+
+COPY server_${TARGETARCH} /usr/bin/server
 RUN chmod +x /usr/bin/server
diff --git a/core/auth/ui/Makefile b/core/auth/ui/Makefile
index 70bf15c..a401141 100644
--- a/core/auth/ui/Makefile
+++ b/core/auth/ui/Makefile
@@ -1,18 +1,19 @@
-build:
-	go build -o server *.go
-
 clean:
-	rm -f server
+	rm -f server_*
 
-image: clean build
-	docker build --tag=giolekva/auth-ui . --platform=linux/arm64
+build_arm64: export CGO_ENABLED=0
+build_arm64: export GO111MODULE=on
+build_arm64: export GOOS=linux
+build_arm64: export GOARCH=arm64
+build_arm64:
+	go build -o server_arm64 *.go
 
-push: image
-	docker push giolekva/auth-ui:latest
+build_amd64: export CGO_ENABLED=0
+build_amd64: export GO111MODULE=on
+build_amd64: export GOOS=linux
+build_amd64: export GOARCH=amd64
+build_amd64:
+	go build -o server_amd64 *.go
 
-
-push_arm64: export GOOS=linux
-push_arm64: export GOARCH=arm64
-push_arm64: export CGO_ENABLED=0
-push_arm64: export GO111MODULE=on
-push_arm64: push
+push: clean build_arm64 build_amd64
+	docker buildx build --tag=giolekva/auth-ui:latest . --platform=linux/arm64,linux/amd64 --push
diff --git a/core/nebula/Dockerfile b/core/nebula/Dockerfile
index 8377bdd..5f8d825 100644
--- a/core/nebula/Dockerfile
+++ b/core/nebula/Dockerfile
@@ -1,6 +1,8 @@
 FROM alpine:latest
 
-RUN wget https://github.com/slackhq/nebula/releases/download/v1.4.0/nebula-linux-arm64.tar.gz -O nebula.tar.gz
+ARG TARGETARCH
+
+RUN wget https://github.com/slackhq/nebula/releases/download/v1.4.0/nebula-linux-${TARGETARCH}.tar.gz -O nebula.tar.gz
 RUN tar -xvf nebula.tar.gz
 RUN mv nebula /usr/bin
 RUN mv nebula-cert /usr/bin
diff --git a/core/nebula/Makefile b/core/nebula/Makefile
index be9f307..c8b2f75 100644
--- a/core/nebula/Makefile
+++ b/core/nebula/Makefile
@@ -1,5 +1,2 @@
-image_arm64:
-	docker build --tag=giolekva/nebula:latest . --platform=linux/arm64
-
-push_arm64: image_arm64
-	docker push giolekva/nebula:latest
+push:
+	docker buildx build --tag=giolekva/nebula:latest . --platform=linux/arm64,linux/amd64 --push
diff --git a/core/nebula/controller/.gitignore b/core/nebula/controller/.gitignore
index 30d5788..17f70e0 100644
--- a/core/nebula/controller/.gitignore
+++ b/core/nebula/controller/.gitignore
@@ -1,3 +1,5 @@
-controller
+controller_arm64
+controller_amd64
 vendor
-web
+web_arm64
+web_amd64
\ No newline at end of file
diff --git a/core/nebula/controller/Dockerfile.controller b/core/nebula/controller/Dockerfile.controller
index fa0b2b7..82586e4 100644
--- a/core/nebula/controller/Dockerfile.controller
+++ b/core/nebula/controller/Dockerfile.controller
@@ -1,9 +1,11 @@
 FROM alpine:latest
 
-COPY controller /usr/bin/nebula-controller
+ARG TARGETARCH
+
+COPY controller_${TARGETARCH} /usr/bin/nebula-controller
 RUN chmod +x /usr/bin/nebula-controller
 
-RUN wget https://github.com/slackhq/nebula/releases/download/v1.4.0/nebula-linux-arm64.tar.gz -O nebula.tar.gz
+RUN wget https://github.com/slackhq/nebula/releases/download/v1.4.0/nebula-linux-${TARGETARCH}.tar.gz -O nebula.tar.gz
 RUN tar -xvf nebula.tar.gz
 RUN mv nebula-cert /usr/bin
 RUN chmod +x /usr/bin/nebula-cert
diff --git a/core/nebula/controller/Dockerfile.web b/core/nebula/controller/Dockerfile.web
index a82f86b..6c5a573 100644
--- a/core/nebula/controller/Dockerfile.web
+++ b/core/nebula/controller/Dockerfile.web
@@ -1,4 +1,6 @@
 FROM alpine:latest
 
-COPY web /usr/bin/nebula-web
+ARG TARGETARCH
+
+COPY web_${TARGETARCH} /usr/bin/nebula-web
 RUN chmod +x /usr/bin/nebula-web
diff --git a/core/nebula/controller/Makefile b/core/nebula/controller/Makefile
index 2104b79..a838f0b 100644
--- a/core/nebula/controller/Makefile
+++ b/core/nebula/controller/Makefile
@@ -1,36 +1,50 @@
 clean:
-	rm -f controller web
+	rm -f controller_* web_*
 
 generate:
 	rm -rf generated
 	./hack/generate.sh
 
-controller: export CGO_ENABLED=0
-controller: export GO111MODULE=on
-controller: export GOOS=linux
-controller: export GOARCH=arm64
-controller:
+controller_arm64: export CGO_ENABLED=0
+controller_arm64: export GO111MODULE=on
+controller_arm64: export GOOS=linux
+controller_arm64: export GOARCH=arm64
+controller_arm64:
 	go mod tidy
 	go mod vendor
-	go build -o controller main.go
+	go build -o controller_arm64 main.go
 
-web: export CGO_ENABLED=0
-web: export GO111MODULE=on
-web: export GOOS=linux
-web: export GOARCH=arm64
-web:
-	go build -o web web.go
+controller_amd64: export CGO_ENABLED=0
+controller_amd64: export GO111MODULE=on
+controller_amd64: export GOOS=linux
+controller_amd64: export GOARCH=amd64
+controller_amd64:
+	go mod tidy
+	go mod vendor
+	go build -o controller_amd64 main.go
 
-image_controller: controller
-	docker build -f Dockerfile.controller --tag=giolekva/nebula-controller:latest . --platform=linux/arm64
+controller: controller_arm64 controller_amd64
 
-image_web: web
-	docker build -f Dockerfile.web --tag=giolekva/nebula-web:latest . --platform=linux/arm64
+web_arm64: export CGO_ENABLED=0
+web_arm64: export GO111MODULE=on
+web_arm64: export GOOS=linux
+web_arm64: export GOARCH=arm64
+web_arm64:
+	go build -o web_arm64 web.go
 
-push_controller: image_controller
-	docker push giolekva/nebula-controller:latest
+web_amd64: export CGO_ENABLED=0
+web_amd64: export GO111MODULE=on
+web_amd64: export GOOS=linux
+web_amd64: export GOARCH=amd64
+web_amd64:
+	go build -o web_amd64 web.go
 
-push_web: image_web
-	docker push giolekva/nebula-web:latest
+web: web_arm64 web_amd64
 
-push_arm64: push_controller push_web
+push_controller: controller
+	docker buildx build -f Dockerfile.controller --tag=giolekva/nebula-controller:latest . --platform=linux/arm64,linux/amd64 --push
+
+push_web: web
+	docker buildx build -f Dockerfile.web --tag=giolekva/nebula-web:latest . --platform=linux/arm64,linux/amd64 --push
+
+push: push_controller push_web