ci: improve multi-arch builds

This commit is contained in:
sebthom 2025-05-26 20:09:45 +02:00
parent 518ee6962c
commit 7b69551e99
4 changed files with 166 additions and 108 deletions

View File

@ -9,7 +9,7 @@ end_of_line = lf
insert_final_newline = true insert_final_newline = true
trim_trailing_whitespace = true trim_trailing_whitespace = true
indent_style = space indent_style = space
indent_size = 3 indent_size = 2
[*.{bat,cmd}] [*.{bat,cmd}]
end_of_line = crlf end_of_line = crlf

3
.gitignore vendored
View File

@ -35,3 +35,6 @@ nb-configuration.xml
# patch # patch
*.orig *.orig
*.rej *.rej
# nektos/act
.actrc

View File

@ -5,23 +5,30 @@
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
# SPDX-ArtifactOfProjectHomePage: https://github.com/vegardit/docker-gitea-act-runner # SPDX-ArtifactOfProjectHomePage: https://github.com/vegardit/docker-gitea-act-runner
function curl() {
command curl -sSfL --connect-timeout 10 --max-time 30 --retry 3 --retry-all-errors "$@"
}
shared_lib="$(dirname "${BASH_SOURCE[0]}")/.shared" shared_lib="$(dirname "${BASH_SOURCE[0]}")/.shared"
[[ -e $shared_lib ]] || curl "https://raw.githubusercontent.com/vegardit/docker-shared/v1/download.sh?_=$(date +%s)" | bash -s v1 "$shared_lib" || exit 1 [[ -e $shared_lib ]] || curl -sSfL "https://raw.githubusercontent.com/vegardit/docker-shared/v1/download.sh?_=$(date +%s)" | bash -s v1 "$shared_lib" || exit 1
# shellcheck disable=SC1091 # Not following: $shared_lib/lib/build-image-init.sh was not specified as input # shellcheck disable=SC1091 # Not following: $shared_lib/lib/build-image-init.sh was not specified as input
source "$shared_lib/lib/build-image-init.sh" source "$shared_lib/lib/build-image-init.sh"
################################################# #################################################
# specify target image repo/tag # declare image meta
################################################# #################################################
gitea_act_runner_version=${GITEA_ACT_RUNNER_VERSION:-latest} gitea_act_runner_version=${GITEA_ACT_RUNNER_VERSION:-latest}
base_image_name=${DOCKER_BASE_IMAGE:-debian:stable-slim} base_image=${DOCKER_BASE_IMAGE:-debian:stable-slim}
image_repo=${DOCKER_IMAGE_REPO:-vegardit/gitea-act-runner} image_repo=${DOCKER_IMAGE_REPO:-vegardit/gitea-act-runner}
platforms="linux/amd64,linux/arm64/v8,linux/arm/v7"
declare -A image_meta=(
[authors]="Vegard IT GmbH (vegardit.com)"
[title]="$image_repo"
[description]="Docker image based on debian:stable-slim to run Gitea's act_runner as a Docker container"
[source]="$(git config --get remote.origin.url)"
[revision]="$(git rev-parse --short HEAD)"
[version]="$(git rev-parse --short HEAD)"
[created]="$(date -u +'%Y-%m-%dT%H:%M:%SZ')"
)
################################################# #################################################
# resolve gitea act runner version # resolve gitea act runner version
@ -32,38 +39,39 @@ case $gitea_act_runner_version in
esac esac
#################################################
# calculate tags
#################################################
declare -a tags=() declare -a tags=()
tags+=("$image_repo:${DOCKER_IMAGE_TAG_PREFIX:-}$gitea_act_runner_version") tags+=("${DOCKER_IMAGE_TAG_PREFIX:-}$gitea_act_runner_version")
tags+=("$image_repo:${DOCKER_IMAGE_TAG_PREFIX:-}$gitea_act_runner_effective_version") tags+=("${DOCKER_IMAGE_TAG_PREFIX:-}$gitea_act_runner_effective_version")
tag_args=()
for t in "${tags[@]}"; do
tag_args+=( --tag "$t" )
done
image_name=${tags[0]}
################################################# #################################################
# build the image # decide if multi-arch build
################################################# #################################################
log INFO "Building docker image [$image_name]..." if [[ ${DOCKER_PUSH:-} == "true" || ${DOCKER_PUSH_GHCR:-} == "true" ]]; then
if [[ $OSTYPE == "cygwin" || $OSTYPE == "msys" ]]; then build_multi_arch="true"
project_root=$(cygpath -w "$project_root")
fi fi
#################################################
# prepare docker
#################################################
run_step -- docker version
# https://github.com/docker/buildx/#building-multi-platform-images # https://github.com/docker/buildx/#building-multi-platform-images
set -x run_step -- docker buildx version # ensures buildx is enabled
docker --version
export DOCKER_BUILDKIT=1 export DOCKER_BUILDKIT=1
export DOCKER_CLI_EXPERIMENTAL=1 # prevents "docker: 'buildx' is not a docker command." export DOCKER_CLI_EXPERIMENTAL=1 # prevents "docker: 'buildx' is not a docker command." in older Docker versions
# Register QEMU emulators for all architectures so Docker can run and build multi-arch images if [[ ${build_multi_arch:-} == "true" ]]; then
# Use a temporary local registry to work around Docker/Buildx/BuildKit quirks,
# enabling us to build/test multiarch images locally before pushing.
run_step -- start_docker_registry LOCAL_REGISTRY
# Register QEMU emulators so Docker can run and build multi-arch images
run_step "Install QEMU emulators" -- \
docker run --privileged --rm ghcr.io/dockerhub-mirror/tonistiigi__binfmt --install all docker run --privileged --rm ghcr.io/dockerhub-mirror/tonistiigi__binfmt --install all
fi
# https://docs.docker.com/build/buildkit/configure/#resource-limiting # https://docs.docker.com/build/buildkit/configure/#resource-limiting
echo " echo "
@ -71,47 +79,71 @@ echo "
max-parallelism = 3 max-parallelism = 3
" | sudo tee /etc/buildkitd.toml " | sudo tee /etc/buildkitd.toml
docker buildx version # ensures buildx is enabled builder_name="bx-$(date +%s)-$RANDOM"
docker buildx create --config /etc/buildkitd.toml --use # prevents: error: multiple platforms feature is currently not supported for docker driver. Please switch to a different driver (eg. "docker buildx create --use") run_step "Configure buildx builder" -- docker buildx create \
trap 'docker buildx stop' EXIT --name "$builder_name" \
# shellcheck disable=SC2154,SC2046 # base_layer_cache_key is referenced but not assigned / Quote this to prevent word splitting --bootstrap \
docker buildx build "$project_root" \ --config /etc/buildkitd.toml \
--file "image/Dockerfile" \ --driver-opt network=host `# required for buildx to access the temporary registry` \
--progress=plain \ --driver docker-container \
--pull \ --driver-opt image=ghcr.io/dockerhub-mirror/moby__buildkit:latest
--build-arg INSTALL_SUPPORT_TOOLS="${INSTALL_SUPPORT_TOOLS:-0}" \ trap 'docker buildx rm --force "$builder_name"' EXIT
`# using the current date as value for BASE_LAYER_CACHE_KEY, i.e. the base layer cache (that holds system packages with security updates) will be invalidate once per day` \
--build-arg BASE_LAYER_CACHE_KEY="$base_layer_cache_key" \
--build-arg BASE_IMAGE="$base_image_name" \
--build-arg BUILD_DATE="$(date -u +"%Y-%m-%dT%H:%M:%SZ")" \
--build-arg GIT_BRANCH="${GIT_BRANCH:-$(git rev-parse --abbrev-ref HEAD)}" \
--build-arg GIT_COMMIT_DATE="$(date -d "@$(git log -1 --format='%at')" --utc +'%Y-%m-%d %H:%M:%S UTC')" \
--build-arg GIT_COMMIT_HASH="$(git rev-parse --short HEAD)" \
--build-arg GIT_REPO_URL="$(git config --get remote.origin.url)" \
--build-arg GITEA_ACT_RUNNER_VERSION="$gitea_act_runner_effective_version" \
--build-arg FLAVOR="$DOCKER_IMAGE_FLAVOR" \
$(if [[ ${ACT:-} == "true" || ${DOCKER_PUSH:-} != "true" ]]; then \
echo -n "--load --output type=docker"; \
else \
echo -n "--platform linux/amd64,linux/arm64,linux/arm/v7"; \
fi) \
"${tag_args[@]}" \
$(if [[ ${DOCKER_PUSH:-} == "true" ]]; then echo -n "--push"; fi) \
"$@"
set +x
if [[ ${DOCKER_PUSH:-} == "true" ]]; then
docker image pull "$image_name" #################################################
# build the image
#################################################
image_name=image_repo:${tags[0]}
build_opts=(
--file "image/Dockerfile"
--builder "$builder_name"
--progress=plain
--pull
# using the current date as value for BASE_LAYER_CACHE_KEY, i.e. the base layer cache (that holds system packages with security updates) will be invalidate once per day
--build-arg BASE_LAYER_CACHE_KEY="$base_layer_cache_key"
--build-arg BASE_IMAGE="$base_image"
--build-arg GIT_BRANCH="${GIT_BRANCH:-$(git rev-parse --abbrev-ref HEAD)}"
--build-arg GIT_COMMIT_DATE="$(date -d "@$(git log -1 --format='%at')" --utc +'%Y-%m-%d %H:%M:%S UTC')"
--build-arg GITEA_ACT_RUNNER_VERSION="$gitea_act_runner_effective_version"
--build-arg FLAVOR="$DOCKER_IMAGE_FLAVOR"
--build-arg INSTALL_SUPPORT_TOOLS="${INSTALL_SUPPORT_TOOLS:-0}"
)
for key in "${!image_meta[@]}"; do
build_opts+=(--build-arg "OCI_${key}=${image_meta[$key]}")
if [[ ${build_multi_arch:-} == "true" ]]; then
build_opts+=(--annotation "index:org.opencontainers.image.${key}=${image_meta[$key]}")
fi
done
if [[ ${build_multi_arch:-} == "true" ]]; then
build_opts+=(--push)
build_opts+=(--sbom=true) # https://docs.docker.com/build/metadata/attestations/sbom/#create-sbom-attestations
build_opts+=(--platform "$platforms")
build_opts+=(--tag "$LOCAL_REGISTRY/$image_name")
else
build_opts+=(--output "type=docker,load=true")
build_opts+=(--tag "$image_name")
fi fi
if [[ $OSTYPE == "cygwin" || $OSTYPE == "msys" ]]; then
project_root=$(cygpath -w "$project_root")
fi
run_step "Building docker image [$image_name]..." -- \
docker buildx build "${build_opts[@]}" "$project_root"
################################################# #################################################
# test image # load image into local docker daemon for testing
################################################# #################################################
echo if [[ ${build_multi_arch:-} == "true" ]]; then
log INFO "Testing docker image [$image_name]..." run_step "Load image into local daemon for testing" @@ "
(set -x; docker run --rm "$image_name" act_runner --version) docker pull '$LOCAL_REGISTRY/$image_name';
echo docker tag '$LOCAL_REGISTRY/$image_name' '$image_name'
"
fi
################################################# #################################################
@ -119,21 +151,39 @@ echo
################################################# #################################################
# TODO see https://gitea.com/gitea/act_runner/issues/513 # TODO see https://gitea.com/gitea/act_runner/issues/513
if [[ ${DOCKER_AUDIT_IMAGE:-1} == "1" && $GITEA_ACT_RUNNER_VERSION == "nightly" ]]; then if [[ ${DOCKER_AUDIT_IMAGE:-1} == "1" && $GITEA_ACT_RUNNER_VERSION == "nightly" ]]; then
run_step "Auditing docker image [$image_name]" -- \
bash "$shared_lib/cmd/audit-image.sh" "$image_name" bash "$shared_lib/cmd/audit-image.sh" "$image_name"
fi fi
################################################# #################################################
# push image to ghcr.io # test image
################################################# #################################################
if [[ ${DOCKER_PUSH_GHCR:-} == "true" ]]; then run_step "Testing docker image [$image_name]" -- \
for tag in "${tags[@]}"; do docker run --pull=never --rm "$image_name" act_runner --version
set -x
#################################################
# push image
#################################################
function regctl() {
run_step "regctl ${*}" -- \
docker run --rm \ docker run --rm \
-u "$(id -u):$(id -g)" -e HOME -v "$HOME:$HOME" \ -u "$(id -u):$(id -g)" -e HOME -v "$HOME:$HOME" \
-v /etc/docker/certs.d:/etc/docker/certs.d:ro \ -v /etc/docker/certs.d:/etc/docker/certs.d:ro \
--network host `# required to access the temporary registry` \
ghcr.io/regclient/regctl:latest \ ghcr.io/regclient/regctl:latest \
image copy "$tag" "ghcr.io/$tag" --host "reg=$LOCAL_REGISTRY,tls=disabled" \
set +x "${@}"
}
if [[ ${DOCKER_PUSH:-} == "true" ]]; then
for tag in "${tags[@]}"; do
regctl image copy --referrers "$LOCAL_REGISTRY/$image_name" "docker.io/$image_repo:$tag"
done
fi
if [[ ${DOCKER_PUSH_GHCR:-} == "true" ]]; then
for tag in "${tags[@]}"; do
regctl image copy --referrers "$LOCAL_REGISTRY/$image_name" "ghcr.io/$image_repo:$tag"
done done
fi fi

