revert buildx bake to bash for-loops

This commit is contained in:
humanoid2050 2023-03-25 15:03:08 -04:00
parent adf227fc48
commit 678b9b485d
12 changed files with 138 additions and 298 deletions

View file

@ -4,12 +4,12 @@ jobs:
vmImage: ubuntu-22.04
strategy:
matrix:
amd64:
DOCKER_ARCH: amd64
arm32v6:
DOCKER_ARCH: arm32v6
arm64v8:
DOCKER_ARCH: arm64v8
amd64:
DOCKER_ARCH: amd64
# The default timeout of 60 minutes is a little low for compiling
# cryptography on ARM architectures.
timeoutInMinutes: 180
@ -32,24 +32,28 @@ jobs:
path: $(Build.ArtifactStagingDirectory)
artifact: docker_$(DOCKER_ARCH)
displayName: Store Docker artifact
- job: docker_run
- job: docker_test
dependsOn: docker_build
pool:
vmImage: ubuntu-22.04
strategy:
matrix:
arm32v6:
DOCKER_ARCH: arm32v6
arm64v8:
DOCKER_ARCH: arm64v8
amd64:
DOCKER_ARCH: amd64
steps:
- task: DownloadPipelineArtifact@2
inputs:
artifact: docker_amd64
artifact: docker_$(DOCKER_ARCH)
path: $(Build.SourcesDirectory)
displayName: Retrieve Docker images
- bash: set -e && docker load --input $(Build.SourcesDirectory)/images.tar
displayName: Load Docker images
- bash: |
set -ex
DOCKER_IMAGES=$(docker images --filter reference='*/certbot' --filter reference='*/dns-*' --format '{{.Repository}}:{{.Tag}}')
for DOCKER_IMAGE in ${DOCKER_IMAGES}
do docker run --rm "${DOCKER_IMAGE}" plugins --prepare
done
set -e && tools/docker/test.sh $(dockerTag) $DOCKER_ARCH
displayName: Run integration tests for Docker images
- job: installer_build
pool:

View file

@ -32,12 +32,12 @@ stages:
vmImage: ubuntu-22.04
strategy:
matrix:
amd64:
DOCKER_ARCH: amd64
arm32v6:
DOCKER_ARCH: arm32v6
arm64v8:
DOCKER_ARCH: arm64v8
amd64:
DOCKER_ARCH: amd64
steps:
- task: DownloadPipelineArtifact@2
inputs:
@ -51,7 +51,7 @@ stages:
command: login
containerRegistry: docker-hub
displayName: Login to Docker Hub
- bash: set -e && tools/docker/deploy_by_arch.sh $(dockerTag) $DOCKER_ARCH
- bash: set -e && tools/docker/deploy_images.sh $(dockerTag) $DOCKER_ARCH
displayName: Deploy the Docker images by architecture
- job: publish_docker_multiarch
dependsOn: publish_docker_by_arch
@ -63,5 +63,5 @@ stages:
command: login
containerRegistry: docker-hub
displayName: Login to Docker Hub
- bash: set -e && tools/docker/deploy_multiarch.sh $(dockerTag)
- bash: set -e && tools/docker/deploy_manifests.sh $(dockerTag) all
displayName: Deploy the Docker multiarch manifests

View file

@ -9,4 +9,3 @@
.tox
venv
docs
.docker_cache

1
.gitignore vendored
View file

@ -40,7 +40,6 @@ tags
# docker files
.docker
.docker_cache
# certbot tests
.certbot_test_workspace

View file

