From 591f07fd26ea13f9687b07ebe862a6041412e1a9 Mon Sep 17 00:00:00 2001 From: andig Date: Fri, 26 Apr 2019 19:22:22 +0200 Subject: [PATCH] Add multi-arch build script --- .dockerignore | 1 + Dockerfile | 9 ++++-- build-docker.sh | 76 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 84 insertions(+), 2 deletions(-) create mode 100755 build-docker.sh diff --git a/.dockerignore b/.dockerignore index 0cace7a..8854504 100644 --- a/.dockerignore +++ b/.dockerignore @@ -6,3 +6,4 @@ dumpcerts.sh acme.json acme-backup.json traefik-certs-dumper +build-docker.sh diff --git a/Dockerfile b/Dockerfile index 7d1ac0a..5c18d4e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,10 @@ FROM golang:1-alpine as builder +ARG RUNTIME_HASH +ARG GOARCH +ARG GOARM +ARG GOOS + RUN apk --update upgrade \ && apk --no-cache --no-progress add git make gcc musl-dev @@ -10,9 +15,9 @@ COPY go.mod go.sum ./ RUN go mod download COPY . . -RUN make build +RUN GOARCH=${GOARCH} GOARM=${GOARM} GOOS=${GOOS} make build -FROM alpine:3.9 +FROM alpine:3.9${RUNTIME_HASH} RUN apk --update upgrade \ && apk --no-cache --no-progress add ca-certificates diff --git a/build-docker.sh b/build-docker.sh new file mode 100755 index 0000000..8744b40 --- /dev/null +++ b/build-docker.sh @@ -0,0 +1,76 @@ +#!/bin/bash +set -ex + +# base docker image tag +TAG="andig/traefik-certs-dumper" + +# only linux for now +OS=linux + +# target platforms in docker manifest notation +declare -a PLATFORMS=( "amd64" "arm.v6" ) + +# images from Dockerfile +IMAGE=$(grep "FROM alpine" < Dockerfile | sed "s/FROM //" | sed 's/\$.*//') + +# manifest cache file +MANIFEST_FILE=/tmp/manifest.$IMAGE.json + +# get platform image hash from docker manifest +function hash () { + local ARCHITECTURE VARIANT HASH + read -r ARCHITECTURE VARIANT <<< "$@" + + if [ -z "$VARIANT" ]; then + HASH=$(jq -r ".manifests[] | select(.platform.architecture == \"$ARCHITECTURE\") | .digest" < "$MANIFEST_FILE") + else + HASH=$(jq -r ".manifests[] | select(.platform.architecture == \"$ARCHITECTURE\" and .platform.variant == \"$VARIANT\") | .digest" < "$MANIFEST_FILE") + fi + + echo "$HASH" +} + +# get manifest +if [ ! -f "$MANIFEST_FILE" ]; then + docker pull "$IMAGE" + docker manifest inspect "$IMAGE" > "$MANIFEST_FILE" +fi + +# main +for platform in "${PLATFORMS[@]}"; do + # split architecture.version + IFS='.' read -r ARCHITECTURE VARIANT <<< "$platform" + + # add xargs to trim whitespace + RUNTIME_HASH=$(hash "$ARCHITECTURE" "$VARIANT") + + # arm architectures flavors, strip "v" prefix + GOARM=${VARIANT:1} + + # build for target runtime image and architecture + docker build --build-arg RUNTIME_HASH=@${RUNTIME_HASH} --build-arg GOARCH=${ARCHITECTURE} --build-arg GOARM=${GOARM} -t "$TAG:latest-$platform" . +done + +# push images +for platform in "${PLATFORMS[@]}"; do + docker push "$TAG:latest-$platform" +done + +# create manifest +TAG_LIST=$(printf "$TAG:latest-%s " "${PLATFORMS[@]}") +# shellcheck disable=SC2086 +docker manifest create --amend "$TAG:latest" $TAG_LIST + +for platform in "${PLATFORMS[@]}"; do + # split architecture.version + IFS='.' read -r ARCHITECTURE VARIANT <<< "$platform" + + # docker and go architectures don't match + if [ "arm" == "$ARCHITECTURE" ] && [ -n "$VARIANT" ]; then + VARIANT="$ARCHITECTURE$VARIANT" + fi + + docker manifest annotate "$TAG:latest" "$TAG:latest-$platform" --os "$OS" --arch "$ARCHITECTURE" --variant "$VARIANT" +done + +docker manifest push "$TAG:latest"