--- version: "1.0" date: "2025-01-15" author: "DWS Foldsite Team" title: "Docker Deployment" description: "Running Foldsite in Docker containers" summary: "Complete guide to deploying Foldsite with Docker for consistent, isolated, and portable deployments." quick_tips: - "Docker ensures consistent environments across development and production" - "Use docker-compose for easy multi-container setup" - "Mount content as volumes for live updates without rebuilding" --- # Docker Deployment Docker provides isolated, reproducible deployments of Foldsite. Perfect for testing, staging, and production environments. ## Why Docker? **Benefits:** - **Consistency** - Same environment everywhere - **Isolation** - Dependencies don't conflict with system - **Portability** - Run anywhere Docker runs - **Easy deployment** - Single command to start - **Version control** - Docker images are versioned **Use cases:** - Team development (everyone has same environment) - Staging environments before production - Production deployments - CI/CD pipelines - Cloud platform deployments ## Prerequisites ### Install Docker **macOS:** ```bash # Download Docker Desktop from docker.com # Or use Homebrew brew install --cask docker ``` **Linux (Ubuntu/Debian):** ```bash # Update package index sudo apt update # Install Docker sudo apt install docker.io docker-compose # Add your user to docker group sudo usermod -aG docker $USER # Log out and back in for group changes ``` **Windows:** ```bash # Download Docker Desktop from docker.com # Requires WSL2 ``` **Verify installation:** ```bash docker --version docker-compose --version ``` ## Quick Start with Docker Compose ### Step 1: Create docker-compose.yml In your Foldsite directory: ```yaml version: '3.8' services: foldsite: image: python:3.11-slim container_name: foldsite working_dir: /app command: > sh -c "pip install -r requirements.txt && python main.py --config config.toml" ports: - "8081:8081" volumes: - .:/app - ./my-site/content:/app/content - ./my-site/templates:/app/templates - ./my-site/styles:/app/styles environment: - PYTHONUNBUFFERED=1 restart: unless-stopped ``` ### Step 2: Create config.toml for Docker ```toml [paths] content_dir = "/app/content" templates_dir = "/app/templates" styles_dir = "/app/styles" [server] listen_address = "0.0.0.0" # Important: bind to all interfaces listen_port = 8081 admin_browser = false max_threads = 4 debug = false access_log = true ``` ### Step 3: Start Container ```bash # Start in background docker-compose up -d # View logs docker-compose logs -f # Stop docker-compose down ``` Visit `http://localhost:8081` to see your site! ## Building a Custom Docker Image For production, build a dedicated Foldsite image: ### Create Dockerfile ```dockerfile # Dockerfile FROM python:3.11-slim # Set working directory WORKDIR /app # Install system dependencies RUN apt-get update && apt-get install -y \ build-essential \ && rm -rf /var/lib/apt/lists/* # Copy requirements first (for caching) COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt # Copy application code COPY . . # Create directories for content RUN mkdir -p /content /templates /styles # Expose port EXPOSE 8081 # Run application CMD ["python", "main.py", "--config", "/app/config.toml"] ``` ### Build Image ```bash # Build image docker build -t foldsite:latest . # Tag for versioning docker tag foldsite:latest foldsite:1.0.0 ``` ### Run Container ```bash docker run -d \ --name foldsite \ -p 8081:8081 \ -v $(pwd)/my-site/content:/content \ -v $(pwd)/my-site/templates:/templates \ -v $(pwd)/my-site/styles:/styles \ foldsite:latest ``` ## Development with Docker ### Hot Reload Setup Mount your code as volumes for live updates: ```yaml # docker-compose.dev.yml version: '3.8' services: foldsite: build: . container_name: foldsite-dev ports: - "8081:8081" volumes: # Mount everything for development - .:/app - ./my-site/content:/app/content - ./my-site/templates:/app/templates - ./my-site/styles:/app/styles environment: - PYTHONUNBUFFERED=1 - FLASK_ENV=development command: > sh -c "pip install -r requirements.txt && python main.py --config config.toml" ``` **Usage:** ```bash # Start development environment docker-compose -f docker-compose.dev.yml up # Changes to content, templates, and styles appear immediately # Code changes require restart ``` ### Interactive Development Run commands inside container: ```bash # Start bash session in running container docker exec -it foldsite bash # Inside container, you can: python main.py --config config.toml pip install new-package ls /app/content ``` ## Production Docker Setup ### Multi-Stage Build Optimize image size with multi-stage build: ```dockerfile # Dockerfile.production # Stage 1: Build dependencies FROM python:3.11-slim as builder WORKDIR /app # Install build dependencies RUN apt-get update && apt-get install -y \ build-essential \ && rm -rf /var/lib/apt/lists/* # Install Python dependencies COPY requirements.txt . RUN pip install --user --no-cache-dir -r requirements.txt # Stage 2: Runtime FROM python:3.11-slim WORKDIR /app # Copy Python dependencies from builder COPY --from=builder /root/.local /root/.local # Copy application COPY . . # Create non-root user RUN useradd -m -u 1000 foldsite && \ chown -R foldsite:foldsite /app # Switch to non-root user USER foldsite # Make sure scripts in .local are usable ENV PATH=/root/.local/bin:$PATH EXPOSE 8081 # Use Gunicorn for production CMD ["gunicorn", "-w", "4", "-b", "0.0.0.0:8081", "main:app"] ``` ### Production docker-compose.yml ```yaml version: '3.8' services: foldsite: build: context: . dockerfile: Dockerfile.production container_name: foldsite-prod ports: - "8081:8081" volumes: - ./content:/app/content:ro # Read-only - ./templates:/app/templates:ro - ./styles:/app/styles:ro environment: - PYTHONUNBUFFERED=1 restart: always logging: driver: "json-file" options: max-size: "10m" max-file: "3" healthcheck: test: ["CMD", "curl", "-f", "http://localhost:8081/"] interval: 30s timeout: 10s retries: 3 ``` ## Docker Compose Examples ### With Nginx Reverse Proxy ```yaml version: '3.8' services: foldsite: build: . container_name: foldsite expose: - "8081" volumes: - ./content:/app/content:ro - ./templates:/app/templates:ro - ./styles:/app/styles:ro restart: always nginx: image: nginx:alpine container_name: nginx ports: - "80:80" - "443:443" volumes: - ./nginx.conf:/etc/nginx/nginx.conf:ro - ./ssl:/etc/nginx/ssl:ro depends_on: - foldsite restart: always ``` **nginx.conf:** ```nginx events { worker_connections 1024; } http { upstream foldsite { server foldsite:8081; } server { listen 80; server_name your-domain.com; location / { proxy_pass http://foldsite; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } # Cache static assets location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ { proxy_pass http://foldsite; expires 30d; add_header Cache-Control "public, immutable"; } } } ``` ### Multiple Sites Run multiple Foldsite instances: ```yaml version: '3.8' services: blog: build: . ports: - "8081:8081" volumes: - ./blog/content:/app/content - ./blog/templates:/app/templates - ./blog/styles:/app/styles restart: always portfolio: build: . ports: - "8082:8081" volumes: - ./portfolio/content:/app/content - ./portfolio/templates:/app/templates - ./portfolio/styles:/app/styles restart: always ``` ## Volume Management ### Content Volumes **Development** - Mount host directories: ```yaml volumes: - ./my-site/content:/app/content - ./my-site/templates:/app/templates - ./my-site/styles:/app/styles ``` **Production** - Read-only mounts: ```yaml volumes: - ./content:/app/content:ro - ./templates:/app/templates:ro - ./styles:/app/styles:ro ``` ### Named Volumes For persistent data: ```yaml services: foldsite: volumes: - content-data:/app/content - templates-data:/app/templates volumes: content-data: templates-data: ``` **Backup named volumes:** ```bash # Backup docker run --rm \ -v foldsite_content-data:/data \ -v $(pwd):/backup \ alpine tar czf /backup/content-backup.tar.gz -C /data . # Restore docker run --rm \ -v foldsite_content-data:/data \ -v $(pwd):/backup \ alpine tar xzf /backup/content-backup.tar.gz -C /data ``` ## Environment Variables Pass configuration via environment: ```yaml services: foldsite: environment: - FOLDSITE_DEBUG=false - FOLDSITE_PORT=8081 - FOLDSITE_MAX_THREADS=4 ``` **Use in config:** ```python # In a config loader import os debug = os.getenv('FOLDSITE_DEBUG', 'false').lower() == 'true' port = int(os.getenv('FOLDSITE_PORT', '8081')) ``` ## Common Docker Commands ### Container Management ```bash # Start containers docker-compose up -d # Stop containers docker-compose down # Restart docker-compose restart # View logs docker-compose logs -f # View logs for specific service docker-compose logs -f foldsite # Exec into running container docker exec -it foldsite bash # View running containers docker ps # View all containers (including stopped) docker ps -a ``` ### Image Management ```bash # Build image docker-compose build # Pull images docker-compose pull # List images docker images # Remove unused images docker image prune # Remove all unused data docker system prune -a ``` ### Debugging ```bash # Check container logs docker logs foldsite # Follow logs docker logs -f foldsite # Inspect container docker inspect foldsite # View container stats docker stats foldsite # Check container health docker ps --filter health=healthy ``` ## Troubleshooting ### Port Already in Use ``` Error: port is already allocated ``` **Solution:** Change port mapping: ```yaml ports: - "8082:8081" # Map to different host port ``` ### Permission Errors ``` PermissionError: [Errno 13] Permission denied ``` **Solution:** Fix volume permissions: ```bash # Fix ownership sudo chown -R $USER:$USER ./my-site # Or run container as your user docker run --user $(id -u):$(id -g) ... ``` ### Container Won't Start ```bash # Check logs docker-compose logs # Common issues: # 1. Missing requirements.txt # 2. Wrong working directory # 3. Port conflicts # 4. Volume mount errors ``` ### Changes Not Appearing **Content changes:** - Should appear immediately (volumes mounted) - Try hard refresh in browser **Code changes:** - Require container restart: `docker-compose restart` **Template changes:** - Should appear immediately - Check volume mounts are correct ### Container Crashes ```bash # View exit reason docker ps -a # Check logs docker logs foldsite # Try running interactively docker run -it foldsite bash ``` ## Performance Optimization ### Resource Limits Limit container resources: ```yaml services: foldsite: deploy: resources: limits: cpus: '2.0' memory: 1G reservations: cpus: '0.5' memory: 512M ``` ### Build Cache Speed up builds: ```bash # Use BuildKit DOCKER_BUILDKIT=1 docker build . # Cache from registry docker build --cache-from myregistry/foldsite:latest . ``` ### Layer Optimization Order Dockerfile for better caching: ```dockerfile # Dependencies first (change rarely) COPY requirements.txt . RUN pip install -r requirements.txt # Code last (changes often) COPY . . ``` ## CI/CD Integration ### GitHub Actions Example ```yaml # .github/workflows/docker.yml name: Build Docker Image on: push: branches: [main] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Build image run: docker build -t foldsite:${{ github.sha }} . - name: Test run: | docker run -d --name test foldsite:${{ github.sha }} docker logs test docker stop test ``` ## Cloud Platform Deployment ### Deploy to AWS ECS ```bash # Build and push to ECR aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin 123456789.dkr.ecr.us-east-1.amazonaws.com docker tag foldsite:latest 123456789.dkr.ecr.us-east-1.amazonaws.com/foldsite:latest docker push 123456789.dkr.ecr.us-east-1.amazonaws.com/foldsite:latest ``` ### Deploy to Google Cloud Run ```bash # Build and push to GCR gcloud builds submit --tag gcr.io/PROJECT_ID/foldsite gcloud run deploy --image gcr.io/PROJECT_ID/foldsite --platform managed ``` ### Deploy to Azure Container Instances ```bash # Create container instance az container create \ --resource-group myResourceGroup \ --name foldsite \ --image myregistry.azurecr.io/foldsite:latest \ --ports 8081 ``` ## Next Steps - **[Production Deployment](production.md)** - Production-grade setup - **[Local Development](local-development.md)** - Development workflow - **[Support](../support.md)** - Get help Docker provides a solid foundation for deploying Foldsite anywhere. From development to production, containers ensure consistency and reliability.