@ -20,21 +20,21 @@ DNS plugin Docker images to Docker Hub.
High-level behavior
-------------------
Running `./build.sh all` causes the Docker images to be built for all
supported architectures. The generated images are stored in a docker
cache backed by the local filesystem.
Running `./build.sh <TAG> all` causes the Docker images to be built for all
supported architectures. The generated images are stored in the local docker image cache.
Running `./test.sh all` either loads images from the filesystem cache
or generates said images on demand, and runs a test command to validate
the image contents.
Running `./test.sh <TAG> all` loads images from the docker image cache
and runs a test command to validate the image contents.
Running `./deploy.sh <TAG> all` will push the previously generated images
Running `./deploy_images.sh <TAG> all` will push the previously generated images
to Docker Hub. The <TAG> argument is an identifier applied to all docker
images and manifests. it may be something like `nightly` or `v2.3.2`. If
the tag is a version stamp greater than v2.0.0, then a `latest` tag will
also be generated and pushed to the docker hub repo. The per-architecture
images are accessible through the corresponding multi-arch manifest by
using the `docker pull --platform <platform spec> <IMAGE>:<TAG>` command.
the tag is a version stamp greater than `v2.0.0`, then a `latest` tag will
also be generated and pushed to the docker hub repo.
Running `./deploy_manifests.sh <TAG> all` will add multiarch manifests to
Docker Hub. This command assumes that `./deploy_images.sh <TAG> all` has
been previously run with the same tag.
Configuration
-------------

View file

@ -1,9 +1,8 @@
#!/bin/bash
set -euxo pipefail
# This script builds certbot docker and certbot dns plugins docker using the
# local Certbot files. Results are stored in a docker cache on the local
# filesystem
# This script builds docker images for certbot and each dns plugin from the
# local Certbot source files. Results are stored in the docker image cache
# Usage:
# ./build.sh <tag> all
@ -38,38 +37,36 @@ trap Cleanup EXIT
# Create the builder
CreateBuilder
rm -rf .docker_cache
BuildAll() {
docker buildx bake -f ${WORK_DIR}/docker-bake.hcl \
--builder certbot_builder \
--set *.cache-to=type=local,dest=.docker_cache,mode=min \
build-all
}
# --progress plain
BuildAndCacheByArch() {
export TAG_ARCH=$1
docker buildx bake -f ${WORK_DIR}/docker-bake.hcl \
--builder certbot_builder \
--set *.platform=$(arch2platform ${TAG_ARCH}) \
--set *.cache-from=type=local,src=.docker_cache \
build-all --load
TAG_ARCH=$1
docker buildx build --target certbot --builder certbot_builder \
--platform $(arch2platform $TAG_ARCH) \
-f "${WORK_DIR}/Dockerfile" \
-t "${REGISTRY_SPEC}certbot:${TAG_ARCH}-${TAG_VER}" \
--load \
.
for plugin in "${CERTBOT_PLUGINS[@]}"; do
docker buildx build --target certbot-plugin --builder certbot_builder \
--platform $(arch2platform $TAG_ARCH) \
--build-context plugin-src="${REPO_ROOT}/certbot-${plugin}" \
-f "${WORK_DIR}/Dockerfile" \
-t "${REGISTRY_SPEC}${plugin}:${TAG_ARCH}-${TAG_VER}" \
--load \
.
done
}
# If the request was for all, max out the buildkit parallelization logic
if [ "$ARCH_LIST" = "all" ]; then
BuildAll
fi
# split arch list into an array for per-arch saving of images to the docker image cache
# In principle, there is a better way to do with by using `docker buildx back`
# instead of a for-loop. However, issues have been found in the results
# of such a build. See git commit adf227fc4.
# split arch list into an array for per-arch image building and saving
IFS_OLD="$IFS"
IFS=","
read -ra REQUESTED_ARCH_ARRAY <<< $(InterpretArchRequest "$ARCH_LIST")
IFS="$IFS_OLD"
for ARCH in "${REQUESTED_ARCH_ARRAY[@]}"; do
# If the build was already done by BuildAll, then the existing image is pulled
# from the build cache. Otherwise, it gets built on demand here.
# Either way, images get tagged and loaded to the docker image cache
# for use by test and deploy
BuildAndCacheByArch $ARCH
done

View file

@ -1,47 +1,34 @@
#!/bin/bash
set -euxo pipefail
# This script builds certbot docker and certbot dns plugins docker using the
# local Certbot files.
# This script takes docker images in the local docker cache and pushes them to
# a registry.
# Usage:
# ./deploy.sh <TAG> all
# ./deploy.sh <TAG> <architectures>
# ./deploy_images.sh <TAG> all
# ./deploy_images.sh <TAG> <architectures>
# The <TAG> argument is an identifier applied to all docker images and manifests.
# It may be something like `nightly` or `v2.3.2`. If the tag is a version
# stamp greater than v2.0.0, then a `latest` tag will also be generated and
# pushed to the docker hub repo.
# The argument "all" will build all know architectures. Alternatively, the
# The argument "all" will push all known architectures. Alternatively, the
# user may provide a comma separated list of architectures drawn from the
# known architectures. Know architectures include amd64, arm32v6, and arm64v8.
source "$(realpath $(dirname ${BASH_SOURCE[0]}))/lib/common"
TAG_BASE="$1"
if [ -z "$TAG_BASE" ]; then
TAG_VER="$1"
if [ -z "$TAG_VER" ]; then
echo "We cannot tag Docker images with an empty string!" >&2
exit 1
fi
REQUESTED_ARCH_LIST=$(InterpretArchRequest "$2")
PLATFORM_SPEC=$(archList2platformList "${REQUESTED_ARCH_LIST[@]}")
#jump to root, matching popd handed by Cleanup on EXIT via trap
pushd "${REPO_ROOT}"
# Set trap here, as the popd won't work as expected if invoked prior to pushd
trap Cleanup EXIT
CreateBuilder
# Helper function to generate latest tag if appropriate
LatestTag() {
TAG_BASE=$1
if [[ "${TAG_BASE}" =~ ^v([2-9]|[1-9][0-9]+)\.[0-9]+\.[0-9]+$ ]]; then
echo "-t ${DOCKER_REPO}:latest"
fi
}
trap popd EXIT
REGISTRY_SPEC="${DOCKER_HUB_ORG}/"
@ -50,25 +37,15 @@ DeployImage() {
TAG_ARCH=$2
TAG_VER=$3
docker push "${REGISTRY_SPEC}${IMAGE_NAME}:${TAG_ARCH}-${TAG_VER}"
if [[ "${TAG_BASE}" =~ ^v([2-9]|[1-9][0-9]+)\.[0-9]+\.[0-9]+$ ]]; then
docker tag "${REGISTRY_SPEC}${IMAGE_NAME}:${TAG_ARCH}-${TAG_VER}" "${REGISTRY_SPEC}${IMAGE_NAME}:latest"
if [[ "${TAG_VER}" =~ ^v([2-9]|[1-9][0-9]+)\.[0-9]+\.[0-9]+$ ]]; then
docker tag "${REGISTRY_SPEC}${IMAGE_NAME}:${TAG_ARCH}-${TAG_VER}" "${REGISTRY_SPEC}${IMAGE_NAME}:${TAG_ARCH}-latest"
fi
}
DeployManifest() {
IMAGE_NAME=$1
local IFS=","
read -ra REQUESTED_ARCH_ARRAY <<< $(InterpretArchRequest "$2")
TAG_VER=$3
SRC_IMAGES=""
for TAG_ARCH in "${REQUESTED_ARCH_ARRAY[@]}"; do
SRC_IMAGES+="${REGISTRY_SPEC}${IMAGE_NAME}:${TAG_ARCH}-${TAG_VER} "
done
docker buildx imagetools create -t "${REGISTRY_SPEC}${IMAGE_NAME}:${TAG_VER} $SRC_IMAGES"
}
IFS_OLD="$IFS"
IFS=","
read -ra REQUESTED_ARCH_ARRAY <<< $(InterpretArchRequest "$2")
IFS="$IFS_OLD"
for TAG_ARCH in "${REQUESTED_ARCH_ARRAY[@]}"; do
DeployImage certbot $TAG_ARCH $TAG_VER
for PLUGIN in "${CERTBOT_PLUGINS[@]}"; do

View file