View File

@ -1,6 +1,5 @@
#syntax=docker/dockerfile:1 #syntax=docker/dockerfile:1
# see https://github.com/moby/buildkit/blob/master/frontend/dockerfile/docs/syntax.md#user-content-syntax # see https://github.com/moby/buildkit/blob/master/frontend/dockerfile/docs/reference.md
# see https://docs.docker.com/build/dockerfile/frontend/
# see https://docs.docker.com/engine/reference/builder/#syntax # see https://docs.docker.com/engine/reference/builder/#syntax
# #
# SPDX-FileCopyrightText: © Vegard IT GmbH (https://vegardit.com) # SPDX-FileCopyrightText: © Vegard IT GmbH (https://vegardit.com)
@ -11,27 +10,24 @@
# https://hub.docker.com/_/debian/tags?name=stable-slim # https://hub.docker.com/_/debian/tags?name=stable-slim
ARG BASE_IMAGE=debian:stable-slim ARG BASE_IMAGE=debian:stable-slim
#############################################################
# build final image
#############################################################
# https://github.com/hadolint/hadolint/wiki/DL3006 Always tag the version of an image explicitly # https://github.com/hadolint/hadolint/wiki/DL3006 Always tag the version of an image explicitly
# hadolint ignore=DL3006 # hadolint ignore=DL3006
FROM ${BASE_IMAGE} FROM ${BASE_IMAGE} as final
LABEL maintainer="Vegard IT GmbH (vegardit.com)"
# https://github.com/hadolint/hadolint/wiki/DL3002 Last USER should not be root
# hadolint ignore=DL3002
USER root
SHELL ["/bin/bash", "-euo", "pipefail", "-c"]
ARG DEBIAN_FRONTEND=noninteractive ARG DEBIAN_FRONTEND=noninteractive
ARG LC_ALL=C ARG LC_ALL=C
SHELL ["/bin/bash", "-euo", "pipefail", "-c"]
ARG INSTALL_SUPPORT_TOOLS=0 ARG INSTALL_SUPPORT_TOOLS=0
ARG BASE_LAYER_CACHE_KEY
ARG UPX_COMPRESS=true ARG UPX_COMPRESS=true
ARG BASE_LAYER_CACHE_KEY
# dood|dind|dind-rootless # dood|dind|dind-rootless
ARG FLAVOR ARG FLAVOR
ARG GITEA_ACT_RUNNER_VERSION ARG GITEA_ACT_RUNNER_VERSION
@ -179,19 +175,6 @@ RUN --mount=type=bind,source=.shared,target=/mnt/shared <<EOF
EOF EOF
ARG BUILD_DATE
ARG GIT_BRANCH
ARG GIT_COMMIT_HASH
ARG GIT_COMMIT_DATE
ARG GIT_REPO_URL
# https://github.com/opencontainers/image-spec/blob/main/annotations.md
LABEL \
org.opencontainers.image.source=$GIT_REPO_URL \
org.opencontainers.image.created=$BUILD_DATE \
org.opencontainers.image.revision=$GIT_COMMIT_HASH \
org.opencontainers.image.vision=$GIT_COMMIT_HASH
# Default configuration: can be overridden at the docker command line # Default configuration: can be overridden at the docker command line
ENV \ ENV \
INIT_SH_FILE='' \ INIT_SH_FILE='' \
@ -211,16 +194,38 @@ ubuntu-20.04:docker://catthehacker/ubuntu:act-20.04' \
GITEA_RUNNER_REGISTRATION_TIMEOUT=30\ GITEA_RUNNER_REGISTRATION_TIMEOUT=30\
GITEA_RUNNER_REGISTRATION_RETRY_INTERVAL=5s GITEA_RUNNER_REGISTRATION_RETRY_INTERVAL=5s
RUN <<EOF ARG OCI_authors
ARG OCI_title
ARG OCI_description
ARG OCI_source
ARG OCI_revision
ARG OCI_version
ARG OCI_created
ARG GIT_BRANCH
ARG GIT_COMMIT_DATE
# https://github.com/opencontainers/image-spec/blob/main/annotations.md
LABEL \
org.opencontainers.image.title="$OCI_title" \
org.opencontainers.image.description="$OCI_description" \
org.opencontainers.image.source="$OCI_source" \
org.opencontainers.image.revision="$OCI_revision" \
org.opencontainers.image.version="$OCI_version" \
org.opencontainers.image.created="$OCI_created"
LABEL maintainer="$OCI_authors"
RUN <<EOF
echo "#################################################" echo "#################################################"
echo "Writing build_info..." echo "Writing build_info..."
echo "#################################################" echo "#################################################"
echo " cat <<EOT >/opt/build_info
GIT_REPO: $GIT_REPO_URL GIT_REPO: $OCI_source
GIT_BRANCH: $GIT_BRANCH GIT_BRANCH: $GIT_BRANCH
GIT_COMMIT: $GIT_COMMIT_HASH @ $GIT_COMMIT_DATE GIT_COMMIT: $OCI_revision @ $GIT_COMMIT_DATE
IMAGE_BUILD: $BUILD_DATE" >/opt/build_info IMAGE_BUILD: $OCI_created
EOT
cat /opt/build_info cat /opt/build_info
EOF EOF