Wolfi is a rolling-release Linux undistro: Alpine's packaging conventions, glibc instead of musl, no kernel. Chainguard Containers are built on it. This repo is the same idea but for things Chainguard doesn't ship, plus a few opinions of my own.
Every image is a declarative apko YAML. No RUN curl $DODGY_URL | sh, no layer cache busting, no recompiling the world when the base changes. The build is reproducible and every file in the image is owned by an APK with a version, a license, and a recipe you can read.
Two properties fall out of this for free:
- Composability. Bump one package, rebuild one layer. Nothing else recompiles.
- Accountability. Every file lives in
/usr/bin,/usr/lib,/etc— not/app/or whatever cursed directory the upstreamDockerfileinvented.
Custom packages that aren't in Wolfi yet are built with melange and live in vaskozl/wolfi-packages. Built APKs are published to https://apks.sko.ai.
A subset — bootc, containerd, niri, cagebreak, pinewall-config — are also bootable hosts via bootc. For how the pieces fit together, see Making Bootable Wolfi Containers.
Tags follow the upstream Wolfi package version. ghcr.io/vaskozl/kubectl:1.33.1-r0 is also available as:
ghcr.io/vaskozl/kubectl:1.33.1ghcr.io/vaskozl/kubectl:1.33ghcr.io/vaskozl/kubectl:1ghcr.io/vaskozl/kubectl:latest
Even pinned tags are rebuilt nightly to pick up security fixes, so they're not immutable. Pin by digest if you need that guarantee.
Renovate keeps the =version pins in the YAML files fresh via a custom renovate-apk-indexer datasource that reads APKINDEX.tar.gz.
Images have no custom entrypoint scripts. Pass the command and arguments directly. Configuration goes in via volume mounts. For real-world examples see vaskozl/home-infra.
- Packages (
melangerecipes, APK registry):vaskozl/wolfi-packages - Home infra manifests:
vaskozl/home-infra - Router config:
vaskozl/pinewall-config