feat: scaffold rpmbuilder image
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/build-matrix/2 Pipeline was successful
ci/woodpecker/pr/build-matrix/3 Pipeline was successful
ci/woodpecker/pr/build-matrix/1 Pipeline was successful
ci/woodpecker/pr/build-matrix/4 Pipeline was successful
ci/woodpecker/pr/build Pipeline was successful

This commit is contained in:
2026-10-05 13:54:47 +11:00
parent f1f3011a73
commit 702f0706aa
13 changed files with 353 additions and 1 deletions
+30
View File
@@ -0,0 +1,30 @@
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v5.0.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
- id: check-merge-conflict
- id: mixed-line-ending
args: [--fix=lf]
- repo: https://github.com/AleksaC/hadolint-py
rev: v2.15.1
hooks:
- id: hadolint
- repo: https://github.com/shellcheck-py/shellcheck-py
rev: v0.11.0.1
hooks:
- id: shellcheck
# No upstream equivalent: a distro added under distros/ but left out of a
# Woodpecker matrix silently never gets built.
- repo: local
hooks:
- id: check-distros
name: distros match the woodpecker matrices
entry: ci/check-distros.sh
language: system
pass_filenames: false
+47
View File
@@ -0,0 +1,47 @@
when:
- event: pull_request
matrix:
include:
# One entry per distro. Adding a distro: add distros/<name>/ and one entry here.
- DISTRO: alma9
BASE_IMAGE_NAME: almalinux9
TAG_SUFFIX: alma9
DEFAULT: "true"
- DISTRO: fedora42
BASE_IMAGE_NAME: fedora42
TAG_SUFFIX: fedora42
DEFAULT: "false"
- DISTRO: fedora43
BASE_IMAGE_NAME: fedora43
TAG_SUFFIX: fedora43
DEFAULT: "false"
- DISTRO: fedora44
BASE_IMAGE_NAME: fedora44
TAG_SUFFIX: fedora44
DEFAULT: "false"
steps:
- name: build
image: "artifactapi.k8s.syd1.au.unkin.net/docker-internal/plugin-docker-buildx:latest"
settings:
# registry is what gets the internal CA into the buildkit container: the plugin
# writes a buildkit.toml pointing at /etc/docker/certs.d/<registry>/ca.crt only
# when it is set. The plugin has no buildkit_config setting.
registry: artifactapi.k8s.syd1.au.unkin.net
repo: "artifactapi.k8s.syd1.au.unkin.net/docker-internal/rpmbuilder"
target: image
dry_run: true
build_args:
BASE_IMAGE_NAME: "${BASE_IMAGE_NAME}"
DISTRO: "${DISTRO}"
backend_options:
kubernetes:
serviceAccountName: default
resources:
requests:
memory: 1Gi
cpu: 1
limits:
memory: 4Gi
cpu: 2
+22
View File
@@ -0,0 +1,22 @@
# Branch protection requires ci/woodpecker/pr/build; matrix entries report build-matrix/<n>.
when:
- event: pull_request
depends_on:
- build-matrix
steps:
- name: build
image: "artifactapi.k8s.syd1.au.unkin.net/docker-internal/plugin-docker-buildx:latest"
commands:
- echo "all build-matrix entries passed"
backend_options:
kubernetes:
serviceAccountName: default
resources:
requests:
memory: 64Mi
cpu: 100m
limits:
memory: 128Mi
cpu: 250m
+74
View File
@@ -0,0 +1,74 @@
when:
- event: tag
ref: refs/tags/v*
matrix:
include:
# One entry per distro. Adding a distro: add distros/<name>/ and one entry here.
- DISTRO: alma9
BASE_IMAGE_NAME: almalinux9
TAG_SUFFIX: alma9
DEFAULT: "true"
- DISTRO: fedora42
BASE_IMAGE_NAME: fedora42
TAG_SUFFIX: fedora42
DEFAULT: "false"
- DISTRO: fedora43
BASE_IMAGE_NAME: fedora43
TAG_SUFFIX: fedora43
DEFAULT: "false"
- DISTRO: fedora44
BASE_IMAGE_NAME: fedora44
TAG_SUFFIX: fedora44
DEFAULT: "false"
steps:
- name: docker
image: "artifactapi.k8s.syd1.au.unkin.net/docker-internal/plugin-docker-buildx:latest"
settings:
# registry is what gets the internal CA into the buildkit container: the plugin
# writes a buildkit.toml pointing at /etc/docker/certs.d/<registry>/ca.crt only
# when it is set. The plugin has no buildkit_config setting.
registry: artifactapi.k8s.syd1.au.unkin.net
repo: "artifactapi.k8s.syd1.au.unkin.net/docker-internal/rpmbuilder"
target: image
build_args:
BASE_IMAGE_NAME: "${BASE_IMAGE_NAME}"
DISTRO: "${DISTRO}"
tags:
- "${CI_COMMIT_TAG##v}-${TAG_SUFFIX}"
backend_options:
kubernetes:
serviceAccountName: default
resources:
requests:
memory: 1Gi
cpu: 1
limits:
memory: 4Gi
cpu: 2
# The default distro's unsuffixed tag is an alias of the image the step above just
# pushed, not a second build of it: imagetools create only writes a new tag reference
# to the existing manifest, so :<version> and :<version>-<suffix> are one digest. No
# daemon is involved; the internal CA is baked into this image at /etc/docker/certs.d/.
- name: docker-default-tag
image: "artifactapi.k8s.syd1.au.unkin.net/docker-internal/plugin-docker-buildx:latest"
when:
- evaluate: 'DEFAULT == "true"'
environment:
REPO: "artifactapi.k8s.syd1.au.unkin.net/docker-internal/rpmbuilder"
VERSION: "${CI_COMMIT_TAG##v}"
SUFFIX: "${TAG_SUFFIX}"
commands:
- 'docker buildx imagetools create -t "$REPO:$VERSION" "$REPO:$VERSION-$SUFFIX"'
backend_options:
kubernetes:
serviceAccountName: default
resources:
requests:
memory: 256Mi
cpu: 250m
limits:
memory: 512Mi
cpu: 500m
+18
View File
@@ -0,0 +1,18 @@
when:
- event: pull_request
steps:
- name: pre-commit
image: "artifactapi.k8s.syd1.au.unkin.net/docker-internal/gobuilder:0.1.0-alma9"
commands:
- uvx pre-commit run --all-files
backend_options:
kubernetes:
serviceAccountName: default
resources:
requests:
memory: 512Mi
cpu: 1
limits:
memory: 2Gi
cpu: 2
+18
View File
@@ -0,0 +1,18 @@
ARG REGISTRY=artifactapi.k8s.syd1.au.unkin.net/docker-internal
# The container-base release this image is built on — the one place to bump it.
ARG BASE_VERSION=0.2.0
ARG BASE_IMAGE_NAME=almalinux9
FROM ${REGISTRY}/${BASE_IMAGE_NAME}:${BASE_VERSION} AS image
ARG DISTRO=alma9
COPY distros/${DISTRO}/ /tmp/distro/
# DL3041: versions are pinned by the estate dnf repos, not here. SC2086: $PACKAGES is a
# word list on purpose.
# hadolint ignore=DL3041,SC2086
RUN set -eux; \
. /tmp/distro/distro.env; \
dnf install -y $PACKAGES; \
dnf clean all; \
rm -rf /var/cache/dnf /tmp/distro
CMD ["/bin/bash"]
+39
View File
@@ -0,0 +1,39 @@
REGISTRY := artifactapi.k8s.syd1.au.unkin.net/docker-internal
DISTROS := $(notdir $(wildcard distros/*))
VERSION ?= $(patsubst v%,%,$(or $(shell git describe --tags --exact-match 2>/dev/null),0.1.0-dev))
.PHONY: build clean pre-commit patch minor major
build: $(addprefix build-,$(DISTROS))
clean: $(addprefix clean-,$(DISTROS))
pre-commit:
@uvx pre-commit run --all-files
# Not .PHONY: GNU make skips implicit-rule search for phony targets.
build-%:
@set -eu; . ./distros/$*/distro.env; \
docker build --build-arg "BASE_IMAGE_NAME=$$BASE_IMAGE_NAME" --build-arg "DISTRO=$*" \
-t "$(REGISTRY)/$$IMAGE:$(VERSION)-$$TAG_SUFFIX" .
clean-%:
@set -eu; . ./distros/$*/distro.env; \
docker rmi "$(REGISTRY)/$$IMAGE:$(VERSION)-$$TAG_SUFFIX" 2>/dev/null || true
_LATEST := $(shell git tag --sort=-v:refname | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$$' | head -1)
_BASE := $(if $(_LATEST),$(_LATEST),v0.0.0)
_MAJ := $(shell echo $(_BASE) | sed 's/^v//' | cut -d. -f1)
_MIN := $(shell echo $(_BASE) | sed 's/^v//' | cut -d. -f2)
_PAT := $(shell echo $(_BASE) | sed 's/^v//' | cut -d. -f3)
patch:
@NEW=v$(_MAJ).$(_MIN).$(shell expr $(_PAT) + 1); \
git tag $$NEW && echo "Tagged $$NEW" && git push origin $$NEW
minor:
@NEW=v$(_MAJ).$(shell expr $(_MIN) + 1).0; \
git tag $$NEW && echo "Tagged $$NEW" && git push origin $$NEW
major:
@NEW=v$(shell expr $(_MAJ) + 1).0.0; \
git tag $$NEW && echo "Tagged $$NEW" && git push origin $$NEW
+33 -1
View File
@@ -1,3 +1,35 @@
# container-rpmbuilder
RPM build container image (rpmbuild/nfpm toolchain), built per distro, used by Woodpecker pipelines to package RPMs.
The estate's RPM packaging image, built on each `container-base` distro image.
Published as `artifactapi.k8s.syd1.au.unkin.net/docker-internal/rpmbuilder:<version>-<suffix>`;
the default distro's build is retagged as the unsuffixed `:<version>`, so both resolve
to one digest. Only explicit versions are published; never a floating tag.
| distro | from | tag suffix | default |
| --- | --- | --- | --- |
| `alma9` | `docker-internal/almalinux9:<base version>` | `alma9` | yes |
| `fedora42` | `docker-internal/fedora42:<base version>` | `fedora42` | no |
| `fedora43` | `docker-internal/fedora43:<base version>` | `fedora43` | no |
| `fedora44` | `docker-internal/fedora44:<base version>` | `fedora44` | no |
Adds `rpm-build`, `rpmdevtools`, `rpmlint`, `rpm-sign`, `nfpm`, `envsubst` (`gettext`),
`buildah`, `go`, `gcc` and the usual autotools/debug toolchain; see `PACKAGES` in each
`distros/<name>/distro.env`.
The `container-base` release this image builds on is `BASE_VERSION` in the `Dockerfile`.
## Adding a distro
1. `distros/<name>/distro.env` — `BASE_IMAGE_NAME`, `IMAGE`, `TAG_SUFFIX`, `DEFAULT`, `PACKAGES`.
2. One `include` entry in each of `.woodpecker/{build-matrix,docker}.yaml`.
The `check-distros` pre-commit hook fails if step 1 or 2 is incomplete, or if more than
one distro claims `DEFAULT`. `.woodpecker/build.yaml` only aggregates the matrix into the
`ci/woodpecker/pr/build` context that branch protection requires.
## Make
make build # build every distro
make pre-commit # uvx pre-commit run --all-files
make build-alma9 # one distro
make patch|minor|major
+43
View File
@@ -0,0 +1,43 @@
#!/usr/bin/env bash
# Every distros/<name>/ needs a complete distro.env and an entry in every Woodpecker
# matrix, or a newly added distro silently never gets built.
set -uo pipefail
KEYS="BASE_IMAGE_NAME IMAGE TAG_SUFFIX DEFAULT PACKAGES"
WORKFLOWS=(.woodpecker/build-matrix.yaml .woodpecker/docker.yaml)
fail=0
for d in distros/*/; do
n=$(basename "$d")
for k in $KEYS; do
grep -q "^${k}=" "${d}distro.env" || { echo "${d}distro.env: missing ${k}"; fail=1; }
done
for wf in "${WORKFLOWS[@]}"; do
grep -q "DISTRO: ${n}\$" "$wf" || { echo "${wf}: distro ${n} missing from matrix"; fail=1; }
# A matrix entry that restates a distro.env key must not drift from it — a stale
# BASE_IMAGE here silently overrides distro.env for every CI build.
while IFS='=' read -r k v; do
[ -n "$k" ] || continue
grep -q "^${k}=" "${d}distro.env" || continue
ev=$(sed -n "s/^${k}=//p" "${d}distro.env" | head -1 | sed 's/^"//;s/"$//')
[ "$v" = "$ev" ] || { echo "${wf}: matrix ${k}=\"${v}\" for ${n} disagrees with ${d}distro.env (\"${ev}\")"; fail=1; }
done <<EOF
$(awk -v d="$n" '
$0 ~ "^[[:space:]]*-[[:space:]]+DISTRO:[[:space:]]*"d"[[:space:]]*$" { inb=1; next }
inb && /^[[:space:]]*-/ { inb=0 }
inb && match($0, /^[[:space:]]+[A-Z_]+:/) {
k=$1; sub(/:$/,"",k)
v=$0; sub(/^[[:space:]]*[A-Z_]+:[[:space:]]*/,"",v); gsub(/^"|"$/,"",v)
print k "=" v
}
' "$wf")
EOF
done
done
# Exactly one distro owns the unsuffixed :<version> tag.
defaults=$(grep -l 'DEFAULT="true"' distros/*/distro.env | wc -l)
[ "$defaults" -eq 1 ] || { echo "expected exactly one distro with DEFAULT=\"true\", found ${defaults}"; fail=1; }
exit "$fail"
+8
View File
@@ -0,0 +1,8 @@
# alma9 — built on the container-base almalinux9 image
BASE_IMAGE_NAME="almalinux9"
IMAGE="rpmbuilder"
TAG_SUFFIX="alma9"
# The default distro also gets the unsuffixed :<version> tag.
DEFAULT="true"
PACKAGES="asciidoc autoconf automake binutils bison buildah byacc cmake diffstat flex gcc gcc-c++ gdb gettext glibc-devel go gzip intltool jna ltrace nfpm patchutils perl-Fedora-VSP perl-generators pesign pkgconf pkgconf-m4 pkgconf-pkg-config redhat-rpm-config rpm rpm-build rpm-sign rpmdevtools rpmlint source-highlight strace systemtap tar unzip valgrind valgrind-devel"
+7
View File
@@ -0,0 +1,7 @@
# fedora42 — built on the container-base fedora42 image
BASE_IMAGE_NAME="fedora42"
IMAGE="rpmbuilder"
TAG_SUFFIX="fedora42"
DEFAULT="false"
PACKAGES="asciidoc autoconf automake binutils bison buildah byacc cmake diffstat flex gcc gcc-c++ gdb gettext glibc-devel go gzip intltool jna ltrace nfpm patchutils perl-Fedora-VSP perl-generators pesign pkgconf pkgconf-m4 pkgconf-pkg-config redhat-rpm-config rpm rpm-build rpm-sign rpmdevtools rpmlint source-highlight strace systemtap tar unzip valgrind valgrind-devel"
+7
View File
@@ -0,0 +1,7 @@
# fedora43 — built on the container-base fedora43 image
BASE_IMAGE_NAME="fedora43"
IMAGE="rpmbuilder"
TAG_SUFFIX="fedora43"
DEFAULT="false"
PACKAGES="asciidoc autoconf automake binutils bison buildah byacc cmake diffstat flex gcc gcc-c++ gdb gettext glibc-devel go gzip intltool jna ltrace nfpm patchutils perl-Fedora-VSP perl-generators pesign pkgconf pkgconf-m4 pkgconf-pkg-config redhat-rpm-config rpm rpm-build rpm-sign rpmdevtools rpmlint source-highlight strace systemtap tar unzip valgrind valgrind-devel"
+7
View File
@@ -0,0 +1,7 @@
# fedora44 — built on the container-base fedora44 image
BASE_IMAGE_NAME="fedora44"
IMAGE="rpmbuilder"
TAG_SUFFIX="fedora44"
DEFAULT="false"
PACKAGES="asciidoc autoconf automake binutils bison buildah byacc cmake diffstat flex gcc gcc-c++ gdb gettext glibc-devel go gzip intltool jna ltrace nfpm patchutils perl-Fedora-VSP perl-generators pesign pkgconf pkgconf-m4 pkgconf-pkg-config redhat-rpm-config rpm rpm-build rpm-sign rpmdevtools rpmlint source-highlight strace systemtap tar unzip valgrind valgrind-devel"