AlmaLinux 9 module stream switching versus rootless Podman for reproducible development environments
0 reputation · 26 Jun 2024, 10:08 UTC
0 reputation · 26 Jun 2024, 10:08 UTC
AlmaLinux 9 ships dnf module streams for language runtimes such as Node.js, Python, and Go, allowing version selection via dnf module install nodejs:18. Switching streams requires dnf module reset followed by dnf module enable, a non‑transactional sequence that can leave orphaned packages or unresolved dependencies. The AlmaLinux Build System publishes these streams, yet a consolidated lifecycle and support matrix for each stream is not documented in a single authoritative source.
Podman provides rootless containers as a distribution‑agnostic isolation layer. A container based on almalinux:9 can pin exact runtime versions without mutating the host package database. However, rootless operation introduces filesystem‑permission and networking constraints that may affect tooling such as bind‑mounted source directories or local database servers.
Neither the official AlmaLinux documentation nor the SIG guidelines explicitly recommend one approach over the other for repeatable development environments. Teams must weigh module‑stream mutability against container‑runtime overhead and SELinux interactions.
What criteria should guide the choice between dnf module streams and rootless Podman containers when the goal is a reproducible, low‑friction development environment on AlmaLinux 9? How can the undocumented stream support windows be factored into that decision? What SELinux policy adjustments are typically required for each path?
For a reproducible, low-friction development environment on AlmaLinux 9, rootless Podman with a pinned almalinux:9-based image is the stronger default. Module streams are the right choice only when the environment is simple — one runtime, one version, no per-project isolation needs — and you want zero container tooling. The deciding factor is that a Containerfile pins exact versions and travels with the project, while a module stream mutates the host package database and depends on whatever the repos happen to offer at rebuild time.
Switching streams is not atomic. The sequence dnf module reset nodejs followed by dnf module install nodejs:20 can fail partway, leaving orphaned packages from the old stream or unresolved dependencies. Before any switch, capture the current state so rollback is possible:
dnf module list --enabled
rpm -qa | grep -E '^(nodejs|python3\.|golang)' > /root/pre-switch-packages.txtEven when the switch succeeds, the stream's contents change over time as the repos publish updates, so "rebuild this machine from scratch in six months and get identical versions" is not guaranteed. A container image digest is.
Module stream lifecycles generally track the upstream runtime's support window, not the full AlmaLinux 9 lifecycle, and there is no single consolidated AlmaLinux support matrix for every stream. Treat this as a per-stream verification task rather than an assumption:
dnf module list nodejs (or python, go) to see available streams and which is enabled.This uncertainty itself is an argument for containers: a pinned image keeps working after a stream goes EOL, though you then own security patching of the image.
Module streams install stock, confined packages, so SELinux normally requires no adjustment at all — a genuine operational advantage.
Rootless Podman is mostly handled by the container-selinux policy, but two issues come up routinely:
:z (shared between containers) or :Z (exclusive):podman run --rm -v "$PWD:/src:Z" almalinux:9 ls /src
ls -Z # confirm the relabel happenedNote that :Z relabels exclusively for one container and can break access for other containers or host tools; prefer :z for shared source trees. For custom paths outside home, you may need semanage fcontext plus restorecon.
127.0.0.1 is not reachable from the container's loopback. Publish ports explicitly or use --network=host where acceptable.| Criterion | Module streams | Rootless Podman |
|---|---|---|
| Reproducibility across hosts/time | Weak — repo contents drift | Strong — pinned image digest |
| Multiple runtime versions per host | Painful — reset/enable churn | Native — one image per project |
| SELinux work | None | Volume labels (:z/:Z), occasional fcontext |
| Support-window clarity | Must verify upstream EOL per stream | You own image patching |
| CI/dev parity | Poor | Good — same image everywhere |
A hybrid works well in practice: keep the AlmaLinux 9 host minimal and stable, and run each project's toolchain in a pinned almalinux:9-based image. This eliminates stream switching entirely. Verify the setup by rebuilding from scratch on a clean VM and confirming the Containerfile yields identical tool versions. Rootless Podman behavior (subuid/subgid mapping, fuse-overlayfs) varies across 9.x minor releases, so test against your installed podman --version before standardizing.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.