@ -0,0 +1,62 @@
#!/bin/bash
set -euxo pipefail
# This script generates multi-arch manifests for images previously pushed to
# a registry vis deploy_images.sh
# Usage:
# ./deploy_manifest.sh <TAG> all
# ./deploy_manifest.sh <TAG> <architectures>
# The <TAG> argument is an identifier applied to all docker images and manifests.
# It may be something like `nightly` or `v2.3.2`. If the tag is a version
# stamp greater than v2.0.0, then a `latest` tag will also be generated and
# pushed to the docker hub repo.
# The argument "all" will push all know architectures. Alternatively, the
# user may provide a comma separated list of architectures drawn from the
# known architectures. Know architectures include amd64, arm32v6, and arm64v8.
source "$(realpath $(dirname ${BASH_SOURCE[0]}))/lib/common"
TAG_VER="$1"
if [ -z "$TAG_VER" ]; then
echo "We cannot tag Docker images with an empty string!" >&2
exit 1
fi
REQUESTED_ARCH_LIST=$(InterpretArchRequest "$2")
#jump to root, matching popd handed by Cleanup on EXIT via trap
pushd "${REPO_ROOT}"
# Set trap here, as the popd won't work as expected if invoked prior to pushd
trap popd EXIT
REGISTRY_SPEC="${DOCKER_HUB_ORG}/"
DeployManifest() {
IMAGE_NAME=$1
local IFS=","
read -ra REQUESTED_ARCH_ARRAY <<< ${REQUESTED_ARCH_LIST}
TAG_VER=$3
IFS=" "
SRC_IMAGES=""
for TAG_ARCH in "${REQUESTED_ARCH_ARRAY[@]}"; do
SRC_IMAGES+="${REGISTRY_SPEC}${IMAGE_NAME}:${TAG_ARCH}-${TAG_VER} "
done
docker buildx imagetools create -t ${REGISTRY_SPEC}${IMAGE_NAME}:${TAG_VER} $SRC_IMAGES
if [[ "${TAG_VER}" =~ ^v([2-9]|[1-9][0-9]+)\.[0-9]+\.[0-9]+$ ]]; then
docker buildx imagetools create -t ${REGISTRY_SPEC}${IMAGE_NAME}:latest $SRC_IMAGES
fi
}
DeployManifest certbot ${REQUESTED_ARCH_LIST} $TAG_VER
for PLUGIN in "${CERTBOT_PLUGINS[@]}"; do
DeployManifest $PLUGIN ${REQUESTED_ARCH_LIST} $TAG_VER
done

View file

