147 lines
5.3 KiB
Bash
Executable File
147 lines
5.3 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.
|
|
#
|
|
# First check if there already is a registry container running, else skip it.
|
|
# This will only happen either locally or running it via Github Actions
|
|
#
|
|
docker start registry > /dev/null 2>&1 || 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
|
|
#
|
|
# Check if there already is a builder running, else skip this and use the existing.
|
|
# This will only happen either locally or running it via Github Actions
|
|
#
|
|
if ! docker buildx inspect builder > /dev/null 2>&1 ; then
|
|
docker buildx create --name builder --use --driver-opt network=host
|
|
fi
|
|
|
|
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 vaultwarden 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
|