docker-containerization

Installation
SKILL.md

Docker Containerization

Build efficient, secure container images and compose multi-service architectures.

Multi-Stage Builds

Python Application

# Stage 1: Build
FROM python:3.12-slim AS builder
WORKDIR /app
COPY pyproject.toml .
RUN pip install --no-cache-dir --prefix=/install .

# Stage 2: Runtime
FROM python:3.12-slim
COPY --from=builder /install /usr/local
COPY src/ /app/src/
WORKDIR /app
USER nobody
EXPOSE 8000
CMD ["python", "-m", "uvicorn", "src.app:app", "--host", "0.0.0.0", "--port", "8000"]

Node.js Application

# Stage 1: Dependencies
FROM node:20-alpine AS deps
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev

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

# Stage 3: Runtime
FROM node:20-alpine
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY --from=builder /app/dist ./dist
USER node
EXPOSE 3000
CMD ["node", "dist/index.js"]

Image Optimization

Layer Ordering

Order instructions from least to most frequently changing:

FROM python:3.12-slim
# 1. System deps (rarely change)
RUN apt-get update && apt-get install -y --no-install-recommends \
    libpq-dev && rm -rf /var/lib/apt/lists/*
# 2. Python deps (change occasionally)
COPY pyproject.toml .
RUN pip install --no-cache-dir .
# 3. Application code (changes often)
COPY src/ ./src/

Size Reduction

Technique Savings
Alpine/slim base 50-80%
Multi-stage builds 40-70%
--no-cache-dir for pip 10-20%
.dockerignore Variable
Combine RUN layers 5-15%

.dockerignore

.git
.venv
__pycache__
*.pyc
node_modules
.env
*.md
tests/
docs/
.build/

Docker Compose

Multi-Service Architecture

services:
  api:
    build: .
    ports:
      - "8000:8000"
    environment:
      - DATABASE_URL=postgresql://user:pass@db:5432/app
      - REDIS_URL=redis://cache:6379
    depends_on:
      db:
        condition: service_healthy
      cache:
        condition: service_started
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
      interval: 30s
      timeout: 5s
      retries: 3

  db:
    image: postgres:16-alpine
    environment:
      POSTGRES_DB: app
      POSTGRES_USER: user
      POSTGRES_PASSWORD: pass
    volumes:
      - pgdata:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U user"]
      interval: 10s
      timeout: 5s
      retries: 5

  cache:
    image: redis:7-alpine
    command: redis-server --maxmemory 256mb --maxmemory-policy allkeys-lru

volumes:
  pgdata:

Development Overrides

# docker-compose.override.yml (auto-loaded in dev)
services:
  api:
    build:
      context: .
      target: builder
    volumes:
      - ./src:/app/src:ro
    command: ["python", "-m", "uvicorn", "src.app:app", "--reload", "--host", "0.0.0.0"]
    environment:
      - DEBUG=1

Health Checks

HEALTHCHECK --interval=30s --timeout=5s --retries=3 \
  CMD curl -f http://localhost:8000/health || exit 1
# Minimal health endpoint
@app.get("/health")
async def health():
    return {"status": "ok"}

Container Security

Non-Root Execution

# Create non-root user
RUN addgroup --system --gid 1001 appgroup && \
    adduser --system --uid 1001 appuser --ingroup appgroup
USER appuser

Read-Only Filesystem

services:
  api:
    read_only: true
    tmpfs:
      - /tmp
      - /app/cache

Secrets Management

services:
  api:
    secrets:
      - db_password
    environment:
      - DB_PASSWORD_FILE=/run/secrets/db_password

secrets:
  db_password:
    file: ./secrets/db_password.txt

Scanning

# Scan for vulnerabilities
docker scout cves myimage:latest
trivy image myimage:latest

Common Patterns

Wait for Dependencies

#!/usr/bin/env bash
set -euo pipefail

# wait-for-it pattern
until pg_isready -h "$DB_HOST" -p "$DB_PORT"; do
  echo "Waiting for database..."
  sleep 2
done

exec "$@"
COPY scripts/entrypoint.sh /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]
CMD ["python", "-m", "uvicorn", "src.app:app"]

Build Arguments

ARG PYTHON_VERSION=3.12
FROM python:${PYTHON_VERSION}-slim

ARG BUILD_DATE
ARG GIT_SHA
LABEL org.opencontainers.image.created="${BUILD_DATE}"
LABEL org.opencontainers.image.revision="${GIT_SHA}"
docker build \
  --build-arg BUILD_DATE=$(date -u +%Y-%m-%dT%H:%M:%SZ) \
  --build-arg GIT_SHA=$(git rev-parse HEAD) \
  -t myapp:latest .

Anti-Patterns

  • Running as root — Always use a non-root USER
  • Using latest tag in production — Pin specific versions
  • Storing secrets in images — Use runtime secrets or environment variables
  • One process per container violated — Keep containers single-purpose
  • No .dockerignore — Always exclude .git, node_modules, .venv, tests
  • Installing dev dependencies in prod image — Use multi-stage builds to separate
Related skills

More from 4444j99/a-i--skills

Installs
1
GitHub Stars
6
First Seen
Apr 19, 2026