mirror of
https://github.com/dani-garcia/bitwarden_rs
synced 2024-11-22 09:55:57 +01:00
5633b6ac94
The bitwarden_rs code is still cross-compiled exactly as before, but Docker Buildx is used to rewrite the resulting Docker images with correct platform metadata (reflecting the target platform instead of the build platform). Buildx also now handles building and pushing the multi-arch manifest lists.
139 lines
4.9 KiB
Bash
Executable File
139 lines
4.9 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
source ./hooks/arches.sh
|
|
|
|
export DOCKER_CLI_EXPERIMENTAL=enabled
|
|
|
|
# Join a list of args with a single char.
|
|
# Ref: https://stackoverflow.com/a/17841619
|
|
join() { local IFS="$1"; shift; echo "$*"; }
|
|
|
|
set -ex
|
|
|
|
echo ">>> Starting local Docker registry..."
|
|
|
|
# Docker Buildx's `docker-container` driver is needed for multi-platform
|
|
# builds, but it can't access existing images on the Docker host (like the
|
|
# cross-compiled ones we just built). Those images first need to be pushed to
|
|
# a registry -- Docker Hub could be used, but since it's not trivial to clean
|
|
# up those intermediate images on Docker Hub, it's easier to just run a local
|
|
# Docker registry, which gets cleaned up automatically once the build job ends.
|
|
#
|
|
# https://docs.docker.com/registry/deploying/
|
|
# https://hub.docker.com/_/registry
|
|
#
|
|
# Use host networking so the buildx container can access the registry via
|
|
# localhost.
|
|
#
|
|
docker run -d --name registry --network host registry:2 # defaults to port 5000
|
|
|
|
# Docker Hub sets a `DOCKER_REPO` env var with the format `index.docker.io/user/repo`.
|
|
# Strip the registry portion to construct a local repo path for use in `Dockerfile.buildx`.
|
|
LOCAL_REGISTRY="localhost:5000"
|
|
REPO="${DOCKER_REPO#*/}"
|
|
LOCAL_REPO="${LOCAL_REGISTRY}/${REPO}"
|
|
|
|
echo ">>> Pushing images to local registry..."
|
|
|
|
for arch in ${arches[@]}; do
|
|
docker_image="${DOCKER_REPO}:${DOCKER_TAG}-${arch}"
|
|
local_image="${LOCAL_REPO}:${DOCKER_TAG}-${arch}"
|
|
docker tag "${docker_image}" "${local_image}"
|
|
docker push "${local_image}"
|
|
done
|
|
|
|
echo ">>> Setting up Docker Buildx..."
|
|
|
|
# Same as earlier, use host networking so the buildx container can access the
|
|
# registry via localhost.
|
|
#
|
|
# Ref: https://github.com/docker/buildx/issues/94#issuecomment-534367714
|
|
#
|
|
docker buildx create --name builder --use --driver-opt network=host
|
|
|
|
echo ">>> Running Docker Buildx..."
|
|
|
|
tags=("${DOCKER_REPO}:${DOCKER_TAG}")
|
|
|
|
# If the Docker tag starts with a version number, assume the latest release
|
|
# is being pushed. Add an extra tag (`latest` or `alpine`, as appropriate)
|
|
# to make it easier for users to track the latest release.
|
|
if [[ "${DOCKER_TAG}" =~ ^[0-9]+\.[0-9]+\.[0-9]+ ]]; then
|
|
if [[ "${DOCKER_TAG}" == *alpine ]]; then
|
|
tags+=(${DOCKER_REPO}:alpine)
|
|
else
|
|
tags+=(${DOCKER_REPO}:latest)
|
|
fi
|
|
fi
|
|
|
|
tag_args=()
|
|
for tag in "${tags[@]}"; do
|
|
tag_args+=(--tag "${tag}")
|
|
done
|
|
|
|
# Docker Buildx takes a list of target platforms (OS/arch/variant), so map
|
|
# the arch list to a platform list (assuming the OS is always `linux`).
|
|
declare -A arch_to_platform=(
|
|
[amd64]="linux/amd64"
|
|
[armv6]="linux/arm/v6"
|
|
[armv7]="linux/arm/v7"
|
|
[arm64]="linux/arm64"
|
|
)
|
|
platforms=()
|
|
for arch in ${arches[@]}; do
|
|
platforms+=("${arch_to_platform[$arch]}")
|
|
done
|
|
platforms="$(join "," "${platforms[@]}")"
|
|
|
|
# Run the build, pushing the resulting images and multi-arch manifest list to
|
|
# Docker Hub. The Dockerfile is read from stdin to avoid sending any build
|
|
# context, which isn't needed here since the actual cross-compiled images
|
|
# have already been built.
|
|
docker buildx build \
|
|
--network host \
|
|
--build-arg LOCAL_REPO="${LOCAL_REPO}" \
|
|
--build-arg DOCKER_TAG="${DOCKER_TAG}" \
|
|
--platform "${platforms}" \
|
|
"${tag_args[@]}" \
|
|
--push \
|
|
- < ./docker/Dockerfile.buildx
|
|
|
|
# Add an extra arch-specific tag for `arm32v6`; Docker can't seem to properly
|
|
# auto-select that image on ARMv6 platforms like Raspberry Pi 1 and Zero
|
|
# (https://github.com/moby/moby/issues/41017).
|
|
#
|
|
# Note that we use `arm32v6` instead of `armv6` to be consistent with the
|
|
# existing bitwarden_rs tags, which adhere to the naming conventions of the
|
|
# Docker per-architecture repos (e.g., https://hub.docker.com/u/arm32v6).
|
|
# Unfortunately, these per-arch repo names aren't always consistent with the
|
|
# corresponding platform (OS/arch/variant) IDs, particularly in the case of
|
|
# 32-bit ARM arches (e.g., `linux/arm/v6` is used, not `linux/arm32/v6`).
|
|
#
|
|
# TODO: It looks like this issue should be fixed starting in Docker 20.10.0,
|
|
# so this step can be removed once fixed versions are in wider distribution.
|
|
#
|
|
# Tags:
|
|
#
|
|
# testing => testing-arm32v6
|
|
# testing-alpine => <ignored>
|
|
# x.y.z => x.y.z-arm32v6, latest-arm32v6
|
|
# x.y.z-alpine => <ignored>
|
|
#
|
|
if [[ "${DOCKER_TAG}" != *alpine ]]; then
|
|
image="${DOCKER_REPO}":"${DOCKER_TAG}"
|
|
|
|
# Fetch the multi-arch manifest list and find the digest of the armv6 image.
|
|
filter='.manifests|.[]|select(.platform.architecture=="arm" and .platform.variant=="v6")|.digest'
|
|
digest="$(docker manifest inspect "${image}" | jq -r "${filter}")"
|
|
|
|
# Pull the armv6 image by digest, retag it, and repush it.
|
|
docker pull "${DOCKER_REPO}"@"${digest}"
|
|
docker tag "${DOCKER_REPO}"@"${digest}" "${image}"-arm32v6
|
|
docker push "${image}"-arm32v6
|
|
|
|
if [[ "${DOCKER_TAG}" =~ ^[0-9]+\.[0-9]+\.[0-9]+ ]]; then
|
|
docker tag "${image}"-arm32v6 "${DOCKER_REPO}:latest"-arm32v6
|
|
docker push "${DOCKER_REPO}:latest"-arm32v6
|
|
fi
|
|
fi
|