This cheat sheet provides a quick reference guide for working with Podman, a container runtime similar to Docker. Whether you’re new to containers or already familiar with Docker, this guide will help you manage your containers effectively.
Note:
- While majority of commands might work the same in Docker, this guide focuses specifically on Podman commands. But I’ll try to mention them.
- The commands assume you have Podman installed and configured.
- Guide is not comprehensive and does not include info about using containers directly (without docker-compose.yml file(s) or how to use podman pods via systemd). I always need
nginx
, cloudflared
and cloudflare-ddns
running. It works, it worked this way in docker year ago and I have no reason to change it, other than learning how to achieve some functionality other way. - Images are on docker hub, linuxserver.io among other places
Podman vs Docker (in short)
- 👍 Podman does not require root privileges to run
- 👍 Backward compatible with Docker (including podman-compose as a replacement to docker-compose)
- 👌 Few specifics (extra volume export, import, dealing with effective user and group IDs - files are kind of yours, but cannot be accessed directly - see podman cp, unshare, …)
- 👎 Linux only (docker somehow works on Windows)
The last point is completely irrelavant to me. What was relevant for me to start using podman was moving from openSUSE to Fedora38 at the day of release for which docker was not available in first days of weeks.
Containers vs Virtual machine (in short)
- Containers are lightweight, kernel is shared with host, more important is that resources such as memory and disk space are shared so memory consumption of containers is typically in order of tens to hundreds of megabytes.
- If images are build on top of Linux distribution, disk space is shared as well
- Container images are immuntable and basic system cannot be touched without image rebuilt. Changes to filesystem are discarded when container is stopped. This can be desired or undesired behavior. Only way to preseve changes is to mount some directories as volumes.
Containers vs local services
- Containers have advantage in isolation. Upgrades are under your control (unless you are using tag
latest
), configurations are separated from defaults of your Linux distribution and from each other. - Because many container images are prebuilt in repositories
- They may have advantage that they keep some bloat separated from your distribution. For example you can have container for manim having all needed Python libraries, ffmpeg, TeX and modules. Or container having tools for cross-compiling binaries for other platform - relying for example on Ubuntu.
Containers
Containers are running instances (similar to lightweight virtual machines)
List running containers
1
2
3
| podman ps
podman ps -a # include stopped containers
podman container list
|
Statistics
1
2
| podman stats
podman container stats
|
1
2
3
4
5
6
7
8
9
| ID NAME CPU % MEM USAGE / LIMIT MEM % NET IO BLOCK IO PIDS CPU TIME AVG CPU %
1a4b5f0e5b89 nginx 0.01% 13.81MB / 33.42GB 0.04% 1.688MB / 108.2MB 30.77MB / 2.945MB 18 6.207151s 0.01%
23619f1ed8fd nextcloud-app 0.04% 38.9MB / 33.42GB 0.12% 3.329MB / 972.2kB 4.411MB / 3.031MB 16 28.52549s 0.04%
3b2829c97cca cloudflare-ddns 0.00% 4.096MB / 33.42GB 0.01% 1.162MB / 361.2kB 0B / 0B 10 2.565019s 0.00%
64be194da171 nextcloud-mariadb 0.02% 129.5MB / 33.42GB 0.39% 840.8kB / 2.92MB 71.22MB / 29.52MB 20 12.562822s 0.02%
666582af4bea gitea 0.21% 91.48MB / 33.42GB 0.27% 12.05MB / 3.578MB 10.1MB / 655.4kB 12 1m15.155867s 0.21%
c4b01be5bdb0 nginx-pe5 0.01% 13.67MB / 33.42GB 0.04% 39.91kB / 21.78kB 0B / 1.663MB 18 4.325363s 0.01%
db5233310336 cloudflared 0.34% 17.98MB / 33.42GB 0.05% 243MB / 254.3MB 1.835MB / 0B 10 3m45.612557s 0.34%
f9b0cf5324c4 gitea-mariadb 0.03% 94.77MB / 33.42GB 0.28% 3.16MB / 11.73MB 29.76MB / 3.072MB 26 9.021421s 0.03%
|
Starting containers via podman-compose
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| # Create and start containers, display logs to console, interrupt by Ctrl+C
podman-compose -f compose-file.yml up
# Create services, but dont' start them (e.g. when you want to restore volumes from backup)
podman-compose -f compose-file.yml up --no-start
# Start containers and detach (run in background)
podman-compose -f compose-file.yml up -d
# Stop running services
podman-compose -f compose-file.yml stop
# Stop running services and remove containers
podman-compose -f compose-file.yml down
|
Interacting with Running Containers via Shell
Interactive shell (interactive+tty)
1
| podman exec -it nginx /bin/bash
|
Some command
1
2
3
4
| podman exec -it nextcloud-app occ maintenance:mode --on
podman exec nextcloud-mariadb /usr/bin/mysqldump --user=nextcloud --password=WontTell nextcloud > nextcloud-db-20230623.sql
podman exec -it nextcloud-app updater.phar # outdated, web updater should be used
podman exec -it nextcloud-app occ maintenance:mode --off
|
As root
1
| podman exec --user=root -it gitea sh
|
Images (useful to know how to upgrade them)
Images are something like immuntable (read-only) disk images layered on top of each other. They may consist for example from Linux distribution, nginx and few utilities on top of it, PHP on top of it, service on top of it.
All data written to image are lost with restart.
Upgrade (whole process multiple commands)
I assume these commands work for both podman and docker.
- Backup
- List images
1
2
3
4
5
6
7
8
| REPOSITORY TAG IMAGE ID CREATED SIZE
lscr.io/linuxserver/mariadb latest 95a1ad3e9e03 2 months ago 310 MB
<none> <none> c572d36e0174 4 months ago 310 MB
docker.io/gitea/gitea 1.20-rootless 56f881b30f91 4 months ago 151 MB
docker.io/cloudflare/cloudflared latest 951a457fb45c 7 months ago 58.8 MB
lscr.io/linuxserver/nginx latest 6b8505b3d0a9 7 months ago 150 MB
docker.io/favonia/cloudflare-ddns latest 60981c3b3269 10 months ago 6.64 MB
lscr.io/linuxserver/nextcloud 26.0.2-ls246 73905ef95744 10 months ago 469 MB
|
- Edit podman-compose-something file to upgrade version, unless it’s “latest”
- Stop service(s)
1
2
3
| podman-compose -f ~/docker/docker-compose-gitea.yml down
podman-compose -f ~/docker/docker-compose-nextcloud.yml down
systemctl --user stop podman-compose.service
|
- Pull new image(s)
1
2
3
| podman-compose -f docker-compose.yml pull
podman-compose -f ~/docker/docker-compose-gitea.yml pull
podman-compose -f ~/docker/docker-compose-nextcloud.yml pull
|
- Start service(s)
1
2
3
| systemctl --user start podman-compose.service
podman-compose -f ~/docker/docker-compose-gitea.yml up -d
podman-compose -f ~/docker/docker-compose-nextcloud.yml up -d
|
- List images and prune old ones (without a tag, when they are upgraded to latest)
1
2
3
4
5
6
7
8
9
10
11
12
13
| REPOSITORY TAG IMAGE ID CREATED SIZE
lscr.io/linuxserver/nginx latest fc4bd81bf833 2 days ago 154 MB
docker.io/cloudflare/cloudflared latest 725da1216eef 3 days ago 60.1 MB
lscr.io/linuxserver/mariadb latest 36a52e2a273f 4 days ago 336 MB
docker.io/gitea/gitea 1.21-rootless c63b90342747 2 weeks ago 152 MB
<none> <none> 95a1ad3e9e03 2 months ago 310 MB
<none> <none> c572d36e0174 4 months ago 310 MB
docker.io/gitea/gitea 1.20-rootless 56f881b30f91 4 months ago 151 MB
docker.io/favonia/cloudflare-ddns latest 41e96711dd67 5 months ago 7.57 MB
<none> <none> 951a457fb45c 7 months ago 58.8 MB
<none> <none> 6b8505b3d0a9 7 months ago 150 MB
<none> <none> 60981c3b3269 10 months ago 6.64 MB
lscr.io/linuxserver/nextcloud 26.0.2-ls246 73905ef95744 10 months ago 469 MB
|
1
2
3
4
5
6
7
| WARNING! This command removes all dangling images.
Are you sure you want to continue? [y/N] y
60981c3b32691f874c35abaf7f2245d890a37d07b48e37ae24539c5c5b897165
6b8505b3d0a93f6915f1cb77d938fe4744163d8fb309583cd5a2e550668b9827
951a457fb45ca86f0909d60f1597de2a64f12a253dc23d944ac500fedec6ed9b
c572d36e01746b7a37607a9ad02d1f8662372bc7632106f9b6f7c895b2abd79d
95a1ad3e9e03945c844f7032778269c44475961a7e7394b55b2940e8eb92c248
|
1
2
3
4
5
6
7
8
| REPOSITORY TAG IMAGE ID CREATED SIZE
lscr.io/linuxserver/nginx latest fc4bd81bf833 2 days ago 154 MB
docker.io/cloudflare/cloudflared latest 725da1216eef 3 days ago 60.1 MB
lscr.io/linuxserver/mariadb latest 36a52e2a273f 4 days ago 336 MB
docker.io/gitea/gitea 1.21-rootless c63b90342747 2 weeks ago 152 MB
docker.io/gitea/gitea 1.20-rootless 56f881b30f91 4 months ago 151 MB
docker.io/favonia/cloudflare-ddns latest 41e96711dd67 5 months ago 7.57 MB
lscr.io/linuxserver/nextcloud 26.0.2-ls246 73905ef95744 10 months ago 469 MB
|
- Delete gitea-1.20 manually
1
| podman image rm 56f881b30f91
|
1
2
| Untagged: docker.io/gitea/gitea:1.20-rootless
Deleted: 56f881b30f91d63c47c3be661ed567985fccb72c4a1462f7d01c30e468cd9972
|
- Delete images not attached to currently running containers
1
| podman image prune --all
|
Copy file to image
Single file copy
1
2
3
| podman cp jekyll/google*****.html nginx:/config/www
podman cp jekyll/BingSiteAuth.xml nginx:/config/www
podman cp teapot.php nginx:/config/www
|
This removes old content and copies whole directory recursively
1
2
| podman exec nginx sh -c "cd /config/www && rm -rf *"
podman cp _site/. nginx:/config/www
|
Edit file inside image
This is podman only
1
| podman unshare vim /home/pavel/.local/share/containers/storage/volumes/docker_gitea-config/_data/app.ini
|
Volumes (useful for backup/restoration)
I assume that export/import works only for podman and not docker.
Volumes are something like read-write virtual hard drives that are used to store editable, permanent data (configs, web pages, logs) that are unique and valuable for you.
Some useful commands are
- list (ls)
- create
- inspect
- remove (rm)
- export
- import
- prune
List
1
2
3
4
| DRIVER VOLUME NAME
local docker_gitea-config
local docker_gitea-data
local docker_gitea-db
|
Inspect
1
| podman volume inspect docker_gitea-config
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| [
{
"Name": "docker_gitea-config",
"Driver": "local",
"Mountpoint": "/home/pavel/.local/share/containers/storage/volumes/docker_gitea-config/_data",
"CreatedAt": "2023-07-03T19:50:00.68860642+02:00",
"Labels": {
"com.docker.compose.project": "docker",
"io.podman.compose.project": "docker"
},
"Scope": "local",
"Options": {},
"UID": 1000,
"GID": 1000,
"MountCount": 0,
"NeedsCopyUp": true,
"LockNumber": 12
}
]
|
Exit code of this command can be used to check if the volume exists.
Export & import
More on this in Backup and recovery
Podman volume export/import works basically the same way as tar to/from console which can be piped to/from file compression utility (such as zstandard or xz) or redirected to/from tar file (podman volume export > file.tar, volume import < file.tar should work)
1
| podman volume export docker_nginx-config | zstd -11 > nginx-config-20240412.tar.zst
|
1
| zstd -dc nextcloud-app-data-2023-07-14.tar.zst | podman volume import docker_nextcloud-app-data -
|
Remove
1
| podman volume rm docker_nextcloud-app-etc-crontabs
|
Prune (use with care)
The following volumes are leftovers from some experiments and invalid compose files.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| WARNING! This will remove all volumes not used by at least one container. The following volumes will be removed:
12cda36aef73013aade716b53cc04be794343beee1936684c2bb9680fd4c7f80
3c4a324817cdb2c4fe91b67c739d7f3fa6a5d51b3fbf3c75d2b7a39f79b225b4
57091935bd519673f6e7a20c0aa634fd43be0dee3f3c17a57be6e9c990c185c2
5f9c212960def60fc6c2d56620e52db379620887fde197a030910cbac50e05e9
c025d84b9264d40ae66b583baea51eccb2bc049fce2c652723839b46806c58aa
e3402edaa17fd3099ecdc08d2a07c8f57d2b4a09050180e1dc3b257174886533
Are you sure you want to continue? [y/N] y
12cda36aef73013aade716b53cc04be794343beee1936684c2bb9680fd4c7f80
3c4a324817cdb2c4fe91b67c739d7f3fa6a5d51b3fbf3c75d2b7a39f79b225b4
57091935bd519673f6e7a20c0aa634fd43be0dee3f3c17a57be6e9c990c185c2
5f9c212960def60fc6c2d56620e52db379620887fde197a030910cbac50e05e9
c025d84b9264d40ae66b583baea51eccb2bc049fce2c652723839b46806c58aa
e3402edaa17fd3099ecdc08d2a07c8f57d2b4a09050180e1dc3b257174886533
|
Running podman compose as a service
1
2
3
4
5
6
7
8
9
10
11
12
13
| [Unit]
Description=Podman Compose Service
After=network.target
[Service]
Type=oneshot
RemainAfterExit=yes
WorkingDirectory=/home/pavel/docker
ExecStart=/usr/bin/podman-compose -f docker-compose.yml up -d
ExecStop=/usr/bin/podman-compose -f docker-compose.yml down
[Install]
WantedBy=default.target
|
Starting service at boot time
- Enable starting user session at boot time
1
| sudo loginctl enable-linger <username>
|
- Enable service on session start and also start it now
1
| systemctl --user enable --now podman-compose.service
|
Getting disc usage statistics
1
2
3
4
| TYPE TOTAL ACTIVE SIZE RECLAIMABLE
Images 6 6 1.179GB 0B (0%)
Containers 8 8 232.7kB 0B (0%)
Local Volumes 9 8 37.87GB 551B (0%)
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
| Images space usage:
REPOSITORY TAG IMAGE ID CREATED SIZE SHARED SIZE UNIQUE SIZE CONTAINERS
lscr.io/linuxserver/nextcloud 26.0.2-ls246 73905ef95744 10 months 468.6MB 0B 468.6MB 1
docker.io/favonia/cloudflare-ddns latest 41e96711dd67 5 months 7.569MB 0B 7.569MB 1
lscr.io/linuxserver/nginx latest fc4bd81bf833 2 days 153.9MB 0B 153.9MB 2
docker.io/cloudflare/cloudflared latest 725da1216eef 3 days 60.07MB 0B 60.07MB 1
lscr.io/linuxserver/mariadb latest 36a52e2a273f 4 days 336.4MB 0B 336.4MB 2
docker.io/gitea/gitea 1.21-rootless c63b90342747 2 weeks 152MB 0B 152MB 1
Containers space usage:
CONTAINER ID IMAGE COMMAND LOCAL VOLUMES SIZE CREATED STATUS NAMES
024e84e56068 c63b90342747 3 12.39kB 2 hours running gitea
1a4b5f0e5b89 fc4bd81bf833 1 39.76kB 2 hours running nginx
23619f1ed8fd 73905ef95744 2 40.86kB 2 hours running nextcloud-app
3b2829c97cca 41e96711dd67 0 11.46kB 2 hours running cloudflare-ddns
64be194da171 36a52e2a273f 1 38.61kB 2 hours running nextcloud-mariadb
aceaa8f430cb 36a52e2a273f 1 38.53kB 2 hours running gitea-mariadb
c4b01be5bdb0 fc4bd81bf833 1 39.77kB 2 hours running nginx-pe5
db5233310336 725da1216eef tunnel --no-autoupdate run 0 11.34kB 2 hours running cloudflared
Local Volumes space usage:
VOLUME NAME LINKS SIZE
docker_gitea-config 1 2.141kB
docker_gitea-data 1 40.17MB
docker_gitea-db 1 212.2MB
docker_nextcloud-app-config 1 735.8MB
docker_nextcloud-app-data 1 36.41GB
docker_nextcloud-app-etc-crontabs 0 551B
docker_nextcloud-db 1 364.2MB
docker_nginx-config 1 95.39MB
docker_nginx-config-pe5 1 12.05MB
|
Logs
Show log of the specified container
1
2
| podman logs gitea-mariadb
podman logs --tail 10 --follow cloudflared
|