Podman¶
Note
This page covers local development only. The published host container image ships podman and its own storage config — no setup needed for production deployments.
Installation¶
Podman is provided by the devenv shell on all platforms — no manual
installation needed. All podman commands on this page assume you are
inside the devenv shell (devenv shell).
Storage¶
Klangk uses rootless podman with --userns=keep-id:uid=1000,gid=1000 (the
KLANGKD_USERNS default) to run workspace containers. This maps the
host user's UID into the container so files on bind mounts are owned
correctly.
When --userns=keep-id... is used, podman must remap UIDs/GIDs in every
image layer. It does this via storage-chown-by-maps — a recursive
chown of the layer tree. This is slow on first container creation
(10-30s depending on image size) but subsequent creates reuse cached
layers and are fast.
A note on "Supports shifting"¶
Running podman info | grep "Supports shifting" shows whether the
kernel's idmapped mount feature is available, which would skip the
recursive chown entirely. In practice, this is always false for
rootless podman — the kernel requires CAP_SYS_ADMIN in the
initial mount namespace to use mount_setattr with MOUNT_ATTR_IDMAP,
which rootless users don't have. Only rootful (sudo) podman can
achieve Supports shifting: true.
This means storage-chown-by-maps is the normal and expected path
for rootless podman.
Container Policy¶
Podman requires a container signature policy file to pull and manage images. The devenv shell creates one automatically, but outside of devenv (e.g., production deployments) you need to create it yourself:
mkdir -p ~/.config/containers
cat > ~/.config/containers/policy.json <<'EOF'
{
"default": [
{
"type": "insecureAcceptAnything"
}
]
}
EOF
Alternatively, create it system-wide at /etc/containers/policy.json.
Without this file, podman operations fail with confusing errors about
missing signatures or policies.
Short Image Names (registries.conf)¶
Podman also needs a containers-registries.conf(5) to resolve a short
image name like alpine:3.21 to a registry. The devenv shell creates one
automatically (unqualified-search-registries = ["docker.io"], exported
via CONTAINERS_REGISTRIES_CONF), but outside of devenv you need to
create it yourself:
mkdir -p ~/.config/containers
cat > ~/.config/containers/registries.conf <<'EOF'
unqualified-search-registries = ["docker.io"]
EOF
Without this file, builds referencing a short name fail with short-name
"alpine:3.21" did not resolve to an alias and no
containers-registries.conf(5) was found. Alternatively, use a
fully-qualified image reference (docker.io/library/alpine:3.21) in the
Dockerfile, which skips resolution entirely.
Configuring Storage¶
By default, podman stores images and runtime state under
~/.local/share/containers/. To use a different location (e.g. a
larger volume), create or edit ~/.config/containers/storage.conf:
NixOS¶
Klangk runs rootless podman. The NixOS module
virtualisation.containers.storage.settings writes to
/etc/containers/storage.conf, which only applies to root podman.
Rootless podman ignores it and uses ~/.config/containers/storage.conf
instead. Create that file manually (as shown above) or use home-manager.
macOS¶
No storage configuration needed. Podman runs in a Linux VM with its own ext4 storage.
Resetting After Config Changes¶
Podman persists storage paths in a SQLite database (db.sql) on first
run. Changing storage.conf alone is not enough — podman ignores
config changes if the database already exists. After changing storage
paths:
This removes all containers, images, and volumes. Rebuild the workspace
image afterward with devenv up.
Troubleshooting¶
Container creation is slow¶
First container creation with --userns=keep-id is always slow
(10-30s) due to storage-chown-by-maps. This is normal for rootless
podman. Subsequent creates reuse cached layers and are fast.
"database run root does not match our run root"¶
Podman's database has a cached path that doesn't match your config.
Run podman system reset --force.
"Found incomplete layer, deleting it"¶
Storage was corrupted by a prior interrupted operation (e.g., a container create that was killed mid-write). Run:
Or if that hangs too, podman system reset --force.