As part of moving my services to EU-based infrastructure, I’ve been migrating away from GitHub to Codeberg, a non-profit code hosting platform based in Germany. One of the things I needed was a CI pipeline to build a container image and push it to the Codeberg container registry for my wildfires project (which also posts to @catfires@rls.social). It took a few tries to get right, so here’s what works for me.
The workflow
name: Build and push container image
on:
push:
branches:
- main
jobs:
build:
runs-on: codeberg-small
steps:
- name: Checkout
uses: https://code.forgejo.org/actions/checkout@v4
- name: Install buildah
run: apt-get update -qq && apt-get install -y buildah ca-certificates
- name: Build image
run: |
buildah build \
--storage-driver=vfs \
--isolation=chroot \
--tag codeberg.org/YOUR_USERNAME/YOUR_IMAGE:latest \
.
- name: Push image
run: |
buildah push \
--storage-driver=vfs \
--creds YOUR_USERNAME:${{ secrets.REGISTRY_TOKEN }} \
codeberg.org/YOUR_USERNAME/YOUR_IMAGE:latest
Registry token
The automatic FORGEJO_TOKEN cannot push to the container registry. You need a personal access token with write:packages scope. Create one under Settings → Applications → Access Tokens, then add it as a repository secret named REGISTRY_TOKEN under Settings → Actions → Secrets.
Why buildah, and why those flags
Codeberg’s hosted runners are rootless Podman containers running inside LXC containers. Neither docker nor podman are available. buildah is the right tool here, but it needs two flags to work in this environment:
--storage-driver=vfs— the default overlay driver needs FUSE, which isn’t available inside the nested container--isolation=chroot— avoids namespace operations that require elevated privileges
Both flags are needed on buildah build and buildah push.
What didn’t work
docker/build-push-action— tries to connect to/var/run/docker.sockwhich doesn’t existpodman builddirectly — not installed on the runnersbuildahwithout--storage-driver=vfs— fails because overlayfs requires FUSE