Docker Container Commands Explained: Understand, Don't Memorize
When you are new to Docker (or Podman, or nerdctl), the number of commands you need to learn can be truly overwhelming.
Docker tries to control the complexity of its CLI by employing a neat grouping technique.
The first thing you see after running docker help
is a list of so-called Management Commands -
umbrella entry points gathering the actual commands by their area of responsibility. But even this list is no short, and it's actually a list of lists!

Also, historically, many commands are known through their shorter but vaguer aliases -
for instance, you'd rather run into docker ps
than docker container list
in the wild. So, the struggle is real 🤪
However, there might be a way to internalize (at least some of) the most important Docker commands without the brute-force memorization!
The goal of this article is to show how a tiny bit of understanding of the containers' nature can help you master Docker's CLI, starting from the most foundational group of commands - commands to manage containers.
Process-File Duality
You've probably already seen or even used many of the Docker container management commands (likely in their shorter form):
docker create # docker container create
docker rename # docker container rename
docker update # docker container update
docker start # docker container start
docker restart # docker container restart
docker wait # docker container wait
docker stop # docker container stop
docker kill # docker container kill
docker run # docker container run
docker exec # docker container exec
docker attach # docker container attach
docker ps # docker container ls
docker rm # docker container rm
docker logs # docker container logs
docker cp # docker container cp
docker diff # docker container diff
docker commit # docker container commit
docker export # docker container export
But have you ever wondered why some of the commands resemble typical process management operations while others look more like file management commands?

This process-file duality might not make much sense for the followers of the "containers are just Linux processes" mantra. And that is yet another reason why I prefer a different analogy - in my opinion, the abstraction becomes less leaky when you start thinking of containers as of isolated and restricted execution environments for processes:
- Isolation - Linux namespaces and other OS-level virtualization means.
- Restriction - Linux capabilities, cgroups, seccomp and AppArmor profiles, etc.
- State - running processes, root filesystem, temporary files, logs, etc.

So, when it comes to managing such environments, you need to have commands to deal with all the parts and not just the processes.
Don't get fooled by Docker trying hard to make containers look like processes by promoting its deceptive docker run
UX 😉
The docker container create
command
...a.k.a docker create
To get a container running, you need to have its files around first.
Typically, containers live on disk at /var/lib/docker/containers/<CONTAINER-ID>
.
The docker create <IMAGE> [COMMAND] [ARG...]
command creates a dedicated container subfolder at the said location with the supplied
(or default, or defined by the image) container configs.
It may also pull the specified image, but it'll not start any processes, so it'll return the control as soon as all the preparations are done.
Comparing to docker run
, this command is much better scoped!
The docker container rename
and update
commands
Well, probably if you changed your mind after creating a container, you can update its configs on disk without re-creating the container. Haven't seen these commands used in the wild...
The docker container start
command
...a.k.a. docker start
The counterpart of the docker create
command is the docker start <CONTAINER>
command -
it starts only created earlier containers (by their names or IDs).
This command creates an OCI runtime bundle
(using the files prepared by the docker create
step) and the isolation borders (using the configs from the docker create
step)
and then launches the containerized process in this new environment.

What happens under the hood when you create and then start a container.
Since you potentially may want to interact with the containerized process,
the docker start
command offers two interesting flags: -a, --attach
and -i, --interactive
.
The first flag is about the container's STDOUT/STDERR streams.
If you provide it, the command will block your terminal and wire it with the corresponding container's standard streams.
The second flag does a similar thing but to the container's STDIN stream.
And if none of the flags are provided, the command will exit immediately,
letting the containerized process run in the background.
The docker container wait
command
...a.k.a. docker wait
If the container(ized process) is running in the background, you may want to know when it exits.
For that, there is the docker wait <CONTAINER>
command.
It'll block your terminal until the container(ized process) terminates and then print out its exit code.
In a way, it's similar to man 2 wait
.
If you run this command for a stopped (or not started yet) container, it'll exit immediately, reporting the saved container exit code (or 0
).
The docker container stop
and kill
commands
Two very similar commands - they both send signals to the containerized process,
potentially with an intention to terminate it.
Notice how the separation of processes from execution environments allows a container to outlive its process(es).
In particular, because container configs, rootfs, and logs are kept on disk.
So, you can always restart a stopped (or killed, or unexpectedly exited container).
Well, unless you haven't used the --rm
flag on the docker create
step 😉
Bonus: the docker restart
command is simply docker stop
followed by docker start
.
The docker container ls
command
...a.k.a docker ps
Another deceptive one!
The shortcut form of this command (docker ps
) and its default behavior (listing only running containers) reinforces the belief that containers are just processes.
However, if you run it with the -a
flag, it'll list all (including created and not started or stopped and not removed yet) containers.
So, it's a fancy way to list all subfolders of /var/lib/docker/containers
, showing only the ones corresponding to running containers by default.
The docker container rm
command
...a.k.a. docker rm
If docker ps
is a way to list subfolders of /var/lib/docker/containers
, the docker rm <CONTAINER>
command is a way to remove them.
The docker container run
command
...a.k.a. docker run
I hope by now, the distinction between containers from processes is already apparent.
So, it's time to tackle the docker run
command.
If we can create, start, wait, and stop containers using the above commands,
what the docker run <IMAGE> [COMMAND] [ARG...]
command is for?
Well, it's just another shortcut!
You can think of docker run
as of a combination of docker create
and docker start
.
It's a handy way to run a command, always in a new container.

🧙♂️ You shall not pass!
This tutorial is only available at the premium tier. Please upgrade your account to unlock all learning materials, get unlimited daily usage, and access to more powerful playgrounds. Help us keep this platform alive and growing!
Level up your Server Side game — Join 11,000 engineers who receive insightful learning materials straight to their inbox