KAHIBARO
Discord Login Register

21.7. Running Containers

Basic Idea Of Running Containers

Running a container means starting an isolated process from an image.
You can think of it as:

You always:

  1. Choose an image.
  2. Run docker run with some options.
  3. Docker creates a container, starts it, and attaches or detaches your terminal.

In this chapter we focus on how to run containers in different ways and what the most common options mean.

Key rule:
You build or pull an image once, then you can run many containers from that image.


The `docker run` Command

The main command:

bash
docker run [OPTIONS] IMAGE [COMMAND] [ARG...]

Typical structure:

PartExampleMeaning
docker rundocker runStart a new container
OPTIONS-it -p 8080:80Configure networking, environment, etc.
IMAGEnginxBase image to use
COMMANDbashOverride default command (optional)
ARG...-lArguments passed to the command

Example:

bash
docker run ubuntu echo "Hello from container"

Running Simple Commands

You can use containers just to run a short command.

bash
docker run ubuntu ls

This:

  1. Starts a container from the ubuntu image.
  2. Runs ls inside it.
  3. Shows the result in your terminal.
  4. Stops the container.

Some common examples:

bash
# Print OS version inside Ubuntu
docker run ubuntu cat /etc/os-release
# Use Alpine as a small Linux to run 'echo'
docker run alpine echo "Hi from Alpine"
# Use Python image to run a small one-line script
docker run python:3.12-alpine python -c "print('Hello, Python in Docker')"

Every time you run these, Docker creates a new container instance.


Interactive Containers (`-it`)

To get a shell inside a container you use:

Often combined as -it:

bash
docker run -it ubuntu bash

This gives you an interactive shell:

text
root@<some-id>:/# ls
bin  boot  dev  etc  home  ...
root@<some-id>:/# pwd
/

When you type exit (or press Ctrl+D), the shell exits and the container stops.

More examples:

bash
# Alpine image uses 'sh' by default
docker run -it alpine sh
# Python REPL inside a container
docker run -it python:3.12-alpine python

Important:
If the main process (like bash, sh, or python) exits, the container stops.
A container lives as long as its main process runs.


Detached Mode (`-d`)

If you do not want to keep the container attached to your current terminal, run it in detached mode:

bash
docker run -d nginx

You can then:

bash
docker ps             # list running containers
docker logs <id>      # view output
docker stop <id>      # stop container

Example with a specific name:

bash
docker run -d --name my-nginx nginx
docker ps
docker logs my-nginx
docker stop my-nginx

Naming Containers (`--name`)

If you do not specify a name, Docker generates one like elegant_panda.

To work with containers more easily, name them:

bash
docker run --name backend -d python:3.12-alpine sleep 3600

Now you can use backend instead of the long ID:

bash
docker logs backend
docker stop backend
docker rm backend

Common pattern for backend work:

bash
# Example: run PostgreSQL with a fixed name
docker run -d \
  --name my-postgres \
  -e POSTGRES_PASSWORD=secret \
  postgres:16

Publishing Ports (`-p`)

By default, container ports are not reachable from your host.
To make a container port accessible, you publish it:

bash
docker run -d -p HOST_PORT:CONTAINER_PORT IMAGE

Example with Nginx:

bash
docker run -d -p 8080:80 nginx

Another example, typical for a backend:

bash
# Suppose your app listens on port 8000 inside the container
docker run -d -p 8000:8000 my-backend-image

Table of examples:

CommandMeaning
-p 8080:80Host 8080 → Container 80
-p 5000:5000Host 5000 → Container 5000
-p 127.0.0.1:5432:5432Only on localhost, 5432 → Container 5432

If you specify IP like 127.0.0.1:8080:80, the port is only bound to localhost, not all network interfaces.


Environment Variables in Containers (`-e`)

Backends often configure:

through environment variables.

You can set them when running a container:

bash
docker run -d \
  -e APP_ENV=production \
  -e DEBUG=false \
  my-backend-image

To check environment variables inside a container:

bash
docker run --rm -e FOO=bar alpine sh -c 'echo $FOO'

Examples for common services:

bash
# PostgreSQL with password
docker run -d \
  --name db \
  -e POSTGRES_PASSWORD=secret \
  postgres:16
# Redis with a custom password (example)
docker run -d \
  -e REDIS_PASSWORD=somepass \
  redis:7-alpine

You can also load environment variables from a file:

bash
docker run -d --env-file .env my-backend-image

.env format:

text
APP_ENV=development
DATABASE_URL=postgresql://user:pass@db:5432/app

Volumes and Mounts (`-v` / `--mount`)

Containers have their own filesystem.
When a container is removed, its filesystem is usually removed too.

To keep data or share files with the host, you use volumes or bind mounts.

Anonymous volume

Simple example:

bash
docker run -d -v /var/lib/postgresql/data postgres:16

Docker creates a volume and mounts it at /var/lib/postgresql/data inside the container.

Named volume

Better for databases and important data:

bash
docker volume create pgdata
docker run -d \
  --name db \
  -e POSTGRES_PASSWORD=secret \
  -v pgdata:/var/lib/postgresql/data \
  postgres:16

Now database data persists even if you remove the container.

Bind mount (share host directory)

Very useful during development to share your code with the container:

bash
docker run -it \
  -v $(pwd):/app \
  -w /app \
  python:3.12-alpine \
  python main.py

Explanation:

Table of mount patterns:


TypeExampleUse case
Named volume-v pgdata:/var/lib/postgresql/dataPersistent DB data
Bind mount-v $(pwd):/appShare source code in development
Read-only-v $(pwd):/app:roShare code without write access

Working With Container Lifecycle

Listing containers

bash
docker ps                  # running only
docker ps -a               # all, including stopped

Important columns:

Example:

text
CONTAINER ID   IMAGE      COMMAND                  STATUS         PORTS                  NAMES
abc123def456   nginx      "/docker-entrypoin..."   Up 2 minutes   0.0.0.0:8080->80/tcp   my-nginx

Stopping and starting

bash
docker stop my-nginx      # send SIGTERM then SIGKILL after timeout
docker start my-nginx     # start a stopped container

stop and start keep the container’s filesystem and configuration.

Restarting

bash
docker restart my-nginx

This is like stop then start.

Removing containers

When you no longer need a container:

bash
docker rm my-nginx

If it is running, you can force:

bash
docker rm -f my-nginx

Important:
docker rm removes the container, not the image.
If you did not use volumes, data inside the container filesystem is lost.

You can also automatically remove a container after it exits:

bash
docker run --rm alpine echo "one-time task"

Inspecting Containers

To inspect what is happening inside or about a container:

Logs

bash
docker logs my-nginx
docker logs -f my-nginx      # follow logs like 'tail -f'

Executing commands in a running container

bash
docker exec -it my-nginx bash

or for Alpine:

bash
docker exec -it my-app sh

This gives you a shell in an already running container.
You can also run a single command:

bash
docker exec my-nginx ls /etc/nginx

Inspect metadata

bash
docker inspect my-nginx

This prints detailed JSON about:

Restart Policies

For backend services in production, you often want containers to restart automatically if they crash or when the host reboots.

Use --restart:

bash
docker run -d \
  --name my-backend \
  --restart unless-stopped \
  my-backend-image

Common restart policies:

PolicyBehavior
noNever restart (default)
on-failureRestart only if exit code is non-zero
alwaysAlways restart, even after docker daemon restart
unless-stoppedRestart unless you manually stop the container

Example for a database:

bash
docker run -d \
  --name db \
  --restart unless-stopped \
  -e POSTGRES_PASSWORD=secret \
  -v pgdata:/var/lib/postgresql/data \
  postgres:16

Practical Backend Examples

Here are some realistic commands you might use as a backend developer.

Run a local PostgreSQL database

bash
docker volume create pgdata
docker run -d \
  --name postgres \
  -e POSTGRES_USER=app \
  -e POSTGRES_PASSWORD=secret \
  -e POSTGRES_DB=app_db \
  -v pgdata:/var/lib/postgresql/data \
  -p 5432:5432 \
  postgres:16

Then in your backend app you can connect to localhost:5432.

Run Redis for caching or sessions

bash
docker run -d \
  --name redis \
  -p 6379:6379 \
  redis:7-alpine

Connect from your app to localhost:6379.

Run a FastAPI app image

Assume you built my-fastapi-app:latest which listens on port 8000.

bash
docker run -d \
  --name fastapi \
  -p 8000:8000 \
  -e APP_ENV=development \
  my-fastapi-app:latest

You can now open http://localhost:8000/docs.


Summary

In this chapter you learned how to:

These are the day-to-day Docker commands you will use when developing and running backend applications.

Views: 10

Comments

Please login to add a comment.

Don't have an account? Register now!