Free Ebook cover Docker for Beginners: Containers Explained with Simple Projects

Docker for Beginners: Containers Explained with Simple Projects

New course

12 pages

Running and Inspecting Containers with Core Commands

Capítulo 4

Estimated reading time: 10 minutes

+ Exercise

Why “run” and “inspect” are the core of day-to-day Docker

Once you already understand what images and containers are and how Dockerfiles build images, most of your daily work becomes a tight loop: start a container, verify it is doing what you expect, look inside it when something is off, and stop or remove it cleanly. This chapter focuses on the core commands used in that loop, with practical, repeatable steps and the mental model for what each command shows you.

We will use a few small examples (a web server, a database, and a “sleeping” container) to practice. The goal is not to memorize flags, but to know which command answers which question: “Is it running?”, “What ports are open?”, “What is it logging?”, “What environment variables did it get?”, “What files are in the container?”, “Why did it exit?”, and “How do I clean up?”

Running containers: docker run as the all-in-one starter

docker run creates a new container from an image and starts it. It is effectively a shortcut for “create + start” with configuration in one command. The most common things you decide at run time are: container name, whether it runs in the background, port publishing, environment variables, and volume mounts.

Basic run patterns

1) Run a container in the foreground (attached):

docker run nginx:alpine

This will attach your terminal to the container’s main process. If that process writes to stdout/stderr, you will see it. If you stop it with Ctrl+C, the container stops.

Continue in our app.

You can listen to the audiobook with the screen off, receive a free certificate for this course, and also have access to 5,000 other free online courses.

Or continue reading below...
Download App

Download the app

2) Run in the background (detached):

docker run -d nginx:alpine

Detached mode returns you to your shell immediately and prints a container ID. The container keeps running in the background.

3) Give the container a friendly name:

docker run -d --name web nginx:alpine

Naming is practical because many other commands accept a name instead of a long ID.

4) Publish a port from container to host:

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

This maps host port 8080 to container port 80. You can now access the service via http://localhost:8080 on the host.

5) Set environment variables:

docker run -d --name demo-env -e APP_MODE=dev -e FEATURE_X=true nginx:alpine

Environment variables are a common way to configure containers at runtime.

6) Mount a host directory into the container (bind mount):

docker run -d --name web -p 8080:80 -v "$PWD/site":/usr/share/nginx/html:ro nginx:alpine

This serves files from your local site folder. The :ro makes it read-only inside the container.

Choosing between --rm and keeping containers

For short-lived experiments, you often want the container removed automatically when it exits:

docker run --rm alpine:3.20 echo "hello from a temporary container"

--rm is great for one-off commands. For services you want to inspect after stopping (logs, exit codes, configuration), do not use --rm so you can examine the container after it exits.

Overriding the default command

Many images define a default command. You can override it by appending a command to docker run:

docker run --rm alpine:3.20 ls -la

This runs ls -la inside the container and then exits.

Interactive containers: -it

When you need a shell or interactive program, use -it (interactive + pseudo-TTY):

docker run --rm -it alpine:3.20 sh

You are now inside the container. Type exit to leave.

Listing and identifying containers: docker ps

After starting containers, the first inspection question is usually “What is running right now?”

docker ps

This shows running containers. Key columns include:

  • CONTAINER ID: short ID you can use in commands
  • IMAGE: which image it was created from
  • COMMAND: the main process command
  • STATUS: running time or exit status
  • PORTS: published ports, if any
  • NAMES: friendly name (auto-generated if you didn’t set one)

To see all containers, including stopped ones:

docker ps -a

This is essential when a container exits quickly and disappears from docker ps but still exists and can be inspected.

Practical step-by-step: spot a container that exited

1) Run a container that exits immediately:

docker run --name quick alpine:3.20 sh -c "echo done; exit 2"

2) Check running containers (you won’t see it):

docker ps

3) Check all containers (you will see it with an exit code):

docker ps -a

4) You can now inspect why it exited using logs and exit code (covered below).

Watching logs: docker logs

