Docker Guide: Containers from Development to Production

Docker packages applications and their dependencies into lightweight, portable containers. This guide covers installation, image building, networking, orchestration with Compose, and security hardening.

Installation

On Debian/Ubuntu, install from the official Docker repository:

# Add Docker's GPG key and repository
sudo apt-get update
sudo apt-get install ca-certificates curl gnupg
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg |   sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
echo "deb [arch=$(dpkg --print-architecture)   signed-by=/etc/apt/keyrings/docker.gpg]   https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" |   sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io

# Verify the installation
sudo docker run hello-world

On RHEL/CentOS, use dnf config-manager --add-repo with the Docker repo URL.

Writing a Dockerfile

A Dockerfile defines how an image is built, layer by layer:

FROM python:3.12-slim

RUN apt-get update && apt-get install -y --no-install-recommends       gcc libpq-dev &&     rm -rf /var/lib/apt/lists/*

WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY . .

EXPOSE 8000

CMD ["gunicorn", "-w", "4", "-b", "0.0.0.0:8000", "app:application"]

Key instructions: FROM sets the base image, RUN executes commands during build, COPY adds files, EXPOSE documents the port, and CMD sets the default runtime command.

Multi-Stage Builds

Reduce final image size by compiling in one stage and copying only the artifacts to a minimal runtime image:

# Build stage
FROM golang:1.22 AS builder
WORKDIR /src
COPY . .
RUN CGO_ENABLED=0 go build -o /app

# Runtime stage
FROM alpine:3.19
COPY --from=builder /app /app
ENTRYPOINT ["/app"]

The final image contains only the compiled binary and the Alpine base -- typically under 20 MB.

Volumes

Persist data outside the container's writable layer:

# Named volume (Docker manages the storage location)
docker volume create pgdata
docker run -d -v pgdata:/var/lib/postgresql/data postgres:16

# Bind mount (host directory mapped into the container)
docker run -d -v /srv/html:/usr/share/nginx/html:ro nginx

The :ro flag makes the mount read-only inside the container.

Networking

Docker provides several network drivers:

# Bridge (default) -- containers on the same bridge can talk
docker network create mynet
docker run -d --name web --network mynet nginx
docker run --rm --network mynet curlimages/curl http://web

# Host -- container shares the host's network stack (no port mapping needed)
docker run -d --network host nginx

# Overlay -- spans multiple Docker hosts (requires Swarm)
docker network create -d overlay prod-net

Docker Compose

Define multi-container applications in a single file:

# compose.yaml
services:
  web:
    build: .
    ports:
      - "8000:8000"
    environment:
      - DATABASE_URL=postgres://db:5432/app
    depends_on:
      - db

  db:
    image: postgres:16
    volumes:
      - pgdata:/var/lib/postgresql/data
    environment:
      POSTGRES_PASSWORD: changeme

volumes:
  pgdata:
docker compose up -d      # start in the background
docker compose logs -f     # follow logs
docker compose down        # stop and remove containers

The depends_on key controls startup order but does not wait for readiness. For that, use health checks or a wait-for-it script.

Security Best Practices

  1. Run as non-root. Add USER 1000 in your Dockerfile after installing packages.
  2. Use rootless Docker on hosts where possible:
dockerd-rootless-setuptool.sh install
  1. Scan images for vulnerabilities:
docker scout cves myimage:latest
# Or use Trivy:
trivy image myimage:latest
  1. Pin image digests in production to avoid supply-chain surprises:
FROM python:3.12-slim@sha256:abcdef1234567890...
  1. Limit resources:
docker run -d --memory=512m --cpus=1.5 myimage

Return to the DevOps hub or continue to Kubernetes Fundamentals and Ansible Guide.