02 - Running Containers¶
What this session is¶
About 45 minutes. Deep dive on docker run - the flag that matters, what each does, how to think about a container's lifetime.
The mental model¶
A container is a wrapped process. docker run does three things:
- Creates a container from an image.
- Starts it (runs the configured command).
- Streams stdout/stderr to your terminal (or detaches if
-d).
When the main process exits, the container stops. (A container is alive while its main process is alive.)
Anatomy of docker run¶
The full shape:
- FLAGS modify how the container runs (interactive, ports, volumes, env, etc.).
- IMAGE is which image to use (e.g.
nginx,python:3.12). - COMMAND (optional) overrides the image's default command.
- ARGS (optional) are passed to that command.
Examples:
docker run nginx # run nginx with its default cmd
docker run -it ubuntu bash # override: run bash instead
docker run python:3 python -c "print(42)" # override + args
The flags that matter¶
-i / -t / -it - interactivity¶
-ikeeps stdin open. Required if you want to type into the container.-tallocates a pseudo-TTY. Makes the prompt look like a real terminal.-itis the combination - for shells.
For one-off commands that don't need input, omit -it:
--rm - auto-cleanup¶
Without --rm, the stopped container hangs around (so you can docker logs it, docker start it again, etc.). For one-shot runs, --rm is right.
-d - detached¶
Runs the container in the background. Returns to your shell immediately. Use for services (web servers, databases) you want to leave running.
-p HOST:CONTAINER - port mapping¶
A container has its own network namespace. Its localhost is not your localhost. To reach a container's port from outside, publish it:
You can publish multiple ports:
Or bind to a specific host interface:
If you don't -p a port, it's not reachable from your host. Containers on the same Docker network can still reach each other (page 07).
-e KEY=value - environment variables¶
Many images are configured via env vars. Read the image's documentation on Docker Hub.
For long lists, use an env-file:
--name NAME - give it a name¶
Without --name, Docker generates a random one (practical_einstein). With --name, you can refer to it by name in subsequent commands:
Names are unique per machine; only one container with a given name at a time.
-v HOST:CONTAINER - bind mounts and volumes¶
Mount a host directory or a named volume into the container. Full coverage in page 06; preview:
docker run -v $(pwd):/data alpine ls /data # mount current dir as /data inside
docker run -v mydata:/var/lib/postgresql/data postgres # named volume
--network NAME - network¶
Connects the container to a specific Docker network. Full coverage in page 07.
Resource limits¶
Limits memory and CPU. Containers without limits can starve the host. Always set limits for production-shaped runs.
--workdir DIR - initial working directory¶
Equivalent to cd /app inside the container before the command runs.
--user UID:GID - run as a specific user¶
Useful when working with mounted volumes (file ownership matches the host user).
Override the image's default command¶
Everything after the image name and before the optional -- is the command + args.
Use --entrypoint to override the image's entrypoint (a deeper override; we'll see entrypoint vs cmd in page 05):
Running interactively vs running detached¶
Two common shapes:
Interactive (foreground), one-shot:
Detached service:
For services you want to keep running, drop --rm (so the container survives a stop and can be restarted with docker start SVC).
A real example: a Redis instance¶
That starts Redis on port 6379. Test from your host:
Stop it:
Restart later:
Remove (when done):
A multi-line docker run (for readability)¶
Long commands are easier to read split across lines with \:
docker run -d \
--name api \
-p 8080:80 \
-e DATABASE_URL=postgres://db:5432/mydb \
-v $(pwd)/data:/data \
--memory=512m \
--restart=unless-stopped \
my-image:1.0
This is what real-world docker run invocations look like. By page 08 (Compose) you'll see how to write this as YAML and avoid retyping the flags.
Exercise¶
-
Hello with a name and port:
Openhttp://localhost:8081. Stop the container. -
Environment variable:
Should printhi from env. -
Volume preview:
You should see the contents of your current directory listed. -
Resource limits:
Note the memory limit reported inside. -
Use a name to re-attach:
What you might wonder¶
"Why both -i and -t?"
-i keeps stdin connected (you can type). -t makes Docker allocate a pseudo-terminal so the program thinks it's running in a real terminal (colors work, line editing works). For a shell you want both. For a pipe (e.g. echo "hi" | docker run -i ...) you only need -i.
"What's the difference between -p 8080:80 and -P (capital P)?"
-P publishes all the image's EXPOSEd ports to random host ports. Rarely used in practice. Stick with explicit -p.
"What's --restart?"
A policy for what to do when the container exits or the daemon restarts. --restart=always, --restart=unless-stopped, --restart=on-failure. Useful for services you want to survive reboots.
"Can a container have multiple processes?" Yes, but the convention is "one main process per container." If you need multiple, use multiple containers (page 08) or a process supervisor inside.
Done¶
- Run interactive shells in containers.
- Run detached services with port mappings.
- Pass environment variables.
- Name containers for easy reference.
- Set resource limits.
- Read a real-world
docker runinvocation.