Containers typically write application output to stdout/stderr. Docker captures that output, and docker logs lets you view it.

docker logs web

Common options:

  • -f: follow (stream) logs like tail -f
  • --tail N: show only the last N lines
  • --since 10m: show logs since a time (e.g., 10 minutes)
  • -t: show timestamps
docker logs -f --tail 50 web

When debugging, logs are usually the first place to look. If a container exits immediately, docker logs often tells you what failed (missing config, permission issues, port conflicts inside the app, etc.).

Starting, stopping, restarting: docker start, docker stop, docker restart

These commands manage container lifecycle after creation.

  • docker stop sends a graceful stop signal and waits before forcing termination.
  • docker start starts an existing stopped container.
  • docker restart stops then starts.
docker stop web
docker start web
docker restart web

Why this matters: if you created a container with a specific name, port mapping, environment variables, and mounts, docker start reuses that configuration. You do not need to retype the full docker run command.

Force stopping: docker kill

If a container does not stop gracefully, you can force it:

docker kill web

Use this sparingly; it is similar to abruptly terminating a process.

Inspecting container details: docker inspect

docker inspect returns a detailed JSON document about a container (or image, network, volume). It is the most complete source of truth for “what did Docker actually configure?”

docker inspect web

The output is large. In practice, you often filter it using Go template formatting:

docker inspect -f '{{.State.Status}}' web
docker inspect -f '{{.State.ExitCode}}' quick
docker inspect -f '{{.Name}}' web

Useful inspection targets:

  • State: running, exited, paused; start/finish timestamps; exit code
  • Config: environment variables, command, working directory
  • HostConfig: port bindings, mounts, restart policy
  • NetworkSettings: container IP, networks, exposed ports

Practical step-by-step: find the host port mapped to a container port

Sometimes you used -p 0:80 (random host port) or you forgot what you mapped. You can query it.

1) Run with a random host port:

docker run -d --name web-random -p 0:80 nginx:alpine

2) Inspect the port mapping:

docker inspect -f '{{json .NetworkSettings.Ports}}' web-random

3) Or use docker ps to see the published port in a human-friendly way:

docker ps --filter name=web-random

Executing commands inside a running container: docker exec

docker exec runs a new process inside an already running container. This is different from docker run, which creates a new container. Use exec for live troubleshooting: checking files, testing connectivity, viewing environment variables, or running admin commands.

Example: open a shell in a running container:

docker exec -it web sh

Example: run a single command:

docker exec web ls -la /usr/share/nginx/html

Example: check environment variables from inside:

docker exec demo-env sh -c 'env | sort | head'

Practical step-by-step: verify a web server is serving the files you expect

1) Create a local folder and file:

mkdir -p site && printf '<h1>Hello from bind mount</h1>' > site/index.html

2) Run Nginx with the bind mount:

docker run -d --name web-mount -p 8081:80 -v "$PWD/site":/usr/share/nginx/html:ro nginx:alpine

3) Inspect the container’s filesystem path:

docker exec web-mount ls -la /usr/share/nginx/html

4) Confirm the file content:

docker exec web-mount sh -c 'cat /usr/share/nginx/html/index.html'

5) Check logs if the page is not loading:

docker logs --tail 50 web-mount

Copying files to/from containers: docker cp

Sometimes you need to extract a generated file (a report, a build artifact) or inject a config file for quick testing. docker cp copies files between your host and a container.

Copy from container to host:

docker cp web-mount:/etc/nginx/nginx.conf ./nginx.conf

Copy from host to container:

docker cp ./nginx.conf web-mount:/etc/nginx/nginx.conf

Note: if you copy into a running container, the application may need a reload/restart to pick up changes. For many services, a restart is the simplest approach:

docker restart web-mount

Viewing resource usage: docker stats

When a container feels slow or your laptop fan spins up, you want a quick view of CPU and memory usage.

docker stats

This shows live metrics per running container. You can also target a specific container:

docker stats web

