Skip to main content

Podman 6.0 Goes Rootless by Default — And No, It Still Isn't Your Kubelet's Container Runtime

8 min readDora NodaDora Noda
Share

Podman 6.0 shipped June 24, 2026, and the first thing worth saying about it has nothing to do with the release notes: Podman was never your kubelet's container runtime, and this release doesn't change that. Kubernetes has required a CRI (Container Runtime Interface)-compliant runtime since dockershim was ripped out in v1.24 back in 2022 — that's containerd or CRI-O, not dockerd and not Podman. If you've been putting off a "should we switch to Podman on our nodes" decision, there's no decision to make; it was never pluggable there in the first place.

The confusion isn't irrational. Podman has spent years marketing itself as a "drop-in replacement for the docker command," and for years before that, dockerd genuinely was what a kubelet talked to — so it's an easy analogical leap from "Podman replaces docker" to "Podman replaces docker on my Kubernetes nodes." It's just wrong on the second half. docker the CLI and dockerd the daemon that used to serve the kubelet are two different things, and Podman only ever competed with the first one.

What Podman 6.0 does do is make rootless mandatory, delete four legacy subsystems outright, and expand Quadlet's systemd-native model with a REST API and new volume options. None of that touches your kubelet — but it touches almost everything else a self-hosted PaaS runs on the same node beside it.

PodmanCRI-Ocontainerddockerd
Kubelet-pluggable (CRI)?No — never wasYesYes (kubeadm/Talos default)No, since Kubernetes v1.24
Runs a persistent daemon?No — fork/exec per commandYes, one per nodeYes, one per nodeYes, one per node
Who actually calls itA human, a CI runner, a build pipelineThe kubeletThe kubeletNobody's kubelet anymore
Pod/container networking (2026)Netavark + Pasta only (CNI removed in 6.0)CNI plugins the cluster's CNI (Calico, Cilium, etc.) configuresSame CNI path as CRI-ODocker bridge / CNI
Rootless by defaultYes, as of 6.0 (June 2026)Partial/experimentalNoNo

That table is the whole correction in miniature. Podman and CRI-O share plumbing — both build on containers/storage, containers/common, and crun — which is exactly why they get confused for interchangeable choices. They aren't. One is a tool a person or a build pipeline runs by hand; the other is a long-running daemon the kubelet calls over a gRPC socket on every pod lifecycle event. Podman 6.0 doesn't make the jump from the first column to the second.

What actually shipped in 6.0

Four things got removed outright, not deprecated-with-a-warning:

  • slirp4netns is gone. Pasta, the default rootless network path since Podman 5.0, is now the only rootless network path.
  • CNI networking is gone. Netavark — Podman's own Rust-based network stack — is now the sole backend for both rootful and rootless containers, and it drops iptables in favor of nftables along the way.
  • cgroups v1 support is gone. A node still running a cgroup v1 kernel doesn't get a deprecation warning; Podman 6.0 simply won't run workloads that need it.
  • The BoltDB storage backend is gone. Anything still on BoltDB (superseded by SQLite as the default back in Podman 4.8) gets migrated automatically on first startup — a one-way door.

Alongside the removals, Quadlet — Podman's mechanism for defining containers, volumes, and networks as systemd unit files instead of imperative podman run invocations — picked up a REST API for querying and managing inactive Quadlet units (the gap that made tools like Cockpit's Podman integration unable to see a stopped unit), reorganized its on-disk layout into per-unit subdirectories instead of a single .app tracking file, and added UID=, GID=, and Options= keys to .volume units. None of this is exotic — it's Podman continuing to harden the "systemd manages my containers" story it's been building since Quadlet's introduction. The companion-version coordination is real, though: 6.0 requires Buildah 1.44, Skopeo 1.23, and Netavark/Aardvark 2.0 — mismatch any of those and you'll hit configuration-parsing errors, not a clean failure.

Two smaller additions round out the release: --gpus now recognizes AMD hardware for podman create/podman run, not just NVIDIA's, and Podman Machine (the VM layer behind Podman on macOS and Windows) gained a podman machine os update command plus --import-native-ca for pulling the host's CA trust store into the VM — both aimed squarely at the local-dev half of the audience, not the fleet-operations half.

Where this actually lands on a Cluster-API-managed Hetzner node

