Podman and Docker
Podman and Docker build and run containers: a service packaged with its runtime and libraries as an image, started as an isolated process with its own file system and network [1], [2]. The commands are the same; this card uses podman, and every command works unchanged with docker.
The quality question it answers: does the service run the same way on every machine? A load or security test is only repeatable if the system under test is.
Run for this card with Podman 6.1.4 (rootless, macOS machine), Docker CLI 29.8 against Podman’s socket, October 2026.
Which one? Podman runs without a background daemon and, by default, rootless: a container cannot do more than your own user could. Docker’s daemon runs as root unless configured otherwise. On macOS and Windows both run containers inside a small Linux virtual machine (podman machine init, or Docker Desktop).
Install and quick start
brew install podman # Linux: your package manager; Windows: winget install RedHat.Podman
podman machine init && podman machine start # macOS and Windows only
A Containerfile (Docker calls it Dockerfile; both tools read either) for the example Flask service, whose code, src/parking/app.py, is printed on the Locust card; build the image once that file exists:
FROM python:3.12-slim
WORKDIR /app
RUN pip install --no-cache-dir flask==3.1.3
COPY src/ ./src/
ENV PYTHONPATH=/app/src
EXPOSE 5000
CMD ["flask", "--app", "parking.app", "run", "--host", "0.0.0.0", "--port", "5000"]
The image pins only Flask, to keep the file short; for a real service, export the lock file (poetry export -f requirements.txt, from the poetry-plugin-export plugin) and install from it, so the container runs the versions you tested.
podman build -t parking:0.1 -f Containerfile .
podman run -d --name parking -p 8080:5000 --cpus 1 --memory 256m parking:0.1
curl "localhost:8080/fee?minutes=90" # {"fee":4,"minutes":90}
Reading the output
$ podman ps --format "table {{.Names}}\t{{.Image}}\t{{.Status}}\t{{.Ports}}"
NAMES IMAGE STATUS PORTS
parking localhost/parking:0.1 Up 3 seconds 0.0.0.0:8080->5000/tcp
$ podman stats --no-stream --format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}"
NAME CPU % MEM USAGE / LIMIT
parking 2.27% 22.24MB / 268.4MB
0.0.0.0:8080->5000/tcp reads “port 8080 on your machine forwards to port 5000 in the container”. The limit column shows the --memory cap. podman logs parking prints what the service wrote; podman stop parking and podman rm parking clean up.
Common mistakes
- The service listens on 127.0.0.1 inside the container. Started without
--host 0.0.0.0, Flask loggedRunning on http://127.0.0.1:5000, andcurlfrom the host gotEmpty reply from server. Inside a container, 127.0.0.1 is the container itself. - No resource limits in a performance test. Without
--cpusand--memory, the service uses whatever your laptop has free, and the numbers change with what else is running. - The wrong CPU architecture. An image built on an Apple Silicon Mac is
arm64(podman image inspect … --format '{{.Architecture}}'); a project that publishes separateamd64andarm64images needs the one for your machine. - Compose.
podman composehands the file to an installed compose provider; on the test machine it randocker-composev5.5.1.
In CI
GitHub’s Ubuntu runners have both tools installed, so podman build and podman run work in a workflow step as they do locally.
Go deeper
- Load Testing with Locust: a containerised service under load.
- Secure Design Principles: least privilege, which rootless containers apply.
- Trivy: scanning the image and the Containerfile.
References
- The Podman project,“Podman Documentation.” 2026. [Online]. Available: https://docs.podman.io/
- Docker Inc.,“Docker Documentation: Dockerfile Reference and docker run.” 2026. [Online]. Available: https://docs.docker.com/
Disclaimer: AI is used for text summarization, polishing and explaining. Authors have verified all facts and claims. In case of an error, feel free to file an issue.