Use this to confirm whether a container is consuming unexpected resources, and to compare multiple containers at once.

Seeing processes inside containers: docker top

docker top lists processes running inside a container (from the host’s perspective).

docker top web

This is useful when:

  • You suspect the main process spawned child processes
  • You want to confirm which command is actually running
  • You need a quick check without opening a shell via docker exec

Understanding networking at a glance: docker port

While docker inspect can show port bindings, docker port is a quick shortcut to display published ports.

docker port web

Or for a specific container port:

docker port web 80

This answers “Which host port is mapped to container port 80?” without parsing JSON.

Container events and “what just happened?”: docker events

When troubleshooting intermittent issues, it helps to see a stream of Docker events: container start/stop/die, network connect/disconnect, and more.

docker events

Filter by container:

docker events --filter container=web

Filter by time window:

docker events --since 30m

This is especially useful when containers are managed by scripts and you want to confirm the order of operations.

Cleaning up: removing containers with docker rm and pruning

Stopped containers take disk space (logs and metadata). Removing them keeps your environment tidy.

Remove a stopped container:

docker rm quick

Remove a running container (force):

docker rm -f web

Remove multiple containers by name/ID:

docker rm web web-mount web-random

Practical step-by-step: clean up everything from this chapter

1) List all containers you created:

docker ps -a

2) Stop running ones:

docker stop web web-mount web-random demo-env 2>/dev/null

3) Remove them:

docker rm web web-mount web-random demo-env quick 2>/dev/null

4) Optionally remove unused stopped containers in general:

docker container prune

docker container prune removes all stopped containers. It will ask for confirmation.

A practical troubleshooting workflow using core commands

When a container does not behave as expected, you can follow a consistent sequence. This is a practical “decision tree” you can apply to most beginner projects.

Scenario: “My container isn’t reachable in the browser”

1) Is it running?

docker ps --filter name=web

If it’s not running, check all containers:

docker ps -a --filter name=web

2) Did it exit? What exit code?

docker inspect -f '{{.State.Status}} {{.State.ExitCode}}' web

3) What do the logs say?

docker logs --tail 100 web

4) Are ports published as expected?

docker port web

Or:

docker ps --filter name=web

5) If it’s running but still not working, check inside quickly:

docker exec -it web sh

Then verify the service is listening and files exist (commands vary by image; for Alpine-based images you might use basic tools available in the image). If the image is minimal and lacks tools, you can still inspect config files and directory contents with ls and cat.

Scenario: “It worked yesterday; what changed?”

1) Compare configuration via inspect (environment, mounts, ports):

docker inspect web

2) Look for recent restarts or failures:

docker events --since 2h --filter container=web

3) Watch resource usage while reproducing the issue:

docker stats web

Reference cheat sheet: core commands and the question they answer

  • docker run: “Start a new container with these settings.”
  • docker ps: “What is running?”
  • docker ps -a: “What exists (including stopped)?”
  • docker logs: “What did the app output?”
  • docker stop/start/restart: “Control lifecycle of an existing container.”
  • docker inspect: “Show the full configuration and state details.”
  • docker exec: “Run a command inside a running container.”
  • docker cp: “Copy files between host and container.”
  • docker stats: “How much CPU/memory is it using?”
  • docker top: “Which processes are running inside?”
  • docker port: “Which host ports map to container ports?”
  • docker events: “What Docker actions occurred over time?”
  • docker rm/docker container prune: “Remove containers and clean up.”

Now answer the exercise about the content:

You started a container with docker run using a specific name, port mapping, environment variables, and a bind mount. After stopping it, which command should you use to start the same container again without retyping the full run configuration?

You are right! Congratulations, now go to the next page

You missed! Try again.

docker start starts an existing stopped container and reuses the configuration it was created with (name, ports, env vars, mounts). docker run creates a new container, and docker exec runs a command inside a running one.

Next chapter

Persisting Data with Volumes and Bind Mounts

Arrow Right Icon
Download the app to earn free Certification and listen to the courses in the background, even with the screen off.