Skip to content

Beginner · Docker · topic 17 of 53 · 35 min

Running containers: ports, volumes, networks and limits

Explanation

docker run starts a container; options publish ports (-p host:container), set environment variables (-e), name it and run it in the background (-d). Container files vanish when the container is removed, so data goes in volumes or bind mounts. Containers on a user-defined network find each other by name. Restart policies and memory and CPU limits keep containers healthy on a shared server.

The everyday commands

bash
docker run -d --name shop-api -p 8080:3000 -e NODE_ENV=production shop-api:2.1.0
docker ps                    # running containers (add -a to include stopped ones)
docker logs -f shop-api      # follow the logs
docker exec -it shop-api sh  # open a shell inside the running container
docker stop shop-api         # graceful stop: SIGTERM, then SIGKILL after a timeout
docker start shop-api        # start it again (same container, same writable layer)
docker rm shop-api           # delete the stopped container
docker run --rm -it python:3.12-slim python   # throwaway container, removed on exit
-d runs in the background (detached). -it gives an interactive terminal. --rm deletes the container when it exits.
bash
docker images                          # local images
docker build -t shop-api:2.1.0 .       # build from the Dockerfile in this folder
docker pull postgres:17                # download
docker tag shop-api:2.1.0 ghcr.io/acme/shop-api:2.1.0
docker push ghcr.io/acme/shop-api:2.1.0  # upload (after docker login ghcr.io)
docker inspect shop-api                # full JSON details: IP, mounts, env, restart policy

Publishing ports

A container has its own network namespace, so an app listening on port 3000 inside it is not reachable from outside until you publish the port. -p 8080:3000 means "send traffic arriving on host port 8080 to container port 3000". The host part comes first.

OptionMeaning
-p 8080:80Host port 8080 on all interfaces → container port 80 (TCP)
-p 127.0.0.1:5432:5432Only reachable from the host itself, not from the network
-p 53:53/udpUDP instead of the default TCP
-p 3000Container port 3000 → a random free host port (see docker port)
Careful: Publishing a database with -p 5432:5432 on a cloud server makes it reachable from the internet if the firewall allows it, and Docker's own firewall rules can bypass a host firewall such as ufw. Bind to 127.0.0.1, or better, do not publish the database at all and let only other containers on the same network reach it.

Storage: volumes, bind mounts and tmpfs

Anything a container writes into its writable layer disappears when the container is removed, for example when you upgrade to a new image. Data that must survive goes outside the container.

TypeWhat it isUse it for
VolumeStorage managed by Docker (under /var/lib/docker/volumes on Linux)Databases and any data that must persist; easiest to back up and move
Bind mountA folder or file from the host mapped into the containerDevelopment (live code reload), or giving a container one config file
tmpfsMemory-only storage, gone when the container stopsTemporary files and sensitive scratch data (Linux hosts)
bash
docker volume create pgdata
docker run -d --name db -e POSTGRES_PASSWORD=devonly \
  -v pgdata:/var/lib/postgresql/data postgres:17      # named volume

docker run --rm -v "$(pwd)":/app -w /app node:24-slim npm test   # bind mount the current folder
docker run -d --tmpfs /tmp --read-only shop-api:2.1.0              # read-only root, writable /tmp in memory
In -v, a plain name (pgdata) means a volume; a path (/home/asha/app or "$(pwd)") means a bind mount.

Networks

Docker creates a default bridge network, a private network inside the host. Containers on it can reach the internet, but they cannot find each other by name. Create your own (user-defined) bridge network instead: Docker then runs a small DNS server, so a container called db is reachable at the host name db.

bash
docker network create shopnet
docker run -d --name db    --network shopnet -e POSTGRES_PASSWORD=devonly postgres:17
docker run -d --name api   --network shopnet -p 8080:3000 \
  -e DATABASE_URL=postgres://postgres:devonly@db:5432/postgres shop-api:2.1.0
The API reaches Postgres at db:5432. Postgres has no -p, so it is not reachable from outside the host.

With --network host, the container uses the host's network directly with no isolation and no port mapping. It is occasionally useful for network tools and works fully on Linux hosts; avoid it for normal apps.

Restart policies and resource limits

--restartBehaviour
no (default)Never restart automatically
on-failure[:N]Restart only if the process exits with a non-zero code, optionally at most N times
alwaysAlways restart; also starts again when the Docker daemon starts, even if you had stopped it by hand
unless-stoppedLike always, but stays stopped after the daemon restarts if you stopped it yourself
bash
docker run -d --name worker --restart unless-stopped \
  --memory 512m --cpus 1.5 shop-worker:2.1.0
docker stats            # live CPU and memory use per container
If a container goes over its memory limit, the kernel kills it (out of memory). Without limits, one leaky container can starve everything else on the server.

Cleaning up

bash
docker ps -a                 # find old stopped containers
docker image prune           # remove dangling images (untagged leftovers)
docker system prune          # remove stopped containers, unused networks, dangling images and build cache
Volumes are not removed unless you add --volumes.

