Skip to content

RFC: add rootless podman to the Linux builder image (unblock Docker-required recipes without DinD privileges) #351

@tannevaled

Description

@tannevaled

Summary

Adding rootless podman (plus the supporting bits: fuse-overlayfs, slirp4netns, /etc/subuid/subgid mappings) to brewkit's Linux builder container image would unblock a class of pantry recipes that need to invoke a container runtime during build — without exposing the host docker socket or running the build privileged.

What this unblocks (concrete recipe pipeline)

Recipe Current state What containerization solves
k0s (pantry#13137) Parked. make build needs docker build to construct .k0sbuild.docker-image.k0s (the codegen tooling host). docker: not found in CI. podman build produces the same OCI image
CockroachDB (pantry#13122 / #13123) Parked. Modern CockroachDB build is bazel-only; bazel itself runs codegen via docker containers. bazel's @docker_repository rules use rootless podman if it's on PATH
Harbor (pantry#13134) Parked as feasibility issue. Upstream Makefile compiles every Go binary inside golang:1.26.3 and bakes them into Photon Linux container images. Replicable with podman build
kubebuilder/controller-gen pipelines (anything using kubernetes-sigs/code-generator) Various recipes work around by stripping codegen. The standard upstream pattern is docker run kube-codegen — works with podman
emscripten (pantry#13065) Required a separate binaryen recipe rather than the upstream ./emsdk flow. emsdk can be docker-orchestrated upstream-style if needed

Why podman rootless and not docker-in-docker

The classic Docker DinD pattern requires --privileged on the outer container, which:

  • Grants full host-kernel capabilities (CAP_SYS_ADMIN, mount, etc.)
  • Bypasses seccomp/AppArmor on the host
  • Effectively defeats the isolation provided by running builds in containers

Rootless podman avoids all of that:

  • No daemon process to run as root
  • Uses unprivileged user namespaces (kernel ≥ 4.18, mainstream since 5.13)
  • Storage: fuse-overlayfs user-space overlay, no kernel module needed
  • Networking: slirp4netns user-space network stack
  • Build: buildah (also rootless) can do Dockerfile-equivalent builds

It is the established pattern at:

  • Fedora/RHEL as the default since RHEL 8
  • Gitlab Runner rootless mode
  • GitHub Actions Linux runners (have podman + docker pre-installed for the same reason)
  • nixpkgs (NixOS modules use rootless podman for any container needs)

What needs to change in brewkit

The current Linux builder container image (referenced in pkgxdev/brewkit's build action) would add:

  1. Install: podman, buildah, fuse-overlayfs, slirp4netns, uidmap
  2. Kernel/sysctl: ensure kernel.unprivileged_userns_clone=1 (default on most modern kernels)
  3. User mappings: /etc/subuid and /etc/subgid with builder:100000:65536 (so 65k container UIDs are mapped under the builder user)
  4. PATH alias: optionally ln -s /usr/bin/podman /usr/bin/docker so existing recipes that hardcode docker work transparently (Fedora ships this by default)

Disk overhead: ~50-100 MB on the builder image. Build-time overhead per recipe: zero if not invoked.

Security trade-off vs current state

Current state: builds run inside a non-privileged container, can do anything a normal user can.

With rootless podman: builds can additionally podman build an image (using only their user-mapped subordinate UIDs) and podman run containers as that mapped user. They cannot:

  • Mount host filesystems (no CAP_SYS_ADMIN)
  • Access the host docker daemon (there is none in the builder)
  • Escape their user namespace

This is strictly less powerful than DinD, and arguably the same security boundary as the current "build can fork arbitrary processes" state.

Alternative considered: qemu-system / firecracker microVMs

For maximum isolation, a microVM (firecracker, libkrun) inside the builder could provide a full nested VM with its own docker daemon. This is what Earthly, Dagger, and nestybox/sysbox do. Trade-off: ~300-500 MB image overhead, ~10s VM boot per build, full guest kernel to maintain. Much heavier than podman rootless; probably overkill for the recipe set involved.

qemu-user — already present, doesn't apply

brewkit already uses qemu-user for cross-arch builds (linux/aarch64 builds on linux/x86-64 hosts). qemu-user emulates a different CPU arch but does NOT provide container runtime semantics — so it doesn't unblock Docker-needing recipes.

Action requested

If maintainers agree:

  1. Update the brewkit builder image to install rootless podman + dependencies
  2. Document the availability in brewkit's recipe-author docs
  3. Pantry contributors (like myself) can then unpark the recipes listed above

If maintainers prefer to keep the current zero-container-tooling stance:

  • The realistic alternative is to mark Docker-required recipes as warnings: - vendored and ship upstream's signed binary tarballs. The pantry precedents (ziglang.org, bun.sh, protoc) already accept this for compiler-bootstrap cases; extending the same pattern to k0s / cockroach / harbor would be consistent.

Either path is defensible. This issue exists to surface the choice rather than letting the recipes sit indefinitely parked.

Related parked recipes

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions