Docker – Install It and Run Your First Container

June 18, 20264 min readUpdated 8/21/2026

There are two things called Docker and it helps to know which one you are installing.

Desktop or Engine

Docker Desktop is what you want on a Mac or a Windows machine. Neither has a Linux kernel, and containers need one — so Desktop quietly runs a small Linux VM and puts the docker command on your machine talking to it. It also brings a GUI, Compose, and buildx. It is free for personal use and for small companies; large ones need a licence.

Docker Engine is the daemon on its own, for Linux, where no VM is needed because the kernel is already there. This is what runs on servers.

Everything in this track works on either. Check what you have:

docker version
docker info

If docker version prints a Client block and then an error about the daemon, Docker is installed but not running — start Docker Desktop, or sudo systemctl start docker.

Run something

docker run hello-world

Four things happened. Docker looked for the hello-world image locally and did not find it; it pulled it from Docker Hub; it created a container from it; it ran the container's command, which printed a paragraph and exited.

Now something that stays up:

docker run -d -p 8080:80 --name web nginx:1.27-alpine

Visit http://localhost:8080 and nginx answers. Every part of that line is doing work:

-d — detached. Without it your terminal is attached to the container's output and Ctrl-C stops the container. Useful when you want the logs; annoying when you want your prompt.

-p 8080:80 — publish. Host port on the left, container port on the right, and mixing them up is the most common Docker mistake there is. Lesson 10 is about nothing else.

--name web — a name you choose. Without it Docker invents one like nostalgic_hopper and you have to look it up every time.

nginx:1.27-alpine — the image, and after the colon the tag. Leave the tag off and you get :latest, which is not a promise of anything (lesson 18).

The six commands you will actually use

docker ps                    # what is running
docker ps -a                 # ... including what has stopped
docker logs -f web           # follow its output
docker exec -it web sh       # a shell INSIDE the running container
docker stop web              # SIGTERM, then SIGKILL after 10s
docker rm web                # delete the stopped container

exec is the one worth getting comfortable with early. It starts a second process in an existing container, so you can look around:

$ docker exec -it web sh
/ # ls /usr/share/nginx/html
50x.html    index.html
/ # exit

-it is two flags: -i keeps stdin open, -t gives you a terminal. Without both, a shell starts and immediately exits with no explanation.

Note also sh, not bash. Alpine-based images have no bash, and docker exec -it web bash fails with executable file not found — which reads like the container is broken rather than minimal.

--rm, and why your disk fills up

A stopped container is not gone. It sits there holding its writable layer until you remove it, which is occasionally what you want and usually just clutter:

docker run --rm -p 8080:80 nginx:1.27-alpine

--rm deletes the container when it exits. Use it for anything throwaway.

When the clutter has already accumulated:

docker ps -a                 # look first
docker container prune       # remove all STOPPED containers
docker image prune           # remove dangling (untagged) images
docker system df             # what is actually using the space

Look before you prune. docker system prune -a is the one people paste from a forum answer; it also removes every image not currently used by a container, which means re-pulling and rebuilding everything. And --volumes on top of that deletes your databases.

"It exited immediately"

The single most common first problem. Try it deliberately:

$ docker run -d --name probe alpine:3.21
$ docker ps
CONTAINER ID   IMAGE   COMMAND   STATUS   PORTS   NAMES
$ docker ps -a
CONTAINER ID   IMAGE          COMMAND   STATUS                     NAMES
c3f1a2b9d4e5   alpine:3.21    "/bin/sh" Exited (0) 2 seconds ago   probe

Nothing is broken. A container lives exactly as long as its main process, and that image's main process is /bin/sh — which, given no input and no terminal, reaches end-of-file and exits successfully. Exit code 0 means it did what it was told.

The rule this comes down to: the process must stay in the foreground. A container whose command starts a daemon and returns exits the instant the command returns, no matter how healthy the daemon it launched was. It is why the nginx images run nginx -g 'daemon off;', and why lesson 4 cares about how CMD is written.

Clean up what we started:

docker stop web
docker rm web probe

Next: what an image is actually made of.