@ -1,146 +0,0 @@
group "build-all" {
targets = ["certbot",
"dns-dnsmadeeasy",
"dns-dnsimple",
"dns-ovh",
"dns-cloudflare",
"dns-digitalocean",
"dns-google",
"dns-luadns",
"dns-nsone",
"dns-rfc2136",
"dns-route53",
"dns-gehirn",
"dns-linode",
"dns-sakuracloud"]
}
variable "WORK_DIR" {
default = "tools/docker"
}
variable "TAG_VER" {
default = "test"
}
variable "TAG_ARCH" {
default = "auto"
}
variable "REGISTRY_SPEC" {
// if provided, this should include the trailing slash (e.g. "certbot/)
default = ""
}
target "certbot" {
dockerfile = "${WORK_DIR}/Dockerfile"
target = "certbot"
tags = ["${REGISTRY_SPEC}certbot:${TAG_ARCH}-${TAG_VER}"]
platforms = ["linux/amd64", "linux/arm64/v8", "linux/arm/v6"]
}
target "dns-dnsmadeeasy" {
dockerfile = "${WORK_DIR}/Dockerfile"
target = "certbot-plugin"
contexts = {plugin-src = "certbot-dns-dnsmadeeasy"}
tags = ["${REGISTRY_SPEC}dns-dnsmadeeasy:${TAG_ARCH}-${TAG_VER}"]
platforms = ["linux/amd64", "linux/arm64/v8", "linux/arm/v6"]
}
target "dns-dnsimple" {
dockerfile = "${WORK_DIR}/Dockerfile"
target = "certbot-plugin"
contexts = {plugin-src = "certbot-dns-dnsimple"}
tags = ["${REGISTRY_SPEC}dns-dnsimple:${TAG_ARCH}-${TAG_VER}"]
platforms = ["linux/amd64", "linux/arm64/v8", "linux/arm/v6"]
}
target "dns-ovh" {
dockerfile = "${WORK_DIR}/Dockerfile"
target = "certbot-plugin"
contexts = {plugin-src = "certbot-dns-ovh"}
tags = ["${REGISTRY_SPEC}dns-ovh:${TAG_ARCH}-${TAG_VER}"]
platforms = ["linux/amd64", "linux/arm64/v8", "linux/arm/v6"]
}
target "dns-cloudflare" {
dockerfile = "${WORK_DIR}/Dockerfile"
target = "certbot-plugin"
contexts = {plugin-src = "certbot-dns-cloudflare"}
tags = ["${REGISTRY_SPEC}dns-cloudflare:${TAG_ARCH}-${TAG_VER}"]
platforms = ["linux/amd64", "linux/arm64/v8", "linux/arm/v6"]
}
target "dns-digitalocean" {
dockerfile = "${WORK_DIR}/Dockerfile"
target = "certbot-plugin"
contexts = {plugin-src = "certbot-dns-digitalocean"}
tags = ["${REGISTRY_SPEC}dns-digitalocean:${TAG_ARCH}-${TAG_VER}"]
platforms = ["linux/amd64", "linux/arm64/v8", "linux/arm/v6"]
}
target "dns-google" {
dockerfile = "${WORK_DIR}/Dockerfile"
target = "certbot-plugin"
contexts = {plugin-src = "certbot-dns-google"}
tags = ["${REGISTRY_SPEC}dns-google:${TAG_ARCH}-${TAG_VER}"]
platforms = ["linux/amd64", "linux/arm64/v8", "linux/arm/v6"]
}
target "dns-luadns" {
dockerfile = "${WORK_DIR}/Dockerfile"
target = "certbot-plugin"
contexts = {plugin-src = "certbot-dns-luadns"}
tags = ["${REGISTRY_SPEC}dns-luadns:${TAG_ARCH}-${TAG_VER}"]
platforms = ["linux/amd64", "linux/arm64/v8", "linux/arm/v6"]
}
target "dns-nsone" {
dockerfile = "${WORK_DIR}/Dockerfile"
target = "certbot-plugin"
contexts = {plugin-src = "certbot-dns-nsone"}
tags = ["${REGISTRY_SPEC}dns-nsone:${TAG_ARCH}-${TAG_VER}"]
platforms = ["linux/amd64", "linux/arm64/v8", "linux/arm/v6"]
}
target "dns-rfc2136" {
dockerfile = "${WORK_DIR}/Dockerfile"
target = "certbot-plugin"
contexts = {plugin-src = "certbot-dns-rfc2136"}
tags = ["${REGISTRY_SPEC}dns-rfc2136:${TAG_ARCH}-${TAG_VER}"]
platforms = ["linux/amd64", "linux/arm64/v8", "linux/arm/v6"]
}
target "dns-route53" {
dockerfile = "${WORK_DIR}/Dockerfile"
target = "certbot-plugin"
contexts = {plugin-src = "certbot-dns-route53"}
tags = ["${REGISTRY_SPEC}dns-route53:${TAG_ARCH}-${TAG_VER}"]
platforms = ["linux/amd64", "linux/arm64/v8", "linux/arm/v6"]
}
target "dns-gehirn" {
dockerfile = "${WORK_DIR}/Dockerfile"
target = "certbot-plugin"
contexts = {plugin-src = "certbot-dns-gehirn"}
tags = ["${REGISTRY_SPEC}dns-gehirn:${TAG_ARCH}-${TAG_VER}"]
platforms = ["linux/amd64", "linux/arm64/v8", "linux/arm/v6"]
}
target "dns-linode" {
dockerfile = "${WORK_DIR}/Dockerfile"
target = "certbot-plugin"
contexts = {plugin-src = "certbot-dns-linode"}
tags = ["${REGISTRY_SPEC}dns-linode:${TAG_ARCH}-${TAG_VER}"]
platforms = ["linux/amd64", "linux/arm64/v8", "linux/arm/v6"]
}
target "dns-sakuracloud" {
dockerfile = "${WORK_DIR}/Dockerfile"
target = "certbot-plugin"
contexts = {plugin-src = "certbot-dns-sakuracloud"}
tags = ["${REGISTRY_SPEC}dns-sakuracloud:${TAG_ARCH}-${TAG_VER}"]
platforms = ["linux/amd64", "linux/arm64/v8", "linux/arm/v6"]
}

