Skip to content
Home
Docker Containers: Build, Ship, and Run Anywhere

Docker Containers: Build, Ship, and Run Anywhere

Cloud Computing Cloud Computing 8 min read 1638 words Beginner ExcellentWiki Editorial Team

Docker revolutionized software development by making containers the standard unit of deployment. A container packages an application with all its dependencies — libraries, configuration files, binaries, and runtime — into a single artifact that runs identically on any Linux, Windows, or macOS machine. Docker containers are lightweight (megabytes, not gigabytes), start in milliseconds (not minutes), and consume only the resources they need. The Docker Engine runs on over 100 million machines worldwide according to Docker’s 2025 usage metrics.

Images vs. Containers

Understanding the distinction between images and containers is fundamental. An image is a read-only template containing the application, runtime, libraries, and configuration. A container is a runnable instance of an image — an isolated process with its own filesystem, network, and process namespace.

Think of images as classes in object-oriented programming and containers as instances. Multiple containers can run from the same image, each with its own writable layer for runtime modifications. When a container is deleted, the writable layer is discarded; the image remains unchanged.

Container images are built in layers, each corresponding to an instruction in the Dockerfile. Layers are cached — if you modify a later instruction but not an earlier one, Docker reuses the cached layers. This layer caching is the key to fast Docker builds.

Writing Effective Dockerfiles

A Dockerfile is a text file containing instructions for building an image. Every instruction creates a new layer:

FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 8000
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]

