Using podman with alpine 3.22.1

I planned create some virtual machines and want use more alpine to manage my containers, even following the official documentation for that I spent some time making everything work as expected then wrote the needed steps above.

That setup was executed against Alpine 3.22.1 inside HyperV.

1
2
3
4
5
6
7
root:~# cat /etc/os-release
NAME="Alpine Linux"
ID=alpine
VERSION_ID=3.22.1
PRETTY_NAME="Alpine Linux v3.22"
HOME_URL="https://alpinelinux.org/"
BUG_REPORT_URL="https://gitlab.alpinelinux.org/alpine/aports/-/issues"

Running podman as root

After install alpine we need to edit /etc/apk/repositories removing the comment of the community packages like that:

#/media/cdrom/apks
http://dl-cdn.alpinelinux.org/alpine/v3.22/main
http://dl-cdn.alpinelinux.org/alpine/v3.22/community

After that we can update and install podman:

1
2
root:~$ apk update
root:~$ apk add podman

Try run podman run busybox but you will receive that error:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
root:~$ podman run busybox
WARN[0000] Using cgroups-v1 which is deprecated in favor of cgroups-v2 with Podman v5 and will be removed in a future version. Set environment variable `PODMAN_IGNORE_CGROUPSV1_WARNING` to hide this warning.
Resolved "busybox" as an alias (/etc/containers/registries.conf.d/00-shortnames.conf)
Trying to pull docker.io/library/busybox:latest...
Getting image source signatures
Copying blob 80bfbb8a41a2 done   |
Copying config 0ed463b26d done   |
Writing manifest to image destination
Your kernel does not support pids limit capabilities or the cgroup is not mounted. PIDs limit discarded.
Error: netavark: iptables: No such file or directory (os error 2)

You wil need to enable cgroups and reboot

1
2
3
root:~$ rc-update add cgroups
root:~$ rc-service cgroups start
root:~$ reboot

Now you can try again podman run busybox but you receive:

1
2
root:~$ podman run busybox
Error: netavark: iptables: No such file or directory (os error 2)

To solve that we need to install nftables and configure to podman use that:

Change /etc/containers/containers.conf and change firewall_driver to nftables like that:

1
2
3
4
5
6
# The firewall driver to be used by netavark.
# The default is empty which means netavark will pick one accordingly. Current supported
# drivers are "iptables", "nftables", "none" (no firewall rules will be created) and "firewalld" (firewalld is
# experimental at the moment and not recommend outside of testing).
#
firewall_driver = "nftables"

After that install nftables with apk:

1
root:~$ apk add nftables

Now you can execute podman normally as root.


Running podman as non-root

You can now setup a local user with setup-user command or use a already created user, I will use lab user in the following commands:

1
2
lab:~$ id
uid=1000(lab) gid=1000(lab) groups=1000(lab)

If you try to execute podman as lab it will break with that message:

1
2
3
4
5
6
7
8
9
lab:~$ podman run busybox
WARN[0000] "/" is not a shared mount, this could cause issues or missing mounts with rootless containers
ERRO[0000] cannot find UID/GID for user lab: no subuid ranges found for user "lab" in /etc/subuid - check rootless mode in man pages.
WARN[0000] Using rootless single mapping into the namespace. This might break some images. Check /etc/subuid and /etc/subgid for adding sub*ids if not using a network user
Resolved "busybox" as an alias (/etc/containers/registries.conf.d/00-shortnames.conf)
Trying to pull docker.io/library/busybox:latest...
Getting image source signatures
Copying blob 80bfbb8a41a2 done   |
Error: internal error: unable to copy from source docker://busybox:latest: copying system image from manifest list: writing blob: adding layer with blob "sha256:80bfbb8a41a2b27d93763e96f5bdccb8ca289387946e406e6f24053f6a8e8494"/""/"sha256:80e840de630d08a6a1e0ee30e7c8378cf1ed6a424315d7e437f54780aee6bf5a": unpacking failed (error: exit status 1; output: potentially insufficient UIDs or GIDs available in user namespace (requested 65534:65534 for /home): Check /etc/subuid and /etc/subgid if configured locally and run "podman system migrate": lchown /home: invalid argument)

Lets configure subuid and subgid:

1
2
3
4
root:~$ modprobe tun
root:~$ echo tun >>/etc/modules
root:~$ echo lab:100000:65536 >/etc/subuid
root:~$ echo lab:100000:65536 >/etc/subgid 

And then as your user execute that:

1
lab:~$ podman system migrate

And now it is working to us create container:

1
2
3
4
5
lab:~$ id
uid=1000(lab) gid=1000(lab) groups=1000(lab)

lab:~$ podman run busybox sh --help
BusyBox v1.37.0 (2024-09-26 21:31:42 UTC) multi-call binary.

How allow non-root containers write to host mounts

if we create a folder and try create a file inside that folder with a host volume mount if container run as root it will work.

1
2
3
4
5
6
7
8
9
lab:~$ mkdir dest

lab:~$ podman run busybox id
uid=0(root) gid=0(root) groups=10(wheel)

lab:~$ podman run -v $PWD/dest:/dest busybox touch /dest/file

lab:~$ ls dest/
file

But if container isn’t root, we will receive permission denied:

1
2
3
4
5
lab:~$ podman run -u 1000 -v $PWD/dest:/dest busybox id
uid=1000(lab) gid=0(root) groups=0(root)

lab:~$ podman run -u 1000 -v $PWD/dest:/dest busybox touch /dest/file
touch: /dest/file: Permission denied

To solve that issue we need to execute a unshare from our local user to bind that folder to the user inside container

1
2
3
4
5
6
lab:~$ podman unshare chown 1000:1000 ./dest

lab:~$ podman run -u 1000 -v $PWD/dest:/dest busybox touch /dest/file

lab:~$ ls dest/
file

How to expose lower ports < 1024

1
2
3
lab:~$ podman run -p 80:80 nginx
Error: pasta failed with exit code 1:
Failed to bind port 80 (Permission denied) for option '-t 80-80:80-80'

As root you need to add that configuration:

1
2
root:~$ echo "net.ipv4.ip_unprivileged_port_start=80" >> /etc/sysctl.conf
root:~$ reboot

Now everything work as expected o/

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
lab:~$ podman run -p 80:80 nginx
/docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
/docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
/docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
10-listen-on-ipv6-by-default.sh: info: Getting the checksum of /etc/nginx/conf.d/default.conf
10-listen-on-ipv6-by-default.sh: info: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf
/docker-entrypoint.sh: Sourcing /docker-entrypoint.d/15-local-resolvers.envsh
/docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
/docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh
/docker-entrypoint.sh: Configuration complete; ready for start up
2025/08/30 18:19:32 [notice] 1#1: using the "epoll" event method
2025/08/30 18:19:32 [notice] 1#1: nginx/1.29.1
2025/08/30 18:19:32 [notice] 1#1: built by gcc 12.2.0 (Debian 12.2.0-14+deb12u1)
2025/08/30 18:19:32 [notice] 1#1: OS: Linux 6.12.43-0-lts
2025/08/30 18:19:32 [notice] 1#1: getrlimit(RLIMIT_NOFILE): 4096:4096
2025/08/30 18:19:32 [notice] 1#1: start worker processes
2025/08/30 18:19:32 [notice] 1#1: start worker process

References