View file

@ -57,37 +57,6 @@ arch2platform() {
esac
}
# Parses the requested architecture string and sets ALL_REQUESTED_ARCH to
# result.
# Usage: archList2platformList [arch-list]
# where [arch-list] is a comma separated list of architectures
# as interpreted by the arch2platform function
archList2platformList() {
local IFS=","
REQUESTED_ARCH="${1}"
# Handle the special value "all"
if [[ "${REQUESTED_ARCH}" == "all" ]]; then
# Recursive call using the list of all known architectures cast to
# comma separated list
archList2platformList "${ALL_TARGET_ARCH[*]}"
return 0
fi
# Convert comma separated list to array of strings
read -ra REQUESTED_ARCH_LIST <<< "$REQUESTED_ARCH"
# Convert each string to the corresponding docker platform specification.
# The internal call to arch2platform might return an error if the arch is
# not recognized, crashing the process (`set -exo` called at beginning of
# script)
PLATFORM_LIST=()
for TARGET_ARCH in "${REQUESTED_ARCH_LIST[@]}"; do
PLATFORM_LIST+=($(arch2platform "$TARGET_ARCH"))
# fail if lookup in subshell failed
if [ $? -ne 0 ]; then exit 1; fi
done
# Return a string made from the array of docker platform spedifications
echo "${PLATFORM_LIST[*]}"
}
# Interpret the user input. Expands "all" to a list of known arches,
# and validates arches if provided with a list
@ -121,6 +90,10 @@ Cleanup() {
popd
}
InstallMultiarchSupport() {
docker run --privileged --rm tonistiigi/binfmt --install all
}
# Function to create a docker builder using the buildkit docker-container
# driver
CreateBuilder() {
@ -129,34 +102,5 @@ CreateBuilder() {
# create the builder instance
docker buildx create --name certbot_builder --driver docker-container --driver-opt=network=host --bootstrap --use
# add binfmt tools to the docker environment, with integration into the new builder instance
docker run --privileged --rm tonistiigi/binfmt --install all
InstallMultiarchSupport
}
# Helper function to generate common args passed to `docker buildx build`
# calls. This makes sure things are consisten between top level scripts.
# Base Certbot version
StandardCertbotBuildArgs() {
PLATFORM_SPEC=$1
cat << EOF
--platform ${PLATFORM_SPEC} \
-f ${WORK_DIR}/Dockerfile \
--target certbot \
--cache-from=type=local,src=${DOCKER_CACHE}/certbot
EOF
}
# Helper function to generate common args passed to `docker buildx build`
# calls. This makes sure things are consisten between top level scripts.
# Certbot Plugin version
StandardPluginBuildArgs() {
PLATFORM_SPEC=$1
PLUGIN=$2
cat << EOF
--platform ${PLATFORM_SPEC} \
-f ${WORK_DIR}/Dockerfile \
--target certbot-plugin \
--build-context plugin-src=${REPO_ROOT}/certbot-${PLUGIN} \
--cache-from=type=local,src=${DOCKER_CACHE}/certbot \
--cache-from=type=local,src=${DOCKER_CACHE}/${PLUGIN}
EOF
}

4
tools/docker/run.sh Executable file
View file

@ -0,0 +1,4 @@
set -euxo pipefail
while true; do
remove_untagged_docker.sh || ./build.sh v2.3.1 all && ./test.sh v2.3.1 all
done

View file

@ -33,9 +33,9 @@ IFS="$IFS_OLD"
pushd "${REPO_ROOT}"
# Set trap here, as the popd won't work as expected if invoked prior to pushd
trap Cleanup EXIT
trap popd EXIT
CreateBuilder
InstallMultiarchSupport
REGISTRY_SPEC="${DOCKER_HUB_ORG}/"