You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							138 lines
						
					
					
						
							4.9 KiB
						
					
					
				
			
		
		
		
			
			
			
		
		
	
	
							138 lines
						
					
					
						
							4.9 KiB
						
					
					
				
								#!/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 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
							 | 
						|
								
							 |