From 518ee6962cd6309303e42f9b786f394fe89ec752 Mon Sep 17 00:00:00 2001 From: sebthom Date: Wed, 21 May 2025 20:51:43 +0200 Subject: [PATCH] build: improve build config --- .gitattributes | 1 + .github/workflows/build.yml | 87 ++++++++++++++++--------- .github/workflows/stale.yml | 2 +- CODE_OF_CONDUCT.md | 2 +- README.md | 2 +- build-image.sh | 125 ++++++++++++++++++++---------------- image/Dockerfile | 32 +++++---- image/run_runner.sh | 1 - 8 files changed, 147 insertions(+), 105 deletions(-) diff --git a/.gitattributes b/.gitattributes index dd24784..dd69b56 100644 --- a/.gitattributes +++ b/.gitattributes @@ -61,6 +61,7 @@ *.python text *.sql text **/Dockerfile text eol=lf +**/*.Dockerfile text eol=lf # Archives diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d8d499d..60840f0 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -3,7 +3,7 @@ # SPDX-License-Identifier: Apache-2.0 # SPDX-ArtifactOfProjectHomePage: https://github.com/vegardit/docker-gitea-act-runner # -# https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions +# https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions name: Build on: @@ -26,10 +26,10 @@ on: - '.github/*.yml' - '.github/workflows/stale.yml' schedule: - # https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows + # https://docs.github.com/en/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows - cron: '0 17 * * 3' workflow_dispatch: - # https://github.blog/changelog/2020-07-06-github-actions-manual-triggers-with-workflow_dispatch/ + # https://docs.github.com/en/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows#workflow_dispatch inputs: VERSION: type: string @@ -41,7 +41,7 @@ defaults: shell: bash env: - DOCKER_IMAGE_REPO: ${{ github.repository_owner }}/gitea-act-runner + DOCKER_REPO_NAME: gitea-act-runner TRIVY_CACHE_DIR: ~/.trivy/cache jobs: @@ -49,6 +49,11 @@ jobs: ########################################################### build: ########################################################### + runs-on: ubuntu-latest # https://github.com/actions/runner-images#available-images + timeout-minutes: 30 + + permissions: + packages: write strategy: matrix: @@ -73,9 +78,6 @@ jobs: GITEA_ACT_RUNNER_VERSION: nightly fail-fast: true - runs-on: ubuntu-latest # https://github.com/actions/runner-images#available-images - timeout-minutes: 30 - steps: - name: "Show: GitHub context" env: @@ -91,11 +93,21 @@ jobs: uses: actions/checkout@v4 # https://github.com/actions/checkout + - name: Run the sh-checker + uses: luizm/action-sh-checker@master # https://github.com/marketplace/actions/sh-checker + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + SHFMT_OPTS: --simplify --keep-padding + with: + sh_checker_comment: true + sh_checker_checkbashisms_enable: true + sh_checker_shfmt_disable: true + + - name: Check Dockerfile uses: hadolint/hadolint-action@v3.1.0 with: dockerfile: image/Dockerfile - ignore: DL3008,SC1091 # https://github.com/hadolint/hadolint/wiki/DL3008 - name: Cache trivy cache @@ -117,22 +129,19 @@ jobs: - name: "Determine if docker images shall be published" + id: docker_push_actions run: | # ACT -> https://nektosact.com/usage/index.html#skipping-steps set -x if [[ $GITHUB_REF_NAME == 'main' && $GITHUB_EVENT_NAME != 'pull_request' && -z "$ACT" ]]; then echo "DOCKER_PUSH_GHCR=true" >> "$GITHUB_ENV" + echo "DOCKER_PUSH_GHCR=true" >> $GITHUB_OUTPUT if [[ -n "${{ secrets.DOCKER_HUB_USERNAME }}" ]]; then echo "DOCKER_PUSH=true" >> "$GITHUB_ENV" fi fi - - name: Install regclient - if: ${{ env.DOCKER_PUSH_GHCR }} - uses: iarekylew00t/regctl-installer@v3 - - - name: Login to docker.io if: ${{ env.DOCKER_PUSH }} uses: docker/login-action@v3 @@ -147,36 +156,50 @@ jobs: with: registry: ghcr.io username: ${{ github.actor }} - password: ${{ github.token }} + password: ${{ secrets.GITHUB_TOKEN }} - - name: Build ${{ env.DOCKER_IMAGE_REPO }}:${{ env.DOCKER_IMAGE_TAG }} + - name: Build ${{ env.DOCKER_REPO_NAME }}:${{ env.DOCKER_IMAGE_TAG }} env: + DOCKER_BASE_IMAGE: ghcr.io/dockerhub-mirror/debian:stable-slim + DOCKER_IMAGE_REPO: ${{ github.repository_owner }}/${{ env.DOCKER_REPO_NAME }} DOCKER_IMAGE_TAG_PREFIX: ${{ matrix.DOCKER_IMAGE_TAG_PREFIX }} DOCKER_IMAGE_FLAVOR: ${{ matrix.DOCKER_IMAGE_FLAVOR }} - TRIVY_GITHUB_TOKEN: ${{ github.token }} + TRIVY_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | if [[ -n "${{ inputs.VERSION }}" ]]; then - export GITEA_ACT_RUNNER_VERSION="${{ inputs.VERSION }}" + export GITEA_ACT_RUNNER_VERSION="${{ inputs.VERSION }}" else - export GITEA_ACT_RUNNER_VERSION="${{ matrix.GITEA_ACT_RUNNER_VERSION }}" + export GITEA_ACT_RUNNER_VERSION="${{ matrix.GITEA_ACT_RUNNER_VERSION }}" fi bash build-image.sh + outputs: + DOCKER_PUSH_GHCR: ${{ steps.docker_push_actions.outputs.DOCKER_PUSH_GHCR }} + + ########################################################### + delete-untagged-images: + ########################################################### + runs-on: ubuntu-latest # https://github.com/actions/runner-images#available-images + timeout-minutes: 5 + needs: [build] + if: ${{ needs.build.outputs.DOCKER_PUSH_GHCR }} + + concurrency: + group: ${{ github.workflow }} + cancel-in-progress: false + + permissions: + packages: write + + steps: - name: Delete untagged images - uses: actions/github-script@v7 - if: ${{ env.DOCKER_PUSH_GHCR }} - continue-on-error: true + uses: dataaxiom/ghcr-cleanup-action@v1 with: - github-token: ${{ secrets.GHA_DELETE_PACKAGES }} - script: | - const imageName = /[^/]*$/.exec(process.env.DOCKER_IMAGE_REPO)[0] - const basePath = `/orgs/${{ github.repository_owner }}/packages/container/${imageName}/versions` - for (version of (await github.request(`GET ${basePath}`, { per_page: 100 })).data) { - if (version.metadata.container.tags.length == 0) { - console.log(`deleting ${version.name}...`) - const delResponse = await github.request(`DELETE ${basePath}/${version.id}`) - console.log(`status: ${delResponse.status}`) - } - } + package: ${{ env.DOCKER_REPO_NAME }} + delete-untagged: true + delete-partial-images: true + delete-ghost-images: true + delete-orphaned-images: true + validate: true diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index 545e172..32d7214 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -1,4 +1,4 @@ -# https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions +# https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions name: Stale issues on: diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index c2934ee..bca16db 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -60,7 +60,7 @@ representative at an online or offline event. Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement at -https://vegardit.com/about/legal/. +https://vegardit.com/en/legal/. All complaints will be reviewed and investigated promptly and fairly. All community leaders are obligated to respect the privacy and security of the diff --git a/README.md b/README.md index 38a0fad..d798064 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ ## What is it? -`debian:stable-slim` based Docker image containing [Gitea](https://gitea.com)'s [act_runner](https://gitea.com/gitea/act_runner/) +Multi-arch Docker image based on `debian:stable-slim` containing [Gitea](https://gitea.com)'s [act_runner](https://gitea.com/gitea/act_runner/) #### Why not using Alpine Linux? - musl-libc - Alpine's Greatest Weakness https://www.linkedin.com/pulse/musl-libc-alpines-greatest-weakness-rogan-lynch diff --git a/build-image.sh b/build-image.sh index 4fb4e99..8778b4a 100644 --- a/build-image.sh +++ b/build-image.sh @@ -6,7 +6,7 @@ # 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 "$@" + command curl -sSfL --connect-timeout 10 --max-time 30 --retry 3 --retry-all-errors "$@" } shared_lib="$(dirname "${BASH_SOURCE[0]}")/.shared" @@ -16,20 +16,10 @@ source "$shared_lib/lib/build-image-init.sh" ################################################# -# check prereqs -################################################# - -if [[ "${DOCKER_PUSH:-}" == "true" ]]; then - if ! hash regctl &>/dev/null; then - log ERROR "regctl (aka regclient) command line tool is misssing!" - fi -fi - - -################################################# -# specify target docker registry/repo +# specify target image repo/tag ################################################# gitea_act_runner_version=${GITEA_ACT_RUNNER_VERSION:-latest} +base_image_name=${DOCKER_BASE_IMAGE:-debian:stable-slim} image_repo=${DOCKER_IMAGE_REPO:-vegardit/gitea-act-runner} @@ -37,13 +27,24 @@ image_repo=${DOCKER_IMAGE_REPO:-vegardit/gitea-act-runner} # resolve gitea act runner version ################################################# case $gitea_act_runner_version in - latest) gitea_act_runner_effective_version=$(curl https://gitea.com/gitea/act_runner/releases.rss | grep -oP "releases/tag/v\K\d\.\d\.\d\d?" | head -n 1) - ;; - *) gitea_act_runner_effective_version=$gitea_act_runner_version - ;; + latest) gitea_act_runner_effective_version=$(curl https://gitea.com/gitea/act_runner/releases.rss | grep -oP "releases/tag/v\K\d\.\d\.\d\d?" | head -n 1) ;; + *) gitea_act_runner_effective_version=$gitea_act_runner_version ;; esac -image_name=$image_repo:${DOCKER_IMAGE_TAG_PREFIX:-}$gitea_act_runner_version -image_name2=$image_repo:${DOCKER_IMAGE_TAG_PREFIX:-}$gitea_act_runner_effective_version + + +################################################# +# calculate tags +################################################# +declare -a tags=() +tags+=("$image_repo:${DOCKER_IMAGE_TAG_PREFIX:-}$gitea_act_runner_version") +tags+=("$image_repo:${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]} ################################################# @@ -51,17 +52,19 @@ image_name2=$image_repo:${DOCKER_IMAGE_TAG_PREFIX:-}$gitea_act_runner_effective_ ################################################# log INFO "Building docker image [$image_name]..." if [[ $OSTYPE == "cygwin" || $OSTYPE == "msys" ]]; then - project_root=$(cygpath -w "$project_root") + project_root=$(cygpath -w "$project_root") fi # https://github.com/docker/buildx/#building-multi-platform-images set -x docker --version -docker run --privileged --rm tonistiigi/binfmt --install all -export DOCKER_BUILD_KIT=1 +export DOCKER_BUILDKIT=1 export DOCKER_CLI_EXPERIMENTAL=1 # prevents "docker: 'buildx' is not a docker command." +# Register QEMU emulators for all architectures so Docker can run and build multi-arch images +docker run --privileged --rm ghcr.io/dockerhub-mirror/tonistiigi__binfmt --install all + # https://docs.docker.com/build/buildkit/configure/#resource-limiting echo " [worker.oci] @@ -70,43 +73,35 @@ echo " docker buildx version # ensures buildx is enabled 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") +trap 'docker buildx stop' EXIT # shellcheck disable=SC2154,SC2046 # base_layer_cache_key is referenced but not assigned / Quote this to prevent word splitting docker buildx build "$project_root" \ - --file "image/Dockerfile" \ - --progress=plain \ - --pull \ - --build-arg INSTALL_SUPPORT_TOOLS="${INSTALL_SUPPORT_TOOLS:-0}" \ - `# 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 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) \ - -t "$image_name" \ - -t "$image_name2" \ - $(if [[ "${DOCKER_PUSH:-}" == "true" ]]; then echo -n "--push"; fi) \ - "$@" -docker buildx stop + --file "image/Dockerfile" \ + --progress=plain \ + --pull \ + --build-arg INSTALL_SUPPORT_TOOLS="${INSTALL_SUPPORT_TOOLS:-0}" \ + `# 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" -fi - -################################################# -# push image to ghcr.io -################################################# -if [[ "${DOCKER_PUSH_GHCR:-}" == "true" ]]; then - (set -x; regctl image copy "$image_name" "ghcr.io/$image_name") - (set -x; regctl image copy "$image_name2" "ghcr.io/$image_name2") +if [[ ${DOCKER_PUSH:-} == "true" ]]; then + docker image pull "$image_name" fi @@ -123,6 +118,22 @@ echo # perform security audit ################################################# # TODO see https://gitea.com/gitea/act_runner/issues/513 -if [[ "${DOCKER_AUDIT_IMAGE:-1}" == 1 && "$GITEA_ACT_RUNNER_VERSION" == "nightly" ]]; then - bash "$shared_lib/cmd/audit-image.sh" "$image_name" +if [[ ${DOCKER_AUDIT_IMAGE:-1} == "1" && $GITEA_ACT_RUNNER_VERSION == "nightly" ]]; then + bash "$shared_lib/cmd/audit-image.sh" "$image_name" +fi + + +################################################# +# push image to ghcr.io +################################################# +if [[ ${DOCKER_PUSH_GHCR:-} == "true" ]]; then + for tag in "${tags[@]}"; do + set -x + docker run --rm \ + -u "$(id -u):$(id -g)" -e HOME -v "$HOME:$HOME" \ + -v /etc/docker/certs.d:/etc/docker/certs.d:ro \ + ghcr.io/regclient/regctl:latest \ + image copy "$tag" "ghcr.io/$tag" + set +x + done fi diff --git a/image/Dockerfile b/image/Dockerfile index 949babf..b6d0b58 100644 --- a/image/Dockerfile +++ b/image/Dockerfile @@ -1,4 +1,4 @@ -#syntax=docker/dockerfile:1.4 +#syntax=docker/dockerfile:1 # see https://github.com/moby/buildkit/blob/master/frontend/dockerfile/docs/syntax.md#user-content-syntax # see https://docs.docker.com/build/dockerfile/frontend/ # see https://docs.docker.com/engine/reference/builder/#syntax @@ -7,13 +7,18 @@ # SPDX-FileContributor: Sebastian Thomschke # SPDX-License-Identifier: Apache-2.0 # SPDX-ArtifactOfProjectHomePage: https://github.com/vegardit/docker-gitea-act-runner -# -# https://hub.docker.com/_/debian?tab=tags&name=stable-slim -FROM debian:stable-slim +# https://hub.docker.com/_/debian/tags?name=stable-slim +ARG BASE_IMAGE=debian:stable-slim + +# https://github.com/hadolint/hadolint/wiki/DL3006 Always tag the version of an image explicitly +# hadolint ignore=DL3006 +FROM ${BASE_IMAGE} 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"] @@ -31,8 +36,9 @@ ARG BASE_LAYER_CACHE_KEY ARG FLAVOR ARG GITEA_ACT_RUNNER_VERSION +# https://github.com/hadolint/hadolint/wiki/DL3008 Pin versions +# hadolint ignore=DL3008 RUN --mount=type=bind,source=.shared,target=/mnt/shared < /etc/apt/sources.list.d/docker.list + + ARCH="$(dpkg --print-architecture)" + # shellcheck disable=SC1091 # Not following: File not included in mock + OS_CODENAME="$(source /etc/os-release && echo "$VERSION_CODENAME")" + echo "deb [arch=$ARCH signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian $OS_CODENAME stable" > /etc/apt/sources.list.d/docker.list apt-get update (set -x; apt-get install --no-install-recommends -y docker-ce containerd.io fuse-overlayfs) apt-get remove -y gnupg diff --git a/image/run_runner.sh b/image/run_runner.sh index 038949b..a897738 100644 --- a/image/run_runner.sh +++ b/image/run_runner.sh @@ -4,7 +4,6 @@ # SPDX-FileContributor: Sebastian Thomschke # SPDX-License-Identifier: Apache-2.0 # SPDX-ArtifactOfProjectHomePage: https://github.com/vegardit/docker-gitea-act-runner -# # shellcheck disable=SC1091 # Not following: /opt/bash-init.sh was not specified as input source /opt/bash-init.sh