Build containerimage on armhf and debian:experimental
Some checks failed
Container Image / Container Image (push) Has been cancelled

This commit is contained in:
Johannes Schmidt 2026-04-23 13:17:11 +02:00
parent 66a0e7d0f5
commit b2e9cfcd62
3 changed files with 232 additions and 39 deletions

View file

@ -0,0 +1,228 @@
# The Build and Publish Container Image workflow builds container images and pushes them to both
# GitHub Container Registry (GHCR) and Docker Hub. It sets up QEMU and Docker Buildx for cross-platform
# builds, and builds the container images using the Containerfile. For all non-pull request events that
# trigger this workflow, it logs into GHCR and Docker Hub using credentials from the workflow call inputs,
# tags and pushes the images to both registries, and generates and pushes signed build provenance attestations
# to each registry. Additionally, when a building and publishing the latest tag, it syncs the README file
# determined by the container_readme_filepath input (or the For-Container.md file found in the ./doc/ directory
# if not provided) with Docker Hub. For pull request events, it just builds the images but does not push them
# to the registries.
name: Container Image
on:
workflow_call:
inputs:
image_name:
required: false
type: string
description: 'Name of the container image to build and publish, e.g., "icinga/icinga2".'
documentation_url:
required: true
type: string
description: 'URL to the Icinga documentation for this project.'
container_readme_filepath:
required: false
type: string
description: 'Path to the README file to sync with Docker Hub. Defaults to the For-Container.md file in the ./doc/ directory.'
# We do not need to require the secrets.GITHUB_TOKEN here because it is automatically
# inherited from the workflow call [^1].
#
# [^1]: https://docs.github.com/en/actions/reference/workflows-and-actions/reusable-workflows#github-context
secrets:
dockerhub_username:
required: true
description: 'Username for Docker Hub.'
dockerhub_token:
required: true
description: 'Personal access token for Docker Hub.'
env:
# If we did not receive a custom image name from the workflow call inputs, we use the repository name prefixed
# with "icinga/" as the default image name. Actually, there's also the ${{ github.repository }} context variable,
# which contains the repository name in the format "owner/repo", but it is not suitable for container image names
# in our case because they must be lowercase, and our organization name is Icinga. Our repository names on the other
# hand, are all lowercase, so no additional modifications are necessary.
IMAGE_NAME: ${{ inputs.image_name || format('icinga/{0}', github.event.repository.name) }}
# The LATEST variable determines if the current release tag is the greatest tag overall.
# If true, the container image will be tagged as 'latest' when pushed to the container registries.
LATEST: false
# The LATEST_MAJOR variable determines if the current release tag is the greatest within its major version.
# If true, the container image will be tagged with the major version (e.g., '1') when pushed to the registries.
LATEST_MAJOR: false
# The path to the README file to sync with Docker Hub. If not provided, it defaults to
# the For-Container.md file found in the ./doc/ directory.
README_FILEPATH: ${{ inputs.container_readme_filepath }}
jobs:
build-and-publish:
name: Build and Publish
runs-on: ubuntu-latest
permissions:
contents: read # Read github repository contents (actually required only for private repositories).
packages: write # Push container images to GitHub Container Registry.
attestations: write # Push signed build provenance attestations to the GHCR.
id-token: write # Required for the actions/attest-build-provenance@v3 action to generate attestations.
steps:
# Explicitly using the checkout action (instead of relying on docker/build-push-action to do it implicitly)
# because we need to fetch all tags.
- name: Checkout
uses: actions/checkout@v6
with:
# Switch to fetch-tags: true once https://github.com/actions/checkout/issues/1467 is fixed.
fetch-depth: 0
# Updates env.LATEST and env.LATEST_MAJOR based on
# whether the current release tag is the greatest overall and/or
# within its major version.
- name: Prepare metadata (release tags)
if: github.event_name == 'release' && github.event.action == 'published'
run: |
# Retrieve the greatest existing tag in the repository by sorting tags in descending order.
# Options used:
# * --sort=-v:refname sorts tags as versions, placing the highest version at the top.
# * -c 'versionsort.suffix=-' ensures that pre-release tags (e.g., 1.0.0-rc1) are sorted correctly,
# so they are not considered greater than their corresponding final release (e.g., 1.0.0).
# Intentionally not using head -1 to prevent potential broken pipe errors.
greatest_tag=$(git -c 'versionsort.suffix=-' tag --list --sort=-v:refname | awk 'NR==1')
if [ "${{ github.ref_name }}" = "$greatest_tag" ]; then
echo "The current tag ${{ github.ref_name }} is the greatest overall. Tagging as 'latest'."
# Update environment variable to enable tagging as 'latest'.
echo "LATEST=true" >> "$GITHUB_ENV"
else
echo "The current tag ${{ github.ref_name }} is not the greatest overall compared to $greatest_tag. Not tagging as 'latest'."
fi
major_version=$(echo ${{ github.ref_name }} | cut -d. -f1)
greatest_major=$(git -c 'versionsort.suffix=-' tag --list "${major_version}.*" --sort=-v:refname | awk 'NR==1')
if [ "${{ github.ref_name }}" = "$greatest_major" ]; then
echo "The current tag ${{ github.ref_name }} is the greatest within its major version. Tagging with major version ${major_version#v}."
# Update environment variable to enable tagging with major version.
echo "LATEST_MAJOR=true" >> "$GITHUB_ENV"
else
echo "The current tag ${{ github.ref_name }} is not the greatest within its major version compared to $greatest_major. Not tagging with major version ${major_version#v}."
fi
- name: Extract metadata (tags, labels)
id: meta
uses: docker/metadata-action@v5
with:
# This will generate tags and labels for both the GHCR image and Docker Hub image.
images: |
# GitHub Container Registry
ghcr.io/${{ env.IMAGE_NAME }}
# Docker Hub
docker.io/${{ env.IMAGE_NAME }}
labels: |
org.opencontainers.image.documentation=${{ inputs.documentation_url }}
org.opencontainers.image.vendor=Icinga GmbH
flavor: |
# Disable automatic 'latest' tagging as our custom logic is used to
# determine when to apply the 'latest' tag.
latest=false
tags: |
type=edge
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{major}},enable=${{ env.LATEST_MAJOR }}
type=raw,value=latest,enable=${{ env.LATEST }}
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to GitHub Container Registry
if: github.event_name != 'pull_request'
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Login to Docker Hub
if: github.event_name != 'pull_request'
uses: docker/login-action@v3
with:
username: ${{ secrets.dockerhub_username }}
password: ${{ secrets.dockerhub_token }}
- name: Build and push Container image
id: build-and-push
uses: docker/build-push-action@v6
with:
context: .
file: ./Containerfile
labels: ${{ steps.meta.outputs.labels }}
platforms: linux/armhf
push: false
# The tags generated in the metadata step include tags for both Docker Hub and GHCR image names,
# allowing the build and push action to build and push images to both registries.
tags: ${{ steps.meta.outputs.tags }}
- name: Generate artifact attestation for GitHub Container Registry
if: github.event_name != 'pull_request'
uses: actions/attest-build-provenance@v3
with:
subject-name: ghcr.io/${{ env.IMAGE_NAME }}
subject-digest: ${{ steps.build-and-push.outputs.digest }}
push-to-registry: false
- name: Generate artifact attestation for Docker Hub
if: github.event_name != 'pull_request'
uses: actions/attest-build-provenance@v3
with:
# According to the documentation [^1],
# "index.docker.io" should be used as the registry portion of the image name when pushing to Docker Hub.
#
# [^1]: https://github.com/actions/attest-build-provenance?tab=readme-ov-file#container-image
subject-name: index.docker.io/${{ env.IMAGE_NAME }}
subject-digest: ${{ steps.build-and-push.outputs.digest }}
push-to-registry: false
- name: Prepare For-Container.md file
if: ${{ env.LATEST == 'true' }}
run: |
if [ -z "${{ env.README_FILEPATH }}" ]; then
files=$(find ./doc -type f -name 'For-Container.md')
if [ -z "$files" ]; then
echo "No For-Container.md file found in the ./doc/ directory."
exit 1
fi
# Must be a single file, otherwise exit with error.
if [ $(echo "$files" | wc -l) -ne 1 ]; then
echo "Multiple For-Container.md files found in the ./doc/ directory. Please specify a single file using the container_readme_filepath input."
echo "$files"
exit 1
fi
file_path=$(echo "$files" | head -n 1)
echo "No custom container README file path provided. Using default path: $file_path"
echo "README_FILEPATH=$file_path" >> "$GITHUB_ENV"
else
# Check if the provided file exists.
if [ -f "${{ env.README_FILEPATH }}" ]; then
echo "Using provided container README file path: ${{ env.README_FILEPATH }}"
else
echo "Provided container README file path does not exist: ${{ env.README_FILEPATH }}"
exit 1
fi
fi
- name: Sync For-Container.md
uses: ms-jpq/sync-dockerhub-readme@e2991ea1ba48832e73555cdbd5b82f5a2e91ee9b # v1
if: ${{ env.LATEST == 'true' }}
with:
username: ${{ secrets.dockerhub_username }}
password: ${{ secrets.dockerhub_token }}
repository: ${{ env.IMAGE_NAME }}
readme: ${{ env.README_FILEPATH }}

