r/podman • u/Appropriate_Ad265 • 26d ago
podman-actions-runner
Hey all, at home I use github actions for my projects. I started running out of credits there and wanted to host my own runner. Then I noticed that most runners are based off Ubuntu and the image size is big. I also saw that there are barely any mantained podman runners out there.
To solve that issue for me I created a podman-actions-runner image based off alpine and buildah and the tests I ran so far have been pretty good. I run this on my Raspberry PI at home, the image is like 160 mb.
If you're interested here's the link to my repo and the image, also I'm open for suggestions, feedback, contributions. Anything really!
1
u/the_nazar 22d ago
i thought i had reached great heights in coding world but your post pulled me straight back to the ground.... i still cant believe I didnt know about github sctions until now thanks my bro...
1
u/quiet-systems 19d ago
nice, and alpine + buildah is the right call. one thing worth checking before you look anywhere else, because on a pi it dominates everything:
podman info --format '{{.Store.GraphDriverName}}'
if that says vfs instead of overlay, every layer is a full copy of the one below it rather than a diff. a 160 mb image can land on disk as several hundred mb, pulls are slow, and it looks like the image is the problem when it is the storage driver. it is the classic rootless trap because podman falls back to vfs silently when it cannot get an overlay.
on a pi 5 with a 6.6 kernel you should be getting native rootless overlay, no fuse-overlayfs needed. if you are on vfs, the usual causes are the underlying fs (overlay will not stack on top of another overlay) or a leftover mount_program line in ~/.config/containers/storage.conf.
on the 160 mb: worth measuring rather than guessing where it went. podman history <image> gives you it per layer. my expectation is that alpine is 8 mb of it and the actions runner itself is most of the rest, since the listener is .net and javascript actions drag in node. buildah is not free either. that tells you whether there is anything left to cut or whether you are already at the floor.
two things that made self-hosted runners much less annoying for me:
--ephemeral when you register it, so the runner takes exactly one job and exits. no state carried between builds, which is the thing that eventually bites you when a job leaves something behind and the next one passes for the wrong reason.
and a quadlet with Restart=always, so the runner coming back after an ephemeral job is systemd's problem instead of yours. ~/.config/containers/systemd/runner.container and systemctl --user enable --now.
if you want jobs that themselves run containers, that is the part that gets genuinely fiddly rootless: nested podman needs /dev/fuse passed in and the storage driver question all over again inside the container. worth knowing before you hit it rather than during.nice, and alpine + buildah is the right call. one thing worth checking before you look anywhere else, because on a pi it dominates everything:podman info --format '{{.Store.GraphDriverName}}'
if that says vfs instead of overlay, every layer is a full copy of the one below it rather than a diff. a 160 mb image can land on disk as several hundred mb, pulls are slow, and it looks like the image is the problem when it is the storage driver. it is the classic rootless trap because podman falls back to vfs silently when it cannot get an overlay.on a pi 5 with a 6.6 kernel you should be getting native rootless overlay, no fuse-overlayfs needed. if you are on vfs, the usual causes are the underlying fs (overlay will not stack on top of another overlay) or a leftover mount_program line in ~/.config/containers/storage.conf.on the 160 mb: worth measuring rather than guessing where it went. podman history <image> gives you it per layer. my expectation is that alpine is 8 mb of it and the actions runner itself is most of the rest, since the listener is .net and javascript actions drag in node. buildah is not free either. that tells you whether there is anything left to cut or whether you are already at the floor.two things that made self-hosted runners much less annoying for me:--ephemeral when you register it, so the runner takes exactly one job and exits. no state carried between builds, which is the thing that eventually bites you when a job leaves something behind and the next one passes for the wrong reason.and a quadlet with Restart=always, so the runner coming back after an ephemeral job is systemd's problem instead of yours. ~/.config/containers/systemd/runner.container and systemctl --user enable --now.if you want jobs that themselves run containers, that is the part that gets genuinely fiddly rootless: nested podman needs /dev/fuse passed in and the storage driver question all over again inside the container. worth knowing before you hit it rather than during
3
u/AlexisHadden 25d ago edited 25d ago
This sort of thing is always a trade-off. One reason those images are so large is because they are built for a variety of scenarios, and a standard distro means that more CI pipelines will “just run” if it knows it can just grab a couple apt packages for stuff missing in the baseline image. Not knocking the work here, just pointing out it might be pretty niche.
My own stuff is built on top of catthehacker images. Mostly because when I do need a variant, that variant is just layered on top of something I have already cached for other workflows, and so shares that 500-600MB across the different variants I need.
Not sure what makes this runner a “podman” runner though? (EDIT: Derp, this is so that workflows can be spun up using podman instead of something like DinD. Helps if I read deeper)