Best practices for Dockerfiles:

  • Use specific base image tagspython:3.12-slim not python:latest. The latest tag changes over time and breaks builds unpredictably. Slim variants reduce attack surface and image size.
  • Order instructions by cacheability — copy dependency files first (requirements.txt, package.json), run the install step, then copy the application code. This maximizes layer cache reuse when only application code changes.
  • Combine RUN commands — each RUN instruction creates a layer. Chain commands with && to reduce layers: RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/*
  • Use .dockerignore — exclude node_modules, .git, pycache, and other non-essential files to keep build context small

Build and run:

docker build -t excellentwiki-api:latest .
docker run -d -p 8000:8000 --name api excellentwiki-api:latest

Essential Docker Commands

CommandPurpose
docker psList running containers
docker imagesList local images
docker logs -f apiFollow container logs
docker exec -it api bashOpen interactive shell in container
docker stop api && docker rm apiStop and remove container
docker system pruneRemove unused containers, images, and networks

Docker provides docker inspect for detailed metadata about containers and images (JSON output), and docker stats for real-time resource usage monitoring.

Container Networking

Docker networks connect containers to each other and to the outside world:

  • Bridge (default) — isolated network on the host, containers communicate via IP. Best for single-host deployments.
  • Host — container uses the host’s network stack directly, no port mapping needed. Best for performance-sensitive workloads but reduces isolation.
  • Overlay — spans multiple Docker hosts in a Swarm cluster. Containers on different hosts communicate as if on the same network.
docker network create app-network
docker run --network app-network --name db postgres:16
docker run --network app-network --name api -p 8000:8000 excellentwiki-api

Containers on the same bridge network can resolve each other by container name — postgres://db:5432/mydb resolves to the database container’s IP.

Volumes: Persistent Storage

Containers are ephemeral — files created inside a container are lost when the container is removed. Volumes provide persistent storage that survives container restarts and removals:

docker volume create pgdata
docker run -v pgdata:/var/lib/postgresql/data -e POSTGRES_PASSWORD=secret postgres:16

Docker volumes are stored in the Docker host’s filesystem (/var/lib/docker/volumes/ on Linux). They support drivers for NFS, cloud storage (Cloudstor), and encryption. Bind mounts map a host directory directly into a container — useful for development hot-reloading but less portable.

Docker Compose for Multi-Container Applications

Docker Compose defines and runs multi-container applications with a single YAML file. Instead of running five docker run commands, you define all services, networks, and volumes in compose.yaml:

services:
  api:
    build: ./api
    ports:
      - "8000:8000"
    environment:
      - DATABASE_URL=postgresql://postgres:secret@db:5432/app
    depends_on:
      - db
      - redis
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
      interval: 30s

  web:
    build: ./web
    ports:
      - "3000:3000"
    depends_on:
      - api

  db:
    image: postgres:16-alpine
    volumes:
      - pgdata:/var/lib/postgresql/data
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: secret
      POSTGRES_DB: app

  redis:
    image: redis:7-alpine

volumes:
  pgdata:
docker compose up -d    # Start all services
docker compose logs -f  # Follow all logs
docker compose down -v  # Stop and remove volumes

Multi-Stage Builds

Multi-stage builds use multiple FROM statements to separate the build environment from the runtime environment, producing smaller, more secure final images:

# Stage 1: Build
FROM node:20-alpine AS builder
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
RUN npm run build

# Stage 2: Runtime
FROM nginx:alpine
COPY --from=builder /app/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

The final image contains only the Nginx runtime and the static files — no Node.js, no source code, no development dependencies. The image size drops from 1.2 GB (full Node + build tooling) to ~25 MB.

Container Registries

Container registries store and distribute images. Push images to a registry after building and pull them on deployment targets:

docker tag excellentwiki-api:latest registry.example.com/excellentwiki-api:v1.0.0
docker push registry.example.com/excellentwiki-api:v1.0.0

Popular registries include Docker Hub, AWS Elastic Container Registry (ECR), Google Artifact Registry, Azure Container Registry (ACR), and GitHub Container Registry (GHCR). Each integrates with its platform’s IAM for access control.

Docker Compose for Local Development

Docker Compose is the standard tool for local development environments with multiple services. It replicates the production architecture locally, eliminating “works on my machine” issues. Hot-reloading is achieved by mounting the source code directory as a bind mount — changes to the source are reflected immediately without rebuilding the image.

services:
  api:
    build:
      context: ./api
      dockerfile: Dockerfile.dev
    volumes:
      - ./api:/app  # Bind mount for hot-reload
    environment:
      - DATABASE_URL=postgresql://postgres:password@db:5432/app
      - REDIS_URL=redis://redis:6379/0
    ports:
      - "8000:8000"
    depends_on:
      db:
        condition: service_healthy
      redis:
        condition: service_started

  db:
    image: postgres:16-alpine
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 5s
    volumes:
      - pgdata:/var/lib/postgresql/data
      - ./db/init:/docker-entrypoint-initdb.d
    environment:
      POSTGRES_PASSWORD: password

  redis:
    image: redis:7-alpine

Use profiles to run different service combinations: docker compose --profile dev up for development with hot-reload, docker compose --profile ci up for testing with ephemeral databases, and docker compose --profile prod up for production-like local testing with optimized images.

Security Best Practices

  • Run as non-root — add USER appuser in the Dockerfile. The default root user inside containers is a common vulnerability.
  • Scan for vulnerabilitiesdocker scan (Snyk integration) checks images against CVE databases. Integrate scanning into CI/CD pipelines.
  • Minimize installed packages — use slim or Alpine base images. Each additional package is a potential attack vector.
  • Sign images — Docker Content Trust (DCT) ensures images are signed by trusted publishers.
  • Use secrets, not environment variablesdocker secret (Swarm) or --secret flag for build-time secrets. Environment variables leak to logs and debugging tools.

FAQ

What is the difference between a container and a VM? Containers share the host OS kernel and run as isolated processes. VMs include a full guest OS with its own kernel, requiring a hypervisor. Containers start in milliseconds and use less memory; VMs provide stronger isolation. You can run dozens of containers on a host that would only support a few VMs.

When should I use Docker Compose vs Kubernetes? Docker Compose is ideal for local development, testing, and single-host production deployments with few services. Kubernetes is needed for multi-host clusters, auto-scaling, rolling updates, service discovery, and complex orchestration. Many teams use Compose for development and Kubernetes for production.

How do I debug a container that crashes immediately? Override the CMD to keep the container running: docker run -it --entrypoint bash myimage. This gives you an interactive shell to inspect files, check logs, and run commands manually.

Why is my container image so large? Common causes: using a full base image (ubuntu:latest instead of ubuntu:22.04-slim), not cleaning up package manager caches (apt-get clean && rm -rf /var/lib/apt/lists/*), including dev dependencies in production builds, and not using multi-stage builds.

Can I run Docker containers on Windows? Yes. Docker Desktop for Windows runs containers using WSL 2 (Windows Subsystem for Linux) or Hyper-V isolation. Windows containers can run .NET Framework and native Windows applications. Most production deployments target Linux containers regardless of the host OS.

Kubernetes GuideCI/CD Pipeline GuideCloud-Native Development

Related Concepts and Further Reading

Understanding docker containers requires familiarity with several interconnected ideas and principles that together form a complete picture. Exploring these related concepts deepens your knowledge and provides context that makes the core material more meaningful and applicable. Each concept builds on the others, creating a web of understanding that supports deeper learning and practical application. Taking time to explore how these elements connect reveals patterns that accelerate comprehension and retention of new information.

The relationship between docker containers and adjacent fields is worth particular attention. Many of the most important insights emerge at the boundaries between disciplines, where ideas from different areas combine to create new approaches and solutions that neither field could produce alone. Exploring these connections pays dividends in both breadth and depth of understanding, revealing patterns and principles that might otherwise remain hidden from view. Cross-disciplinary knowledge is increasingly valued as problems become more complex and interconnected.

For those looking to go beyond introductory material, several excellent resources provide deeper treatment of specific aspects of docker containers. Academic journals, industry publications, authoritative reference works, and online courses each offer different perspectives and levels of detail. The key is to match your reading to your current learning goals and build knowledge progressively, focusing on quality over quantity in your study materials. A well-chosen resource that matches your current level is worth more than dozens of resources that are too basic or too advanced.

Section: Cloud Computing 1638 words 8 min read Beginner 756 articles in section Report inaccuracy Back to top