Common mistakes

  • docker system prune -a --volumes on a server "to free space" can delete the volume holding your database if its container is stopped at that moment. Read the warning, and back up volumes first.
  • Getting the -p order wrong: it is host:container. -p 3000:8080 sends host port 3000 to container port 8080.
  • The app inside listens on 127.0.0.1 only, so -p seems not to work. Inside a container, the app must listen on 0.0.0.0.
  • Using container IP addresses in config. They change on restart; use names on a user-defined network.

Need help?

Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.

Try:

Watch the lesson

Running containers: ports, volumes, networks and limits · 1/8

docker run -d --name shop-api -p 8080:3000 shop-api:2.1.0

docker run starts a container. Dash d runs it in the background, name gives it a name, and rm deletes it when it exits.

Prefer a video by a teacher? Find free videos on “docker run volumes bind mounts networks tutorial” on YouTube ↗

In real life: A hospital lab report service in Kochi

A hospital IT team runs a small lab-report service on one Linux server. The report database runs in a container with a named volume, so upgrading Postgres images never touches the data, and it is not published to the network at all. The web app joins the same user-defined network, reaches the database as db, and is published on port 8080 behind the hospital's reverse proxy. Both containers use --restart unless-stopped, so after a power cut and reboot they come back on their own, and a memory limit stops the PDF generator from starving the database.

bash
docker network create labnet
docker run -d --name db --network labnet --restart unless-stopped \
  -v labdata:/var/lib/postgresql/data -e POSTGRES_PASSWORD_FILE=/run/secrets/pg postgres:17
docker run -d --name web --network labnet --restart unless-stopped \
  --memory 1g -p 8080:8000 lab-reports:1.8.2
The password file would be mounted from a secure location; it is never typed on the command line in production.

Practice (0/3 done)

Task 1 · Question

Your app listens on port 5000 inside the container. Which option makes it reachable at http://localhost:8000 on your laptop?

Task 2 · Code · Python

Write parse_port(spec) for docker run -p values. Return a dict with "host_ip" (None means all interfaces), "host_port" (None means Docker picks a random one), "container_port" (an int) and "protocol" ("tcp" by default). Formats: "3000", "8080:80", "127.0.0.1:5432:5432", "127.0.0.1::80" (empty host port) and any of these followed by "/udp", "/tcp" or "/sctp". Raise ValueError for another protocol, a port that is not a number, or a port outside 1 to 65535. IPv6 addresses are not tested.

Task 3 · Practice

On your own machine, run Postgres with a named volume, create a table and a row, then delete the container and start a NEW container with the same volume. Prove the row is still there. Then run a second container on a user-defined network that connects to the database by name.

Quick quiz

Question 1

1.What happens to files a container wrote into its own file system when you run docker rm on it?

Question 2

2.Two containers are on the default bridge network. Why can the api container not reach the database at the host name db?

Question 3

3.Which restart policy restarts a container only when its process exits with an error code?

Question 4

4.Which is the best way to share your source folder with a container for live reloading during development?

Question 5

5.What does --memory 512m do?

Read more (free)

Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.

What happens to files a container wrote into its own file system when you run docker rm on it?

Answer: They are deleted with the container

The writable layer belongs to the container. Use a volume for data that must survive.

Two containers are on the default bridge network. Why can the api container not reach the database at the host name db?

Answer: The default bridge network has no DNS by container name; use a user-defined network

User-defined bridge networks provide name resolution; the default bridge does not.

Which restart policy restarts a container only when its process exits with an error code?

Answer: on-failure

on-failure restarts on a non-zero exit code, optionally up to a maximum number of times.

Which is the best way to share your source folder with a container for live reloading during development?

Answer: A bind mount of the project folder

A bind mount maps a host folder into the container, so edits appear inside at once.

What does --memory 512m do?

Answer: Sets a hard memory limit; going over it gets the container's process killed

Memory limits are enforced with cgroups; the kernel kills the process when the limit is exceeded.

Which command removes the containers AND deletes the project's named volumes?Related

Answer: docker compose down -v

The -v flag removes named volumes declared in the file and anonymous volumes. Plain down keeps them.

From Docker Compose: multi-container apps

Why can't a rootless container publish host port 80 by default?Related

Answer: Ports below 1024 need root privileges

Unprivileged users cannot bind low ports by default.

From Containers with Podman: images, run, ports and logs

What is the difference between an image and a container?Related

Answer: An image is the package (recipe); a container is a running copy of it

You build an image once and start one or many containers from it.

From Docker: packaging your app

What happens to files written inside a container (not in a volume) after podman rm?Related

Answer: They are deleted with the container

The container layer is removed.

From Persistent storage and containers as systemd services

Pass the quiz (60% or more) or mark this topic as done when you are ready.

Your progress is saved on this device only.

Next steps

  1. 2 more topics in “Docker” before its exam: Docker Compose: multi-container apps, Image and container security.
  2. Module 4 exam: Docker · 14 questions · 25 min, without help. 5 topics of this module still to finish first.
  3. Then the next module, Kubernetes fundamentals. 53 topics left in the course before the final exam.

← Previous: Writing Dockerfiles: caching, multi-stage builds and small images