What?/Why?
I used Forgejo instance for a long time mainly to backup my projects from GitHub, but few days ago, I came to conclusion it would be great to have CI/CD working on my instance of Forejo, mainly for building container images.
I had an Raspberry Pi 5 with podman installed, so without hesitation I started installing the runner on it. It went smoothly, the official documentation described all the steps.
However the breaking point was building container images in CI.
I really needed wanted it, and got a few key requirements:
- debian (While I love podman, I am used to Debian, so images need to be debian-based.)
- no
--priviledged
(Apart from thedata.forgejo.org/forgejo/runner
control container, nothing should have any more privileges.) - reasonable speed (Downloading the base images for build for every CI job was not an option.)
Podman in Podman Debian image
The first step was to create podman image, which could run podman without other priviledges (or tunneling host podman socket). After a long struggle with uidmaps and storage I came up with this Containerfile.
FROM debian:trixie
RUN apt-get update && \
apt-get upgrade -y && \
apt-get install -y \
podman slirp4netns uidmap \
git curl iputils-ping nodejs zstd && \
rm -rf /var/cache/apt/archives /var/lib/apt/lists/*
RUN useradd podman && \
echo -e "root:1:65535\npodman:1:999\npodman:1001:64535" > /etc/subuid && \
echo -e "root:1:65535\npodman:1:999\npodman:1001:64535" > /etc/subgid
ADD ./containers.conf /etc/containers/containers.conf
ADD ./storage.conf /home/podman/.config/containers/storage.conf
RUN mkdir -p /home/podman/.local/share/containers && \
chown podman:podman -R /home/podman && \
chmod 0644 /etc/containers/containers.conf
VOLUME /home/podman/.local/share/containers
# Replace setuid bits by proper file capabilities for uidmap binaries.
# See <https://github.com/containers/podman/discussions/19931>.
RUN apt-get install -y libcap2-bin && \
chmod 0755 /usr/bin/newuidmap /usr/bin/newgidmap && \
setcap cap_setuid=ep /usr/bin/newuidmap && \
setcap cap_setgid=ep /usr/bin/newgidmap && \
apt-get autoremove --purge -y libcap2-bin
ENV _CONTAINERS_USERNS_CONFIGURED=""
USER podman
WORKDIR /home/podman
# containers.conf
[containers]
netns="host"
userns="host"
ipcns="host"
utsns="host"
cgroupns="private"
cgroups="enabled"
log_driver = "k8s-file"
volumes = [
"/proc:/proc"
]
[engine]
cgroup_manager = "cgroupfs"
events_logger="file"
runtime="crun"
# storage.conf
[storage]
driver="overlay"
[storage.options]
additionalimagestores=["/images"]
It is based mainly on existing Containerfile for fedora. Nevertheless there are differences and some tweaks.
Storage driver
The podman storage driver is set to overlay
.
On the Raspberry Pi 5 it drastically reduces the time needed to start the container.
Shared image storage
Every CI job has its own podman container to run podman.
Without some sort of cache every CI job needs to download the images.
To reduce this issue, I stumbled upo additionalimagesstore
option for podman,
which enables to store R/O images in other parts of the filesystem.
Specifically, the Containerfile
sets this directory to /images
.
Later when configuring the Forgejo runner, volume is mounted to this path with
read-only access. Later on the setup of it.
Building the image
Building the image is fairly straightforward, simply build the Containerfile.
podman build -t pip-runner .
Setup shared image storage
# create the storage directory
mkdir ./images
# allow the container to create sub-directories in ns
chmod a+rwx ./images
# pull the needed images
podman run -v $(pwd)/images/:/images pip-runner \
podman --root /images pull debian:bookworm
# (optional) remove the rwx access on the directory
chmod go-rwx ./images
After this setup, the following podman command should return all the pulled images. All of them should be marked as R/O in the last column, which indicates it is available on read-only image storage.
podman run -v $(pwd)/images/:/images:ro -it --rm pip-runner podman images
Creating containers from the downloaded images should now be near instant.
Configuring the Forgejo Runner
There are no differences in the initial configuration of the runner from the docs,
however the config.yaml
should be edited to contain the imagestore
volume.
labels:
- "debian:docker://pip-runner:latest"
container:
enable_ipv6: true
docker_host: "-"
network: "podman"
options: "--volume /path/to/imagestore:/images:ro"
valid_volumes:
- /path/to/imagestore
Conclusion
Repository containing the source files for the image is available in this GitHub Gist.
I would be extremely surprised, if someone would actually use some of the above, but maybe, there is someone else with these very niches requirements.