Conventions and Terminology
- privileged containers: container running as root with U/GID
0
and maximum permissions. - unprivileged containers: container running with an U/GID different than root's
0
. - ephemeral containers: when the process running inside the container exists, the container gets deleted automatically.
- subgid and subuid: set of U/GIDs the user can use besides their own U/GID.
Paths
/usr/share/containers/
default/etc/containers/
overrides${XDG_CONFIG_HOME}/containers
for rootless containers
Commands
- Create a container:
podman create alpine:latest
- Create a container with a custom name:
podman create --name=alpine alpine:latest
- Show running containers:
podman ps
- Show existing containers:
podman ps -a
- Start container:
podman start alpine
- Stop container:
podman stop alpine
- Attach to a running container.
Ctrl+p Ctrl+q
to detach:podman attach -ia alpine
- Execute a command inside a running container:
podman exec -it alpine /bin/sh
- Create and start a container:
podman run -d alpine:latest
- Create, start and attach to a container:
podman run -it alpine:latest
- Create, start and attach to an ephemeral container:
podman run --rm -it alpine:latest
- Create, start and attach to an ephemeral container with another command:
podman run --rm -it --entrypoint /bin/sh alpine:latest
- Display the running processes of a container:
podman top <container>
- List images:
podman images
- Remove an image:
podman rmi <name or ID>
- Search for an image globally:
podman search <string>
- List mapped ports:
podman port <container>
- Display the changes in the filesystem caused by a container.
C
for changed andA
for added:podman diff <container>
- Mount and report the location of a container's filesystem:
podman mount <container>
- Umount a container's filesystem:
podman unmount <container>
- Build Dockerfile:
podman build -t <image>:<tag> .
- Export a container's filesystem to a tar file:
podman export -o <output_filename> <conainer>
- Import a container's filesystem from a tar file:
podman export <filename> [<image>:<tag>]
- Export image to file:
podman save --output image.tar localhost/image
- Import image from file:
podman load --input image.tar
- Create an image from a container:
podman commit container image:latest
- Show command output inside the container:
podman logs container_name
docs - Show intermediate images:
podman image ls --all
- Remove all images not in use by containers:
podman image prune --all
- Remove unused data:
podman system prune
. Stopped containers, networks not used by at least one container, dangling images and dangling build cache. - Show metadata describing a container:
podman inspect <container>
Container options
--net=none
--uidmap=0:0:65536 --gidmap=0:0:65536 --name=nethack --subgidname=yu --subuidname=yu --userns=private --rm -i -t --read-only --image-volume tmpfs --env --group-add --user=0 --cap-drop=ALL --read-only=true --read-only-tmpfs=false --systemd=false --userns=keep-id --security-opt=no-new-privileges --memory=2048mb --cap-add cap_sys_chroot --volume --root --runroot --systemd=false --tmpfs --group-add --user-add
rootless containers
By default you can only run podman as root until you configure subUIDs for your user.
To do so run: usermod --add-subuids 1000000-1065536 --add-subgids 1000000-1065536 username
.
This will add username:1000000:65536
to /etc/subuid
and /etc/subgid
.
Now you can run rootless containers.
Simply run podman run -it alpine:latest
as user to create a rootless container.
This is the same as podman run --uidmap=0:0:65536 -it alpine:latest
UIDs will be mapped like:
container | host |
---|---|
0 | 1000 |
1 | 1000000 |
1000 | 1000999 |
65534 | 65533 |
If you do not want to map user 0
inside the container to your user ID in the host you need to add --uidmap=0:1:65536
to the command: podman run --uidmap=0:1:65536 -it alpine:latest
.
With this configuration the UID map will be like:
container | host |
---|---|
0 | 1000000 |
1 | 1000001 |
1000 | 1001000 |
65534 | 1065534 |
If you close the user session all rootless containers will be stopped by systemd.
To avoid it you have to enable lingering with loginctl enable-linger
. Source
Using podman in RAM
The first step is to create a tmpfs
mount, I will create mine in /tmp/podman
, and create some folders there:
root
Storage root dir in which data, including images, is stored.run
Storage state directory where all state information is stored.tmp
Path to the tmp directory, for libpod runtime content.
You can temporally change the paths with podman --root /tmp/podman/root --runroot /tmp/podman/run --tmpdir /tmp/podman/tmp
(this options have to be issued before a podman command like run
) so the final command could look like:
podman --root /tmp/podman/root --runroot /tmp/podman/run --tmpdir /tmp/podman/tmp run --rm -it alpine:latest
And if you want to build and image:
podman --root /tmp/podman/root --runroot /tmp/podman/run --tmpdir /tmp/podman/tmp build -t image:latest .
Using podman with GUIs
Using podman 4.2.1
, sway 1.7
and wlroots 0.15.1
in archlinux.
Wayland on host and Wayland in container
You need to allow the host UID mapped to the container UID that runs the app to write to the wayland and pulseaudio socket. In my case I use the user nobody inside the container so 65534
which outside is 1065534
:
setfacl -m u:1065534:-w- "/run/user/1000/wayland-1"
setfacl -m u:1065534:-w- "/run/user/1000/pulse-socket"
And map the sockets as files to the container:
podman run --rm -d --uidmap=0:1:65536 \
-v /run/user/1000/pulse-socket:/1000/pulse-socket \
-v /run/user/1000/wayland-1:/1000/wayland-1 \
-v /dev/dri/renderD128:/dev/dri/renderD128 \
firefox:latest
/dev/dri/renderD128
is already accessible by all in my system.
You may need some variables inside the container:
Wayland on host and Xorg in container
Pretty much like wayland but with X stuff.
First you need an xauthority file which sway does not have AFAIK.
touch /run/user/1000/xauthority
xauth generate :0 . trusted
xhost +
And allow the UID in the container to access them:
setfacl -m u:1065534:r-- /run/user/1000/xauthority
sudo setfacl -m u:1065534:r-x /tmp/.X11-unix
sudo setfacl -m u:1065534:rwx /tmp/.X11-unix/X0
setfacl -m u:1065534:-w- "/run/user/1000/pulse-socket"
And launch the container:
podman run --rm -d --uidmap=0:1:65536 \
-v /run/user/1000/xauthority:/1000/xauthority \
-v /tmp/.X11-unix/X0:/tmp/.X11-unix/X0 \
-v /dev/dri/renderD128:/dev/dri/renderD128 \
-v /run/user/1000/pulse-socket:/1000/pulse-socket \
lagrange:latest
You may need some variables inside the container:
--env XDG_SEAT=$XDG_SEAT --env XDG_SESSION_ID=$XDG_SESSION_ID
Turn a container into an image file
Customize the container at will.
Create a custom image from the container's data with: podman commit container image:latest
You can check the size, ID and tag with podman images
.
After you have the image you can export it to a file with podman save --output image.tar localhost/image
.
To import the image run podman load --input image.tar
and start a new container podman run image:latest
.
Map an unprivileged port
We have a web server in a container running in port 80. We map the container to the host on port 8080. Now, to access this server on port 80 of the host, there is 3 ways.
- The worst:
net.ipv4.ip_unprivileged_port_start = 80
or even worstnet.ipv4.ip_unprivileged_port_start = 0
. This will allow every program to listen on privileged ports. - The bad:
AmbientCapabilities=CAP_NET_BIND_SERVICE
in systemd grants that container the possibility to listen on privileged ports. - The good: firewall NAT. Haven't tried the rules, just copy pasted them.
firewall-cmd --direct --add-rule ipv4 nat OUTPUT 0 -p tcp --dport=80 -o lo -j REDIRECT --to-port=8080
iptables -t nat -A OUTPUT -o lo -p tcp --dport=80 -j REDIRECT --to-port=8080
nft add rule ip nat OUTPUT oifname "lo" tcp dport 80 counter redirect to :8080
Also, there are tools like redir to redirect ports.
Errors
Container stuck in removing
podman system renumber