aboutsummaryrefslogtreecommitdiff
path: root/hooks
diff options
context:
space:
mode:
authorJeremy Lin <[email protected]>2020-06-10 02:01:41 -0700
committerJeremy Lin <[email protected]>2020-07-15 20:03:34 -0700
commit4559e85daa31afb5120c5320760a708f2e5ea862 (patch)
tree3c3eb9292c51338e2d30e76774a47273b60c7796 /hooks
parentbbef332e25f2e9045c70d7219d7d7f1a38cda316 (diff)
downloadvaultwarden-4559e85daa31afb5120c5320760a708f2e5ea862.tar.gz
vaultwarden-4559e85daa31afb5120c5320760a708f2e5ea862.zip
Multi-arch image support
Diffstat (limited to 'hooks')
-rw-r--r--hooks/README.md19
-rw-r--r--hooks/arches.sh30
-rwxr-xr-xhooks/build14
-rwxr-xr-xhooks/push55
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