DeveloperBootstrap

Containerization

Docker Containerization Complete Guide

Master Docker containerization from fundamentals to production deployment with multi-stage builds, container orchestration, security best practices, monitoring, and CI/CD integration on Ubuntu 24.04 LTS.

What you'll learn

  • Install and configure Docker CE on Ubuntu 24.04 LTS
  • Write optimized Dockerfiles with multi-stage builds
  • Orchestrate multi-container apps with Docker Compose
  • Implement container security best practices
  • Set up monitoring and observability for containers
  • Integrate Docker into CI/CD pipelines
  • Deploy containers to production environments

Installation & Setup

Install Docker CE on Ubuntu 24.04 LTS using the official Docker repository for the latest stable release with full production support.

Bash
1# Remove old Docker installations
2sudo apt remove -y docker docker-engine docker.io containerd runc
3
4# Install prerequisites
5sudo apt update && sudo apt install -y ca-certificates curl gnupg
6
7# Add Docker's official GPG key
8sudo install -m 0755 -d /etc/apt/keyrings
9curl -fsSL https://download.docker.com/linux/ubuntu/gpg | \
10  sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
11sudo chmod a+r /etc/apt/keyrings/docker.gpg
12
13# Add the Docker repository
14echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
15  https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
16  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
17
18# Install Docker Engine
19sudo apt update
20sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
21
22# Add current user to the docker group
23sudo usermod -aG docker $USER
24newgrp docker
25
26# Verify installation
27docker --version
28docker compose version

Docker Fundamentals

Understand the core concepts: images, containers, volumes, and networks.

Bash
1# Pull and run a container
2docker pull nginx:alpine
3docker run -d -p 8080:80 --name my-nginx nginx:alpine
4
5# List running containers
6docker ps
7
8# View logs
9docker logs my-nginx
10
11# Execute a command inside a container
12docker exec -it my-nginx sh
13
14# Stop and remove
15docker stop my-nginx && docker rm my-nginx
16
17# Manage volumes
18docker volume create my-data
19docker run -v my-data:/data alpine sh
20
21# Inspect networks
22docker network ls
23docker network inspect bridge

Dockerfile Optimization

Write efficient Dockerfiles that produce small, secure, cache-friendly images.

DOCKERFILE
1# Optimized Node.js Dockerfile
2FROM node:20-alpine AS base
3WORKDIR /app
4
5# Install dependencies separately for better cache
6FROM base AS deps
7COPY package*.json ./
8RUN npm ci --only=production
9
10FROM base AS build
11COPY package*.json ./
12RUN npm ci
13COPY . .
14RUN npm run build
15
16# Production image — minimal footprint
17FROM base AS runner
18ENV NODE_ENV=production
19RUN addgroup -S appgroup && adduser -S appuser -G appgroup
20COPY --from=deps /app/node_modules ./node_modules
21COPY --from=build /app/dist ./dist
22USER appuser
23EXPOSE 3000
24CMD ["node", "dist/main.js"]

Multi-Stage Builds

Multi-stage builds eliminate build-time dependencies from production images, dramatically reducing image size and attack surface.

Best practice: Always use a minimal base image (alpine, distroless) for your final production stage. A typical Node.js app shrinks from ~1 GB to under 100 MB.

Docker Compose

Define and run multi-container applications with a single compose.yml file.

YAML
1# compose.yml
2services:
3  api:
4    build: ./api
5    ports:
6      - "3000:3000"
7    environment:
8      DATABASE_URL: postgres://user:pass@db:5432/mydb
9    depends_on:
10      db:
11        condition: service_healthy
12
13  db:
14    image: postgres:16-alpine
15    volumes:
16      - pg-data:/var/lib/postgresql/data
17    environment:
18      POSTGRES_USER: user
19      POSTGRES_PASSWORD: pass
20      POSTGRES_DB: mydb
21    healthcheck:
22      test: ["CMD-SHELL", "pg_isready -U user"]
23      interval: 10s
24      timeout: 5s
25      retries: 5
26
27  redis:
28    image: valkey/valkey:8-alpine
29    volumes:
30      - redis-data:/data
31
32volumes:
33  pg-data:
34  redis-data:

Container Security

  • Run containers as a non-root user (USER appuser)
  • Use read-only root filesystems (--read-only)
  • Drop all Linux capabilities and add only what is needed
  • Scan images with docker scout cves
  • Pin base image digests, not just tags
  • Never bake secrets into images — use Docker secrets or environment variables at runtime

Monitoring & Observability

Export container metrics to Prometheus and visualize in Grafana.

YAML
1# Add cadvisor to your compose stack
2cadvisor:
3  image: gcr.io/cadvisor/cadvisor:latest
4  volumes:
5    - /:/rootfs:ro
6    - /var/run:/var/run:ro
7    - /sys:/sys:ro
8    - /var/lib/docker/:/var/lib/docker:ro
9  ports:
10    - "8080:8080"
11  restart: unless-stopped

CI/CD Integration

Build, test, scan, and push Docker images automatically with GitHub Actions.

YAML
1# .github/workflows/docker.yml
2- name: Build and push
3  uses: docker/build-push-action@v5
4  with:
5    context: .
6    platforms: linux/amd64,linux/arm64
7    push: true
8    tags: ghcr.io/org/app:latest
9    cache-from: type=gha
10    cache-to: type=gha,mode=max

Production Deployment

  • Use restart policies: restart: unless-stopped
  • Set CPU and memory limits on every service
  • Use Docker Swarm or Kubernetes for multi-node deployments
  • Store persistent data in named volumes, not bind mounts
  • Enable Docker daemon TLS for remote access