Docker and Podman: Container Basics on Linux
Containers package an application together with everything it needs to run, isolated from the host system and from other containers, without the overhead of a full virtual machine. Docker popularized the modern container workflow; Podman is a newer, daemonless alternative that is command-line compatible with Docker for most everyday use. This guide covers the core concepts and commands that apply to both.
Images and containers
An image is a read-only template: a packaged filesystem plus metadata describing how to run something, typically pulled from a registry like Docker Hub. A container is a running or stopped instance created from an image, with its own writable layer stacked on top. One image can spawn any number of independent containers, each isolated from the others and from the image itself.
docker pull nginx # download an image from a registry
docker images # list locally available images
docker run nginx # create and start a container from an image
docker ps # list running containers
docker ps -a # list all containers, including stopped ones
Running a container
docker run -d --name mywebserver -p 8080:80 nginx
-d runs the container in detached mode, in the background, rather than attaching your terminal to its output. --name gives the container a memorable name instead of a random generated one. -p 8080:80 maps port 8080 on the host to port 80 inside the container, which is how you make a service running inside a container reachable from outside it.
docker run -it ubuntu bash
-it combines two flags: -i keeps standard input open, and -t allocates a pseudo-terminal, together giving you an interactive shell inside the container, useful for exploring an image or debugging.
Stopping and removing containers
docker stop mywebserver # stop gracefully
docker start mywebserver # start it again (it still exists, just stopped)
docker rm mywebserver # remove a stopped container entirely
docker rm -f mywebserver # force-stop and remove in one step
A stopped container still exists and can be restarted; removing it (rm) deletes it and its writable layer permanently. This distinction trips up a lot of newcomers who expect stop to also clean things up.
Volumes: persisting data
Anything a container writes to its own filesystem is lost when the container is removed, since that data lives only in the container’s writable layer. Volumes solve this by mapping a host directory (or a Docker-managed volume) into the container:
docker run -d -v /host/data:/var/lib/data myimage
This maps /host/data on the host to /var/lib/data inside the container. Files written to that path inside the container actually live on the host and survive container removal. Databases, uploaded user content, and configuration that needs to persist are almost always paired with a volume mount in real-world deployments.
Building your own image
Images are typically built from a Dockerfile, a plain text file describing the steps to assemble one:
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
CMD ["python", "app.py"]
docker build -t myapp:latest .
docker run myapp:latest
docker build -t myapp:latest . builds an image from the Dockerfile in the current directory (.), tagging it myapp:latest.
Cleaning up
Unused images, stopped containers, and build cache accumulate over time and consume real disk space:
docker system df # see how much space containers/images/volumes are using
docker system prune # remove unused containers, networks, and dangling images
docker system prune -a # more aggressive: also remove unused images not tied to any container
Podman: a daemonless alternative
Docker relies on a persistent background daemon, dockerd, running as root, that every docker command communicates with. Podman is daemonless: each command runs as its own independent process, with no long-running privileged service required in the background.
Podman was deliberately built to be command-line compatible with Docker, so most of what you just read works unchanged with podman substituted for docker:
podman run -d --name mywebserver -p 8080:80 nginx
podman ps
podman build -t myapp:latest .
Many systems even set up an alias so docker itself points to podman, letting existing scripts and muscle memory work without modification.
Rootless containers
Podman’s other major design difference is native support for rootless operation: unprivileged users can run Podman containers without needing membership in a privileged group or a root-owned daemon running in the background. Docker, by contrast, defaults to requiring root or membership in the docker group, which effectively grants root-equivalent control over the host through the daemon. This is one of the more commonly cited security advantages of Podman: a compromised rootless container has a much smaller potential blast radius than a compromised container running through a root-owned daemon.
# Rootless podman, no special setup required in most modern distributions
podman run -it alpine sh
Choosing between them
Docker has a larger ecosystem, more third-party tooling built directly around it, and a longer track record in production environments. Podman offers a smaller attack surface, no daemon to keep patched and running, and rootless operation as a default rather than an afterthought. For learning containers or running them on a personal machine, either is a reasonable starting point, and the command-line compatibility means the core concepts transfer directly between them.
Frequently Asked Questions
What is the difference between an image and a container?
An image is a read-only template: a packaged filesystem plus metadata describing how to run a piece of software, built from a Dockerfile (or equivalent) and typically downloaded from a registry like Docker Hub. A container is a running (or stopped) instance created from an image, with its own writable layer on top of the image’s read-only layers. The relationship is similar to a class and an object in programming, or a program file and a running process: one image can be used to start any number of independent containers, each with its own state, without affecting the image itself or any other container started from it.
What is the main difference between Docker and Podman?
Docker relies on a persistent background daemon (dockerd) running as root, which every docker command talks to in order to manage containers. Podman is daemonless: each podman command runs as an independent process with no long-running background service required, and it supports running fully rootless containers more naturally, without needing special daemon configuration. Podman was also designed to be command-line compatible with Docker, so most docker commands work unchanged if you simply type podman instead, including in many cases aliasing docker to podman entirely. The tradeoff is that Docker has a larger ecosystem and longer track record, while Podman offers a smaller attack surface and no daemon to keep running and patched.
Do I need root privileges to run Docker or Podman?
By default, Docker requires root privileges (or membership in the docker group, which is effectively equivalent to root access on the host, since it grants control over the daemon). Podman was built with rootless operation as a core design goal, and unprivileged users can run Podman containers without any special group membership or daemon configuration in most standard setups. This is one of Podman’s most commonly cited security advantages: a compromised rootless Podman container has a much smaller potential blast radius than a compromised container running under a root-owned Docker daemon.
How do I stop and remove a container?
docker stop container_name (or ID) stops a running container gracefully, sending a termination signal and waiting briefly before forcing it to stop if needed. docker rm container_name removes a stopped container entirely, freeing its writable layer and metadata; a running container generally must be stopped first, or removed with docker rm -f to force-stop and remove in one step. Stopping a container does not remove it, a stopped container remains listable with docker ps -a and can be restarted with docker start, whereas rm actually deletes it.
What does -v do in a docker run command?
-v mounts a volume or bind-mounts a host directory into the container, making data persist beyond the container’s own lifecycle and letting the container read or write files on the host filesystem. docker run -v /host/path:/container/path image maps a specific host directory into the container at the given path. Without a volume mount, any files a container writes live only in its own writable layer and are lost when the container is removed, which is why databases, uploaded files, and other persistent data are almost always paired with a volume mount in real deployments.
How do I see what containers and images are currently on my system?
docker ps lists currently running containers; add -a to include stopped ones as well (docker ps -a). docker images lists all locally downloaded or built images. Both commands work identically with podman substituted for docker. To free up disk space by removing unused images, stopped containers, and other clutter, docker system prune (or podman system prune) removes anything not currently in use, after a confirmation prompt.