Skip to main content

braindump & snippets

braindump & snippets

Anatomy of a Docker Compose File

Docker Compose uses YAML to define multi-container applications.

Basic Structure

version: '3.8'  # Compose file format version

services:       # Define your containers
  web:
    # Service definition
  database:
    # Another service

volumes:        # Named volumes (optional)
  data:

networks:       # Custom networks (optional)
  app-network:

Service Configuration Options

Image vs Build

services:
  web:
    # Use existing image
    image: nginx:alpine
    
  app:
    # Build from Dockerfile
    build:
      context: .
      dockerfile: Dockerfile.dev
      args:
        NODE_ENV: development

Ports and Networking

services:
  web:
    ports:
      - "3000:3000"    # host:container
      - "80:8080"
    expose:
      - "3000"         # Only to other containers

Environment Variables

services:
  app:
    environment:
      NODE_ENV: production
      DATABASE_URL: postgresql://db:5432/myapp
    env_file:
      - .env           # Load from file
      - .env.local

Volumes and Persistence

services:
  database:
    volumes:
      - db_data:/var/lib/postgresql/data  # Named volume
      - ./config:/etc/config:ro           # Bind mount (read-only)
      - /tmp                              # Anonymous volume
      
volumes:
  db_data:  # Define named volume

Dependencies

services:
  web:
    depends_on:
      - database
      - redis
    restart: unless-stopped

Complete Example - Full Stack App

version: '3.8'

services:
  frontend:
    build:
      context: ./frontend
      dockerfile: Dockerfile.dev
    ports:
      - "3000:3000"
    volumes:
      - ./frontend/src:/app/src
      - /app/node_modules
    environment:
      - REACT_APP_API_URL=http://localhost:4000
    depends_on:
      - backend

  backend:
    build:
      context: ./backend
      dockerfile: Dockerfile
    ports:
      - "4000:4000"
    environment:
      - NODE_ENV=development
      - DATABASE_URL=postgresql://postgres:password@database:5432/myapp
      - REDIS_URL=redis://redis:6379
    volumes:
      - ./backend:/app
      - /app/node_modules
    depends_on:
      - database
      - redis

  database:
    image: postgres:15-alpine
    environment:
      POSTGRES_DB: myapp
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: password
    volumes:
      - postgres_data:/var/lib/postgresql/data
      - ./init.sql:/docker-entrypoint-initdb.d/init.sql
    ports:
      - "5432:5432"

  redis:
    image: redis:7-alpine
    ports:
      - "6379:6379"
    volumes:
      - redis_data:/data

  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
    depends_on:
      - frontend
      - backend

volumes:
  postgres_data:
  redis_data:

networks:
  default:
    name: myapp-network

Demo Commands & Snippets

Container Crafting by Hand Demo

1. Basic chroot Demo

2. Namespaces Demo

3. cgroups Demo

Docker Build & Run Demos

Building Images

# Build with tag
docker build -t myapp:v1.0 .

# Build with build args
docker build --build-arg NODE_ENV=production -t myapp:prod .

# Build specific stage
docker build --target builder -t myapp:builder .

# See build layers
docker history myapp:v1.0

Running Containers

# Basic run
docker run -d -p 3000:3000 --name myapp myapp:v1.0

# Run with environment variables
docker run -d -p 3000:3000 -e NODE_ENV=production myapp:v1.0

# Run with volume
docker run -d -p 3000:3000 -v $(pwd)/data:/app/data myapp:v1.0

# Run interactively
docker run -it --rm myapp:v1.0 /bin/bash

# Run with resource limits
docker run -d --memory=512m --cpus=0.5 myapp:v1.0

Docker Compose Demos

# Start all services
docker-compose up -d

# Build and start
docker-compose up --build

# View logs
docker-compose logs -f web

# Scale a service
docker-compose up -d --scale web=3

# Stop and remove
docker-compose down

# Stop and remove with volumes
docker-compose down -v

Slim Container Techniques

Multi-stage Build Benefits

# Bad - Large image with build tools
FROM node:18
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
CMD ["npm", "start"]

# Good - Small production image
FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

FROM node:18-alpine AS production
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
COPY package.json ./
USER 1000
CMD ["npm", "start"]

Size Comparison Commands

# Compare image sizes
docker images | grep myapp

# Dive into image layers
docker run --rm -it \
  -v /var/run/docker.sock:/var/run/docker.sock \
  wagoodman/dive myapp:v1.0

# Inspect image
docker inspect myapp:v1.0

Security Best Practices Demo

# Scan for vulnerabilities
docker scout quickview myapp:v1.0

# Run as non-root user
docker run --user 1000:1000 myapp:v1.0

# Read-only filesystem
docker run --read-only myapp:v1.0

# Drop capabilities
docker run --cap-drop=ALL --cap-add=NET_BIND_SERVICE myapp:v1.0

This extended content should give you plenty of material for demos and explanations. The hands-on examples will really help your audience understand the concepts!

Quick find

Search the garden