Post

ENG | Podman (docker) cheat sheet

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

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%

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
    
    podman image ls
    
    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
    
    podman image ls
    
    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
    
    podman image prune
    
    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
    
    podman image ls
    
    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
podman volume ls
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
podman volume prune
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

Extras

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

  1. Enable starting user session at boot time
    1
    
    sudo loginctl enable-linger <username>
    
  2. Enable service on session start and also start it now
    1
    
    systemctl --user enable --now podman-compose.service
    

Getting disc usage statistics

1
podman system df
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
podman system df -v
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
This post is licensed under CC BY 4.0 by the author.