Skip to main content
โšก Calmops

Docker and Containerization: Deploying Python Applications

Docker and Containerization: Deploying Python Applications

Docker enables packaging Python applications with all dependencies into containers, ensuring consistency across development, testing, and production environments.

Docker Fundamentals

Installation

# Install Docker
# macOS: brew install docker
# Ubuntu: sudo apt-get install docker.io
# Windows: Download Docker Desktop

# Verify installation
docker --version
docker run hello-world

Basic Concepts

  • Image: Blueprint for containers (like a class)
  • Container: Running instance of an image (like an object)
  • Dockerfile: Instructions to build an image
  • Registry: Repository for storing images (Docker Hub, etc.)

Creating Docker Images

Simple Dockerfile

# Use official Python runtime as base image
FROM python:3.11-slim

# Set working directory
WORKDIR /app

# Copy requirements
COPY requirements.txt .

# Install dependencies
RUN pip install --no-cache-dir -r requirements.txt

# Copy application code
COPY . .

# Expose port
EXPOSE 8000

# Set environment variables
ENV PYTHONUNBUFFERED=1

# Run application
CMD ["python", "app.py"]

Multi-stage Dockerfile

# Build stage
FROM python:3.11 as builder

WORKDIR /app
COPY requirements.txt .
RUN pip install --user --no-cache-dir -r requirements.txt

# Runtime stage
FROM python:3.11-slim

WORKDIR /app

# Copy only necessary files from builder
COPY --from=builder /root/.local /root/.local
COPY . .

ENV PATH=/root/.local/bin:$PATH
ENV PYTHONUNBUFFERED=1

EXPOSE 8000
CMD ["python", "app.py"]

Dockerfile for Flask Application

FROM python:3.11-slim

WORKDIR /app

# Install system dependencies
RUN apt-get update && apt-get install -y \
    gcc \
    && rm -rf /var/lib/apt/lists/*

# Copy and install Python dependencies
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# Copy application
COPY . .

# Create non-root user
RUN useradd -m appuser && chown -R appuser:appuser /app
USER appuser

EXPOSE 5000

# Health check
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
    CMD python -c "import requests; requests.get('http://localhost:5000/health')"

CMD ["gunicorn", "--bind", "0.0.0.0:5000", "--workers", "4", "app:app"]

requirements.txt

Flask==2.3.0
requests==2.31.0
python-dotenv==1.0.0
gunicorn==21.0.0

Building and Running Containers

Build Image

# Build image
docker build -t my-python-app:1.0 .

# Build with build arguments
docker build -t my-app:latest --build-arg PYTHON_VERSION=3.11 .

# List images
docker images

# Remove image
docker rmi my-python-app:1.0

Run Container

# Run container
docker run -d --name my-container my-python-app:1.0

# Run with port mapping
docker run -d -p 8000:8000 --name my-app my-python-app:1.0

# Run with environment variables
docker run -d -e DATABASE_URL=postgres://... my-python-app:1.0

# Run with volume mount
docker run -d -v /host/path:/container/path my-python-app:1.0

# Run with resource limits
docker run -d --memory=512m --cpus=1 my-python-app:1.0

# Run interactively
docker run -it my-python-app:1.0 /bin/bash

# List running containers
docker ps

# Stop container
docker stop my-container

# Remove container
docker rm my-container

Docker Compose

docker-compose.yml

version: '3.8'

services:
  web:
    build: .
    ports:
      - "8000:8000"
    environment:
      - DATABASE_URL=postgresql://user:password@db:5432/mydb
      - REDIS_URL=redis://redis:6379
    depends_on:
      - db
      - redis
    volumes:
      - .:/app
    command: python app.py

  db:
    image: postgres:15
    environment:
      - POSTGRES_USER=user
      - POSTGRES_PASSWORD=password
      - POSTGRES_DB=mydb
    volumes:
      - postgres_data:/var/lib/postgresql/data
    ports:
      - "5432:5432"

  redis:
    image: redis:7-alpine
    ports:
      - "6379:6379"

  celery:
    build: .
    command: celery -A tasks worker --loglevel=info
    environment:
      - DATABASE_URL=postgresql://user:password@db:5432/mydb
      - REDIS_URL=redis://redis:6379
    depends_on:
      - db
      - redis

volumes:
  postgres_data:

Docker Compose Commands

# Start services
docker-compose up

# Start in background
docker-compose up -d

# Stop services
docker-compose down

# View logs
docker-compose logs -f web

# Execute command in service
docker-compose exec web python manage.py migrate

# Rebuild images
docker-compose build

# Scale service
docker-compose up -d --scale celery=3

Best Practices

Optimize Image Size

# Bad: Large image
FROM python:3.11
RUN apt-get update && apt-get install -y build-essential
COPY requirements.txt .
RUN pip install -r requirements.txt

# Good: Smaller image
FROM python:3.11-slim
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

Security

# Create non-root user
RUN useradd -m -u 1000 appuser
USER appuser

# Use specific versions
FROM python:3.11.0-slim

# Don't run as root
# Don't include secrets in image
# Use .dockerignore to exclude unnecessary files

.dockerignore

__pycache__
*.pyc
*.pyo
*.pyd
.Python
env/
venv/
.git
.gitignore
.dockerignore
.env
.env.local
*.log
.pytest_cache
.coverage
dist/
build/
*.egg-info/

Debugging Containers

# View container logs
docker logs my-container
docker logs -f my-container  # Follow logs

# Inspect container
docker inspect my-container

# Execute command in running container
docker exec -it my-container /bin/bash

# View resource usage
docker stats

# View processes in container
docker top my-container

# Copy files from container
docker cp my-container:/app/file.txt ./file.txt

Registry and Deployment

Push to Docker Hub

# Login to Docker Hub
docker login

# Tag image
docker tag my-python-app:1.0 username/my-python-app:1.0

# Push image
docker push username/my-python-app:1.0

# Pull image
docker pull username/my-python-app:1.0

Private Registry

# Tag for private registry
docker tag my-app:1.0 registry.example.com/my-app:1.0

# Push to private registry
docker push registry.example.com/my-app:1.0

# Pull from private registry
docker pull registry.example.com/my-app:1.0

Common Pitfalls

Bad Practice:

# Don't: Large base image
FROM python:3.11

# Don't: Cache pip packages
RUN pip install -r requirements.txt

# Don't: Run as root
# (no USER directive)

# Don't: Copy entire directory
COPY . .

Good Practice:

# Do: Use slim image
FROM python:3.11-slim

# Do: Don't cache pip
RUN pip install --no-cache-dir -r requirements.txt

# Do: Run as non-root
RUN useradd -m appuser
USER appuser

# Do: Use .dockerignore
COPY app/ /app/

Conclusion

Docker enables consistent, reproducible deployments of Python applications. Master Dockerfile creation, Docker Compose for multi-container applications, and best practices for security and efficiency. Containerization is essential for modern application deployment.

Comments