Drei aktuelle Releases decken zusammen den Container-Build-Workflow in Woodpecker CI ab: ein Podman-basiertes Build-Plugin für beliebige Woodpecker-Agents, ein privater Agent auf Hetzner Cloud als Heimat für Pipelines mit Secrets oder großen Builds, und ein Filter-Proxy, der entscheidet, welche Plugin-Images auf dem eigenen Agent privilegiert laufen dürfen.
woodpecker-ci-plugin-podman0.1.0 - direkterpodman build/podman push-Wrapper, der multi-arch Manifest Lists in einem Schritt erzeugtchilly-willy-agentv0.3.0 - privater Agent auf Fedora CoreOS plus Hetzner Cloudwally-walrus-agent-guardv0.2.0 - Filter-Proxy zwischen Agent und Podman-Socket mit aktiver Privilegien-Policy
Woodpecker CI Plugin Podman 0.1.0#
Ein direkter Wrapper um podman build, podman push und podman manifest push --all. Das Plugin bietet damit dasselbe Interface, das man auch lokal von podman kennt.
Codebergs public CI: das Plugin läuft out of the box. Mehr als CLONE_NEWUSER braucht es nicht, und das ist im Default-Seccomp-Profil erlaubt. Storage fällt auf vfs zurück (kein /dev/fuse auf den public Agents), Multi-Arch-Builds funktionieren, soweit die Runner-Hosts die nötige binfmt_misc-Konfiguration mitbringen.
Self-hosted Agent (Chilly Willy Agent v0.3.0 als Referenz-Setup): overlay plus fuse-overlayfs (deutlich schneller bei Builds mit vielen Layern), echte cross-arch RUN-Steps für beliebige Manifest-Listen-Einträge und Privilegien-Force-Escalation via Agent Guard.
steps:
- name: publish
image: head1328/woodpecker-ci-plugin-podman
settings:
repo: head1328/myapp
tags: latest
platforms: linux/amd64,linux/arm64
username:
from_secret: docker_hub_user
password:
from_secret: docker_hub_tokenBewusste Designentscheidung: das Plugin macht keine eigene binfmt_misc-Registrierung im Container. Seit Linux 6.7 ist binfmt_misc per User-Namespace skoped, und in nested rootless Podman lassen sich qemu-Handler innerhalb der Build-Sub-Runtime nicht mehr zuverlässig setzen. Das Plugin verlässt sich stattdessen auf den Host: wenn dort die qemu-Handler mit F (fix-binary) registriert sind, klappen cross-arch RUN-Steps; wenn nicht, scheitert der Build sauber.
Chilly Willy Agent v0.3.0#
Der Agent provisioniert einen privaten Woodpecker-Agent auf Hetzner Cloud und registriert ihn bei einer Woodpecker-Instanz (etwa der von Codeberg). Eine ausführliche Vorstellung gab es bereits zum Initial-Release ; 0.3.0 bringt drei größere Änderungen:
Native Multi-Arch im Host-Kernel: beim ersten Boot installiert eine systemd-Oneshot-Unit
qemu-user-staticalsrpm-ostree-Layer und startet das System neu. Beim zweiten Boot registriertsystemd-binfmtdie qemu-Interpreter aus/usr/lib/binfmt.d/qemu-*-static.confmit demF-Flag im Host-Kernel. Der Flag hält den Interpreter-FD bereits beim Registrieren offen, was ihn jedem geschachtelten rootless Userns zugänglich macht - inklusive der Build-Sub-Runtime von Podman.[Unit] Description=Layer qemu-user-static via rpm-ostree for cross-arch builds After=hetzner-ipv6.service network-online.target nss-lookup.target Before=zincati.service boot-complete.target ConditionPathExists=!/var/lib/cwa-qemu-layered.stamp [Service] Type=oneshot RemainAfterExit=yes ExecStart=/usr/bin/rpm-ostree install --allow-inactive qemu-user-static ExecStart=/usr/bin/touch /var/lib/cwa-qemu-layered.stamp ExecStart=/usr/bin/systemctl rebootZwei Presets:
secure(high-security baseline, vfs+chroot, keine Privileged-Plugins) undprivileged(overlay+FUSE, Privilegien-Eskalation via Allowlist). Beide erben die qemu binfmt-Handler aus dem Host-Kernel und können damit Multi-Arch-Manifests bauen.Wally Walrus Agent Guard v0.2.0 Integration plus deterministisches Update-Fenster: der Agent spricht über den Guard-Socket mit Podman, Zincati-Reboots sind auf ein tägliches Fenster von 03:00 bis 05:00 UTC begrenzt statt der unkontrollierten
immediate-Strategie.
Wally Walrus Agent Guard v0.2.0#
Der Agent Guard sitzt als Filter-Reverse-Proxy zwischen Woodpecker-Agent und Podman-Socket. Jedes POST /containers/create wird inspiziert und gegen die privileged_images-Allowlist des Agent-Operators abgeglichen.
Mit 0.2.0 wird aus dem passiven Filter eine aktive Policy. Drei Fälle:
- Image auf der Allowlist, Server sendet
Privileged=true: durchgelassen. - Image auf der Allowlist, Server sendet
Privileged=false: Der Agent Guard force-eskaliert aufPrivileged=true(neu in 0.2.0). Der Agent-Operator entscheidet damit eigenständig, welche Plugin-Images privilegiert laufen - unabhängig von der Server-Allowlist. - Image nicht auf der Allowlist, Server sendet
Privileged=true: HTTP 403, der Container-Create wird abgelehnt.
Das ist relevant für die Codeberg-Welt: Codeberg pflegt WOODPECKER_PLUGINS_PRIVILEGED als zentrale Liste. Welche Plugins Codeberg privilegieren lässt, entscheiden die Codeberg-Admins, nicht die Repository-Owner. Wenn man auf seinem eigenen Agent ein anderes Plugin (oder eine andere Version) privilegiert laufen lassen will, ohne mit der Codeberg-Liste in Konflikt zu geraten, kann der Agent Guard das auf Agent-Seite force-eskalieren - streng auf die eigene Allowlist beschränkt.
Zusammenspiel im privileged-Preset#
Die Demo-Pipeline .woodpecker/privileged.yml im Agent-Repo testet das Setup end-to-end mit vier Podman-Plugin-Steps: jeweils gegen den rollenden :next-Tag und gegen den per Digest gepinnten Release-Tag :0.1.0@sha256:c3f066..., einmal single-arch (linux/amd64), einmal multi-arch (linux/amd64,linux/arm64).
Im multi-arch-Lauf passiert konkret Folgendes:
- Woodpecker schickt den Container-Create an die Agent-API.
- Codeberg hat
head1328/woodpecker-ci-plugin-podmannicht in seiner Server-Allowlist, also kommt der Request mitPrivileged=false. - Der Agent Guard sieht das Image in
WALLY_GUARD_PRIVILEGED_IMAGES, schreibt den Request aufPrivileged=trueum und leitet ihn an Podman weiter. - Das Plugin läuft im privilegierten Pipeline-Container und ruft
podman build --platform=linux/amd64,linux/arm64 --manifest=...auf. - Für den linux/arm64-Build öffnet
podman buildeinen frischen rootless Userns. Der erste exec eines arm64-Binaries (/bin/shaus dem Alpine-Image) triggert denbinfmt_misc-Lookup im Kernel; der Kernel findetqemu-aarch64mitF-Flag und nutzt den bereits offenen Interpreter-FD direkt. RUN apk add jq ca-certificatesläuft im arm64-Container überqemu-aarch64-static.uname -mmeldetaarch64.
Lizenzen#
Alle drei Projekte stehen unter Apache 2.0.
Verwendete Projekte#
- Woodpecker CI - container-nativer CI-Agent
- Codeberg - Forgejo-basierte Git-Forge mit Woodpecker-CI-Integration
- Fedora CoreOS - minimales, transaktional aktualisiertes Container-Host-OS
- Podman - daemonless Container-Runtime
- QEMU
- Maschinen-Emulator (
qemu-user-staticfür die Userspace-Emulation) - Hetzner Cloud - Cloud-Provider mit IPv6-only-Servern
Hat dir das hier geholfen?
Unterstütze gerne via:
