|
|
|
#!/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 when needed..."
|
|
|
|
|
|
|
|
# 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
|
|
|
|
#
|
|
|
|
if ! timeout 5 bash -c 'cat < /dev/null > /dev/tcp/localhost/5000'; then
|
|
|
|
# defaults to port 5000
|
|
|
|
docker run -d --name registry --network host registry:2
|
|
|
|
fi
|
|
|
|
|
|
|
|
# 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
|