diff options
author | Jeremy Lin <[email protected]> | 2020-06-10 02:01:41 -0700 |
---|---|---|
committer | Jeremy Lin <[email protected]> | 2020-07-15 20:03:34 -0700 |
commit | 4559e85daa31afb5120c5320760a708f2e5ea862 (patch) | |
tree | 3c3eb9292c51338e2d30e76774a47273b60c7796 /hooks | |
parent | bbef332e25f2e9045c70d7219d7d7f1a38cda316 (diff) | |
download | vaultwarden-4559e85daa31afb5120c5320760a708f2e5ea862.tar.gz vaultwarden-4559e85daa31afb5120c5320760a708f2e5ea862.zip |
Multi-arch image support
Diffstat (limited to 'hooks')
-rw-r--r-- | hooks/README.md | 19 | ||||
-rw-r--r-- | hooks/arches.sh | 30 | ||||
-rwxr-xr-x | hooks/build | 14 | ||||
-rwxr-xr-x | hooks/push | 55 |
4 files changed, 118 insertions, 0 deletions
diff --git a/hooks/README.md b/hooks/README.md new file mode 100644 index 00000000..0932987a --- /dev/null +++ b/hooks/README.md @@ -0,0 +1,19 @@ +The hooks in this directory are used to create multi-arch images using Docker Hub automated builds. + +Docker Hub hooks provide these predefined [environment variables](https://docs.docker.com/docker-hub/builds/advanced/#environment-variables-for-building-and-testing): + +* `SOURCE_BRANCH`: the name of the branch or the tag that is currently being tested. +* `SOURCE_COMMIT`: the SHA1 hash of the commit being tested. +* `COMMIT_MSG`: the message from the commit being tested and built. +* `DOCKER_REPO`: the name of the Docker repository being built. +* `DOCKERFILE_PATH`: the dockerfile currently being built. +* `DOCKER_TAG`: the Docker repository tag being built. +* `IMAGE_NAME`: the name and tag of the Docker repository being built. (This variable is a combination of `DOCKER_REPO:DOCKER_TAG`.) + +The current multi-arch image build relies on the original bitwarden_rs Dockerfiles, which use cross-compilation for architectures other than `amd64`, and don't yet support all arch/database/OS combinations. However, cross-compilation is much faster than QEMU-based builds (e.g., using `docker buildx`). This situation may need to be revisited at some point. + +## References + +* https://docs.docker.com/docker-hub/builds/advanced/ +* https://docs.docker.com/engine/reference/commandline/manifest/ +* https://www.docker.com/blog/multi-arch-build-and-images-the-simple-way/ diff --git a/hooks/arches.sh b/hooks/arches.sh new file mode 100644 index 00000000..216179e3 --- /dev/null +++ b/hooks/arches.sh @@ -0,0 +1,30 @@ +# The default Debian-based SQLite images support these arches. +# +# Other images (Alpine-based, or with other database backends) currently +# support only a subset of these. +arches=( + amd64 + arm32v6 + arm32v7 + arm64v8 +) + +case "${DOCKER_REPO}" in + *-mysql) + db=mysql + arches=(amd64) + ;; + *-postgresql) + db=postgresql + arches=(amd64) + ;; + *) + db=sqlite + ;; +esac + +if [[ "${DOCKER_TAG}" == *alpine ]]; then + # The Alpine build currently only works for amd64. + os_suffix=.alpine + arches=(amd64) +fi diff --git a/hooks/build b/hooks/build new file mode 100755 index 00000000..2a534606 --- /dev/null +++ b/hooks/build @@ -0,0 +1,14 @@ +#!/bin/bash + +echo ">>> Building images..." + +source ./hooks/arches.sh + +set -ex + +for arch in "${arches[@]}"; do + docker build \ + -t "${DOCKER_REPO}:${DOCKER_TAG}-${arch}" \ + -f docker/${arch}/${db}/Dockerfile${os_suffix} \ + . +done diff --git a/hooks/push b/hooks/push new file mode 100755 index 00000000..5fd96079 --- /dev/null +++ b/hooks/push @@ -0,0 +1,55 @@ +#!/bin/bash + +echo ">>> Pushing images..." + +export DOCKER_CLI_EXPERIMENTAL=enabled + +declare -A annotations=( + [amd64]="--os linux --arch amd64" + [arm32v6]="--os linux --arch arm --variant v6" + [arm32v7]="--os linux --arch arm --variant v7" + [arm64v8]="--os linux --arch arm64 --variant v8" +) + +source ./hooks/arches.sh + +set -ex + +declare -A images +for arch in ${arches[@]}; do + images[$arch]="${DOCKER_REPO}:${DOCKER_TAG}-${arch}" +done + +# Push the images that were just built; manifest list creation fails if the +# images (manifests) referenced don't already exist in the Docker registry. +for image in "${images[@]}"; do + docker push "${image}" +done + +manifest_lists=("${DOCKER_REPO}:${DOCKER_TAG}") + +# If the Docker tag starts with a version number, assume the latest release is +# being pushed. Add an extra manifest (`latest-release` or `alpine-release`, +# as appropriate) to make it easier to track the latest release. +if [[ "${DOCKER_TAG}" =~ ^[0-9]+\.[0-9]+\.[0-9]+ ]]; then + if [[ "${DOCKER_TAG}" == *alpine ]]; then + manifest_lists+=(${DOCKER_REPO}:alpine-release) + else + manifest_lists+=(${DOCKER_REPO}:latest-release) + fi +fi + +for manifest_list in "${manifest_lists[@]}"; do + # Create the (multi-arch) manifest list of arch-specific images. + docker manifest create ${manifest_list} ${images[@]} + + # Make sure each image manifest is annotated with the correct arch info. + # Docker does not auto-detect the arch of each cross-compiled image, so + # everything would appear as `linux/amd64` otherwise. + for arch in "${arches[@]}"; do + docker manifest annotate ${annotations[$arch]} ${manifest_list} ${images[$arch]} + done + + # Push the manifest list. + docker manifest push --purge ${manifest_list} +done |