If Podman isn't what your kubelet calls, where does a rootless-by-default Podman 6.0 change anything for a self-hosted PaaS running its own Cluster-API fleet? Two places, concretely:

Host-level Quadlet units running beside the kubelet. A CAPH-provisioned Hetzner node runs more than kubelet-managed pods — a node-exporter instance, a log shipper, a Headscale or WireGuard sidecar, a one-off maintenance script — services an operator often wires up as a systemd unit directly on the host rather than routing through the cluster's own scheduler. Before 6.0, getting that unit to run without a root Podman socket meant explicitly opting into --user-scoped Quadlet configuration and getting the UID/GID mapping right yourself. In 6.0, rootless is simply what you get by not asking for root — one fewer privileged process listening on a shared multi-tenant box, without an operator having to remember to ask for it.

Local and CI image-build pipelines. A platform team building the images that eventually land in a tenant's registry doesn't need Docker Desktop's daemon (or its licensing) to do it — Podman and Buildah build OCI images directly, no long-lived root process required on a laptop or a shared CI runner. That's true independent of 6.0, but the release's insistence on rootless-as-default plus the Buildah 1.44 pairing is a forcing function to actually verify that pipeline is rootless today, not "rootless-capable, if someone remembers to pass the flag."

What 6.0 does not change is the node image itself. kubernetes-sigs/image-builder, the tooling CAPH's own docs point to for baking custom node images, builds those images with Packer and Ansible — not Podman or Buildah. So there's no image-build-pipeline dependency lurking inside your node image that this release forces you to touch.

The security case for caring at all is the same one rootless containers have always made, just harder to opt out of now: a process escaping a rootful Podman container lands on a host root shell and a Unix socket other root processes trust; the same escape from a rootless container lands in a remapped, unprivileged UID namespace with no privileged socket to reach for. On a shared multi-tenant Hetzner box running a handful of host-level sidecars next to tenant workloads, that's the difference between an escaped process being a contained embarrassment and a fleet-wide incident. Podman 6.0 doesn't add that property — it just stops letting an operator forget to ask for it.

The pre-flight checklist before you flip the switch anywhere

Because the breaking changes are deletions, not warnings, verify these before letting 6.0 anywhere near a shared node — whether that's a Quadlet-managed sidecar or a CI runner's build image:

  1. Kernel check. Confirm every node image is on cgroup v2. A cgroup v1 kernel doesn't degrade gracefully here — Podman 6.0 refuses to run the affected workloads.
  2. Storage migration. If any host has an existing Podman install still on BoltDB, the migration to SQLite happens automatically on upgrade — but it's one-way, so back up containers/storage state first if that host matters.
  3. Network re-creation. Any podman network defined against the old CNI backend doesn't carry over — it has to be re-declared under Netavark. If a Quadlet .network unit references a CNI-era config, it silently stops resolving the way it used to.
  4. Companion-version lockstep. Buildah, Skopeo, and Netavark/Aardvark all need to move to their 6.0-compatible versions together. A build pipeline that pins Podman 6.0 against an older Buildah will hit config-parsing failures that look like a Podman bug but aren't.
  5. Stage the Quadlet migration on one node first. The reorganized on-disk layout (subdirectories instead of a single .app file) and the new REST-visible inactive-unit state are the kind of change that's easy to verify on a single Hetzner box and expensive to discover fleet-wide — roll it to one node, confirm systemctl status and the new Quadlet REST endpoint agree on what's running, then template the change into the rest of the fleet's bootstrap.

The bottom line for the runbook

Podman 6.0 doesn't touch the one decision people keep reaching for it to make — containerd or CRI-O is still what your kubelet talks to, and that hasn't been up for debate since 2022. What it does do is raise the security bar, by default, for every host-level container a self-hosted fleet runs beside the kubelet rather than through it: the sidecars, the maintenance scripts, the image builds. That's a smaller story than "Podman replaces your container runtime," but it's the true one, and it's worth verifying — kernel, storage, network, and companion versions — before the upgrade lands on a node you can't afford to lose for an afternoon.

Bex.co is the open-source, AI-native Render alternative — push a git repo, get a running HTTPS service on machines you own, orchestrated by Cluster API on hardware you actually control. Star the repo on GitHub or deploy your first app today.

Related articles

Run this on infrastructure you own

bex is the open-source, AI-native Render alternative — push a git repo and get a running HTTPS service on your own machines.

Get started with bex