View file

@ -3,7 +3,7 @@ name: Container Image
on:
push:
branches:
- master
- enable-parallel-testing-armhf
pull_request: {}
release:
types:
@ -24,7 +24,7 @@ jobs:
id-token: write
name: Container Image
uses: icinga/github-actions/.github/workflows/container-image.yml@main
uses: ./.github/workflows/container-image-base.yml
with:
documentation_url: https://icinga.com/docs/icinga2
secrets:

View file

@ -1,7 +1,7 @@
# SPDX-FileCopyrightText: 2025 Icinga GmbH <https://icinga.com>
# SPDX-License-Identifier: GPL-2.0-or-later
FROM debian:trixie-slim AS build-base
FROM debian:experimental AS build-base
# Install all the necessary build dependencies for building Icinga 2 and the plugins.
#
@ -113,6 +113,7 @@ RUN --mount=type=bind,source=.,target=/icinga2,readonly \
PATH="/usr/lib/ccache:$PATH" \
cmake -S /icinga2 -B /icinga2-build \
-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} \
-DCMAKE_CXX_FLAGS="-fstack-protector-strong" \
# Podman supports forwarding notifications from containers to systemd, so build Icinga 2 with systemd support.
-DUSE_SYSTEMD=ON \
-DBUILD_TESTING=${ICINGA2_BUILD_TESTING} \
@ -146,42 +147,6 @@ FROM debian:trixie-slim AS icinga2
# The real UID of the Icinga user to be used in the final image.
ARG ICINGA_USER_ID=5665
# Install the necessary runtime dependencies for the Icinga 2 binary and the monitoring-plugins.
RUN apt-get update && \
apt-get upgrade -y && \
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends --no-install-suggests \
bc \
ca-certificates \
curl \
dumb-init \
file \
libboost-context1.83.0 \
libboost-coroutine1.83.0 \
libboost-date-time1.83.0 \
libboost-filesystem1.83.0 \
libboost-iostreams1.83.0 \
libboost-program-options1.83.0 \
libboost-regex1.83.0 \
libboost-system1.83.0 \
libboost-thread1.83.0 \
libcap2-bin \
libedit2 \
libldap-common \
libmariadb3 \
libmoosex-role-timer-perl \
libpq5 \
libprotobuf-lite32t64 \
libssl3 \
libsystemd0 \
mailutils \
monitoring-plugins \
msmtp \
msmtp-mta \
openssh-client \
openssl && \
# Official Debian images automatically run `apt-get clean` after every install, so we don't need to do it here.
rm -rf /var/lib/apt/lists/*
# Create the icinga user and group with a specific UID as recommended by Docker best practices.
# The user has a home directory at /var/lib/icinga2, and if configured, that directory will also
# be used to store the ".msmtprc" file created by the entrypoint script.