Docker to Podman translation sheet
Not the commands that are identical - the ones that are not. What changes silently, what has no equivalent, and what needs a flag Docker never asked for. Every row with a Play example was executed on Ubuntu 26.04 with Podman 5.7.0.
- OSUbuntu 26.04 LTS (resolute)
- Podman5.7.0
- Runtimecrun 1.21
- Networknetavark 1.16.1
- Commands40
- Reviewed22 August 2026
Works unchanged
-
podman run / ps / stop / rm / exec / logs / cp / inspectSame flags, same behaviour. A script of these generally runs untouched.
-
podman build -t app:1 .Dockerfiles need no changes. `Containerfile` is preferred but `Dockerfile` is read as a fallback.
-
docker --versionWith podman-docker installed, `docker` is a three-line shim that execs podman. It reports podman's version rather than pretending.
bash Example session docker --versionEmulate Docker CLI using podman. Create /etc/containers/nodocker to quiet msg.podman version 5.7.0 -
podman --format 'table {{.Names}} {{.Status}}'Go templates work the same way. Field names come from `inspect` JSON.
bash Example session podman ps --format 'table {{.Names}} {{.Image}} {{.Status}} {{.Ports}}'NAMES IMAGE STATUS PORTSsite docker.io/library/nginx:alpine Up Less than a second 0.0.0.0:8081->80/tcp
Changes silently - fix these first
-
podman build -t app:1 . # -> localhost/app:1CautionLocally built images gain a `localhost/` prefix. Anything grepping image names breaks, and a push needs a re-tag.
bash Example session podman images appREPOSITORY TAG IMAGE ID CREATED SIZElocalhost/app 1 c154b5c3995c Less than a second ago 13.8 MB -
podman pull docker.io/library/alpineNo implicit Docker Hub. Qualify every image reference - this is the single highest-value change when migrating.
A bare name resolves via a 132-entry alias table, or fails. `hello-world` maps to quay.io/podman/hello.
-
podman pull traefikAn unaliased bare name fails outright rather than assuming a registry.
bash Example session podman pull traefikError: short-name "traefik" did not resolve to an alias and no unqualified-search registries are defined in "/etc/containers/registries.conf"[exit 125] -
podman inspect c --format '{{.NetworkSettings.IPAddress}}'CautionEMPTY for a rootless container on the default network - there is no bridge address to report.
bash Example session podman inspect alpha --format 'ip=[{{.NetworkSettings.IPAddress}}] net={{range $k,$v := .NetworkSettings.Networks}}{{$k}}{{end}}'ip=[] net= -
podman exec a getent hosts bFails on the default network. Container DNS needs a network you created.
bash Example session podman exec alpha getent hosts beta [exit 2] -
podman network create appnetThe fix for both of the above: a user-defined network has DNS and real bridge addresses.
bash Example session podman network inspect appnet --format 'driver={{.Driver}} subnet={{range .Subnets}}{{.Subnet}}{{end}} dns={{.DNSEnabled}}'driver=bridge subnet=10.89.0.0/24 dns=true
Needs a flag Docker never needed
-
podman run --userns=keep-id -v ~/src:/src ...Without it, a non-root container user writes files owned by UID 100999 that you cannot delete.
bash Example session rm -rf ~/src/treerm: cannot remove '/home/sysadmin/src/tree/deep/f.txt': Permission denied[exit 1] -
podman unshare rm -rf ./dirDestructiveDelete a directory tree a container left behind, from inside the namespace where you own it.
-
sudo sysctl net.ipv4.ip_unprivileged_port_start=80CautionRequired before a rootless container can publish a port below 1024.
Host-wide, and does not survive a reboot. A reverse proxy is usually better.
-
podman run -p 80:80 ... # fails rootlesspasta cannot bind a privileged port as your user.
bash Example session podman run -d --name low -p 80:80 docker.io/library/nginx:alpineError: pasta failed with exit code 1:Listen failed for HOST TCP port */80: Permission deniedCouldn't listen on requested TCP ports [exit 126] -
podman run --init ...Makes stops fast. Without it a process that ignores SIGTERM as PID 1 takes the full 10-second timeout and a SIGKILL.
bash Example session time podman stop nosigtime="2026-08-22T11:32:00Z" level=warning msg="StopSignal SIGTERM failed to stop container nosig in 10 seconds, resorting to SIGKILL"nosig real 0m10.119suser 0m0.083ssys 0m0.087s -
loginctl enable-linger $USERWithout it a rootless service starts at first LOGIN, not at boot - so a rebooted host serves nothing until someone connects.
The migration step most likely to cause a real outage if skipped.
-
[[registry]] insecure = truePodman assumes TLS for every registry and will not downgrade. A plain HTTP registry must be declared, per client.
bash Example session podman push localhost/multi:1 192.168.0.23:5000/multi:1Getting image source signaturesCopying blob sha256:7da0375eb2ecd60c8f630fc42f4cc36c6d2b3923f404212810c167019169b092Copying blob sha256:6f09edfb3f6d7173733adc8eec8ea00626550dc6fc2dcf07d40e13f5c1e907c4Error: trying to reuse blob sha256:6f09edfb3f6d7173733adc8eec8ea00626550dc6fc2dcf07d40e13f5c1e907c4 at destination: pinging container registry 192.168.0.23:5000: Get "https://192.168.0.23:5000/v2/": http: server gave HTTP response to HTTPS client[exit 125]
No Docker equivalent
-
podman pod create --name app -p 8080:80A first-class pod. Containers in it share one network namespace and talk over localhost.
bash Example session podman pod create --name web -p 8080:804d919ca8a0e9ab39fbc7b834fe526dfdf8ad73794f9309cbb39cc55e5d2fe46e -
podman kube generate appExport a running pod as a real Kubernetes manifest.
bash Example session podman kube generate shop# Save the output of this file and use kubectl create -f to import# it into Kubernetes.## Created with podman-5.7.0apiVersion: v1kind: Podmetadata: annotations: io.kubernetes.cri-o.SandboxID/cache: 2d5e8d85ede5aa9e0de6841ad6efb3d95f3e0fd3f22da34ca66f4dc84d781695 io.kubernetes.cri-o.SandboxID/storefront: 2d5e8d85ede5aa9e0de6841ad6efb3d95f3e0fd3f22da34ca66f4dc84d781695 -
podman kube play app.yamlRun a Kubernetes manifest on one host with no cluster.
bash Example session podman kube play shop.yamlPod:91a48f41701aea32709524af38796565f8aa865927d027cfad7f322e337134b2Containers:edd8357786aef2751997b473b79cb2b72e09d839668be44fafabca933af07cef5d392f6ec1f390b903dc58dd1d364d6a8b719829d49ffbc74fccc23b9c476ccf -
podman image scp localhost/app:1 lab02::Copy an image host to host over ssh with no registry.
bash Example session podman image scp localhost/multi:1 lab02::Copying blob sha256:6f09edfb3f6d7173733adc8eec8ea00626550dc6fc2dcf07d40e13f5c1e907c4Copying blob sha256:7da0375eb2ecd60c8f630fc42f4cc36c6d2b3923f404212810c167019169b092Copying config sha256:9f00b68fe5e6bb84503d42c233b5a42d492c28bca1305725319db6fa702e5f04Writing manifest to image destinationLoaded image: localhost/multi:1 -
podman volume export data -o data.tarBack a volume up in one command. Docker has no equivalent and needs a helper container.
bash Example session tar -tvf ~/dbdata.tar-rw-r--r-- 0/0 16 2026-08-22 12:11 table -
podman generate systemd # deprecated, use QuadletA container as a systemd unit, described in a nine-line file that systemd regenerates on every reload.
bash Example session podman generate systemd --help[DEPRECATED] Generate systemd units Description: Generate systemd units for a pod or container. The generated units can later be controlled via systemctl(1). -
podman auto-updatePull a newer image behind the same tag and restart the unit. No orchestrator involved.
bash Example session podman auto-update --dry-run UNIT CONTAINER IMAGE POLICY UPDATED myapp.service c82799dc0640 (myapp) localhost:5000/myapp:latest registry pending -
podman unshare cat /proc/self/uid_mapRun a command inside your own user namespace. There is no Docker analogue because Docker has no user namespace to enter.
bash Example session podman run --rm docker.io/library/alpine cat /proc/self/uid_map 0 1000 1 1 100000 65536 -
docker swarm initCautionNO EQUIVALENT. Podman has no orchestrator. Use Kubernetes, or systemd units per host.
Declared not-executed: there is nothing to run.
Architecture differences you can verify
-
pgrep -a podman # nothing, while containers runThere is no daemon. One conmon per container, parented to PID 1.
bash Example session pstree -sp $(pgrep conmon | head -1)systemd(1)---conmon(4859)---nginx(4861)-+-nginx(4886) `-nginx(4887) -
systemctl is-active podman.service`inactive` is the correct, healthy state immediately after installing.
bash Example session systemctl is-active podman.serviceinactive[exit 3] -
podman info --format '{{.Store.GraphRoot}}'Rootless images live under your home and count against its quota. `sudo podman` is a separate, empty store.
bash Example session sudo -n podman info --format 'graphroot={{.Store.GraphRoot}} rootless={{.Host.Security.Rootless}}'graphroot=/var/lib/containers/storage rootless=false -
sudo podman images # empty on a host full of imagesRootful and rootless are two machines that share a binary. `sudo` is not a fix.
bash Example session sudo -n podman imagesREPOSITORY TAG IMAGE ID CREATED SIZE -
podman run --rm alpine grep CapEff /proc/self/statusRootless and rootful get the SAME eleven capabilities. The difference is reach, not the bitmask.
bash Example session podman run --rm docker.io/library/alpine grep -E '^Cap(Prm|Eff|Bnd)' /proc/self/statusCapPrm: 00000000800405fbCapEff: 00000000800405fbCapBnd: 00000000800405fb -
journalctl --user CONTAINER_NAME=cLogs go to journald and OUTLIVE the container. `podman logs` fails once it is removed; the journal does not.
bash Example session journalctl --user CONTAINER_NAME=talker --no-pager -o catline 1 from the container line 2 from the container line 3 from the container
Rough edges to know about
-
podman run --read-only -p 8080:80 ...CautionBREAKS the published port on rootless 5.7.0. The container runs, serves its own loopback, and resets forwarded connections.
bash Example session curl -s -o /dev/null -w 'from host: http=%{http_code}\n' http://localhost:8133from host: http=000[exit 56] -
podman kube down app.yamlCautionPrints a rootless netns error and exits 0 anyway. Check `$?`, not the text.
bash Example session podman kube down shop.yamlPods stopped:Error: stopping container a5cb6d4e001ba8035d2f3eee8e8fa777d00135c9589b7dc5e59b1ac621fe4574: removing container a5cb6d4e001ba8035d2f3eee8e8fa777d00135c9589b7dc5e59b1ac621fe4574 network: 1 error occurred: * rootless netns: kill network process: permission denied Pods removed:b3063debdee5129b9960376fa8cc4c0aacfcd7cc45fb131bffbdf05eb32159b3Secrets removed:Volumes removed: -
docker compose down # under PodmanCautionSame netns error, worse: exits 1 and leaves a container behind.
bash Example session cd ~/stack && DOCKER_HOST=unix://$XDG_RUNTIME_DIR/podman/podman.sock docker compose down>>>> Executing external compose provider "/usr/libexec/docker/cli-plugins/docker-compose". Please see podman-compose(1) for how to disable this message. <<<< Container stack-web-1 Stopping Container stack-cache-1 Stopping Container stack-web-1 Stopped Container stack-web-1 Removing Container stack-cache-1 Error while Stopping Container stack-web-1 RemovedError response from daemon: removing container 2b34bcc8c996b9f5cde6d6de2cf6d6745f7a0d4e08d6a97d7d1a686398fa80c6 network: 1 error occurred: * rootless netns: kill network process: permission deniedError: executing /usr/libexec/docker/cli-plugins/docker-compose down: exit status 1[exit 1] -
systemctl --user restart app-web.service # a pod memberCautionFails on BindsTo and takes the whole pod down. Restart the POD unit instead.
bash Example session systemctl --user restart app-web.serviceA dependency job for app-web.service failed. See 'journalctl -xe' for details.[exit 1] -
podman kube play dep.yaml # replicas > 1Warns and gives you ONE pod. The manifest applied and did not do what it says.
bash Example session podman kube play dep.yamltime="2026-08-22T11:09:34Z" level=warning msg="Limiting replica count to 1, more than one replica is not supported by Podman"Pod:c01315c6a04eb89312c3d4f034f7d842df4f12eb26d0b9aa5c7447a0f5cfe1e0Container: -
podman build ... # chown above your subuid range`Invalid argument`, not permission denied - the UID has no mapping. Ceiling is the count in /etc/subuid.
bash Example session cd ~/limits && podman build -t limits:outofrange .STEP 1/2: FROM docker.io/library/alpine:3.22STEP 2/2: RUN chown 70000:70000 /tmp && echo "uid 70000 should not be reachable"chown: /tmp: Invalid argumentError: building at STEP "RUN chown 70000:70000 /tmp && echo "uid 70000 should not be reachable"": while running runtime: exit status 1[exit 1] -
podman system connection add name ssh://...Succeeds WITHOUT testing anything. The ssh error waits for first use.
bash Example session podman --remote info --format 'host={{.Host.Hostname}} rootless={{.Host.Security.Rootless}}'OS: linux/amd64buildOrigin: Ubuntuprovider: qemuversion: 5.7.0 Cannot connect to Podman. Please verify your connection to the Linux system using `podman system connection list`, or try `podman machine init` and `podman machine start` to manage a new Linux VMError: unable to connect to Podman socket: failed to connect: ssh: handshake failed: ssh: unable to authenticate, attempted methods [none publickey], no supported methods remain: ssh://sysadmin@192.168.0.21:22/run/user/1000/podman/podman.sock[exit 125] -
podman volume prune -fDestructiveRemoves every volume no RUNNING container references - including a stopped database's. No undo.
bash Example session podman volume prune -fstack_siteorphan
No command matches that search.