We use cookies to enhance your experience on the site
CodeWorlds

Docker - Containerization

Docker lets you package an application with all its dependencies into a container that runs identically everywhere!

Core Concepts

  • Image - a template/recipe for a container (like a class in OOP)
  • Container - a running instance of an image (like an object)
  • Dockerfile - instructions for building an image
  • Registry - image repository (Docker Hub, ECR, GCR)

Dockerfile for Python

1# Base image with Python
2FROM python:3.11-slim
3
4# Environment variables
5ENV PYTHONDONTWRITEBYTECODE=1
6ENV PYTHONUNBUFFERED=1
7
8# Working directory
9WORKDIR /app
10
11# Copy requirements and install dependencies
12COPY requirements.txt .
13RUN pip install --no-cache-dir -r requirements.txt
14
15# Copy application code
16COPY . .
17
18# Application port
19EXPOSE 8000
20
21# Run command
22CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]

Multi-stage Build - Smaller Image

1# Stage 1: Builder
2FROM python:3.11-slim as builder
3
4WORKDIR /app
5COPY requirements.txt .
6RUN pip wheel --no-cache-dir --no-deps --wheel-dir /app/wheels -r requirements.txt
7
8# Stage 2: Production
9FROM python:3.11-slim
10
11WORKDIR /app
12
13# Copy wheels from builder
14COPY --from=builder /app/wheels /wheels
15RUN pip install --no-cache /wheels/*
16
17# Copy only necessary code
18COPY src/ ./src/
19COPY main.py .
20
21# Non-root user for security
22RUN useradd -m appuser
23USER appuser
24
25EXPOSE 8000
26CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]

Basic Docker Commands

1# Build image
2docker build -t safari-api:latest .
3
4# Run container
5docker run -p 8000:8000 safari-api:latest
6
7# Run in background
8docker run -d -p 8000:8000 --name safari safari-api:latest
9
10# List containers
11docker ps        # running
12docker ps -a     # all
13
14# Logs
15docker logs safari
16docker logs -f safari  # follow
17
18# Stop/remove
19docker stop safari
20docker rm safari
21
22# Enter container
23docker exec -it safari /bin/bash

docker-compose - Multiple Containers

1# docker-compose.yml
2version: '3.8'
3
4services:
5  api:
6    build: .
7    ports:
8      - "8000:8000"
9    environment:
10      - DATABASE_URL=postgresql://user:pass@db:5432/safari
11      - REDIS_URL=redis://cache:6379
12    depends_on:
13      - db
14      - cache
15    volumes:
16      - ./src:/app/src  # Hot reload for development
17
18  db:
19    image: postgres:15
20    environment:
21      POSTGRES_USER: user
22      POSTGRES_PASSWORD: pass
23      POSTGRES_DB: safari
24    volumes:
25      - postgres_data:/var/lib/postgresql/data
26    ports:
27      - "5432:5432"
28
29  cache:
30    image: redis:7-alpine
31    ports:
32      - "6379:6379"
33
34volumes:
35  postgres_data:

docker-compose Commands

1# Start all services
2docker-compose up
3
4# In background
5docker-compose up -d
6
7# Rebuild images
8docker-compose up --build
9
10# Stop
11docker-compose down
12
13# Stop and remove volumes
14docker-compose down -v
15
16# Logs for a specific service
17docker-compose logs api
18
19# Execute a command in a service
20docker-compose exec api pytest

Best Practices

  1. Use .dockerignore
1# .dockerignore
2__pycache__/
3*.pyc
4.git/
5.env
6.venv/
7tests/
8*.md
  1. One process per container
  2. Small images (slim, alpine)
  3. Don't store secrets in the image
  4. Use health checks
1HEALTHCHECK --interval=30s --timeout=3s \
2    CMD curl -f http://localhost:8000/health || exit 1
Go to CodeWorlds