# Docker Deployment This guide covers deploying Wizamart using Docker and Docker Compose. **Best for:** Teams who want consistent environments and easy rollbacks. --- ## Development vs Production | Aspect | Development | Production | |--------|-------------|------------| | Compose file | `docker-compose.yml` | `docker-compose.prod.yml` | | App server | Hot reload enabled | Multiple workers | | Database | Local volume | Persistent volume with backups | | SSL | Not needed | Required (via Nginx) | | Logging | Console | File + centralized | --- ## Development Setup ```bash # Start all services make docker-up # Or manually docker compose up -d # View logs docker compose logs -f # Stop services make docker-down ``` ### Current Services | Service | Port | Purpose | |---------|------|---------| | db | 5432 | PostgreSQL database | | redis | 6379 | Cache and queue broker | | api | 8000 | FastAPI application | --- ## Production Deployment ### 1. Create Production Compose File ```yaml # docker-compose.prod.yml services: api: build: context: . dockerfile: Dockerfile restart: always ports: - "127.0.0.1:8000:8000" environment: DATABASE_URL: postgresql://wizamart_user:${DB_PASSWORD}@db:5432/wizamart_db REDIS_URL: redis://redis:6379/0 CELERY_BROKER_URL: redis://redis:6379/1 env_file: - .env depends_on: db: condition: service_healthy redis: condition: service_healthy volumes: - uploads:/app/uploads - logs:/app/logs healthcheck: test: ["CMD", "curl", "-f", "http://localhost:8000/health"] interval: 30s timeout: 10s retries: 3 deploy: resources: limits: memory: 1G celery: build: . restart: always command: celery -A app.celery worker --loglevel=info --concurrency=4 environment: DATABASE_URL: postgresql://wizamart_user:${DB_PASSWORD}@db:5432/wizamart_db REDIS_URL: redis://redis:6379/0 CELERY_BROKER_URL: redis://redis:6379/1 env_file: - .env depends_on: - db - redis volumes: - logs:/app/logs deploy: resources: limits: memory: 512M celery-beat: build: . restart: always command: celery -A app.celery beat --loglevel=info environment: CELERY_BROKER_URL: redis://redis:6379/1 env_file: - .env depends_on: - redis deploy: resources: limits: memory: 256M db: image: postgres:15-alpine restart: always environment: POSTGRES_DB: wizamart_db POSTGRES_USER: wizamart_user POSTGRES_PASSWORD: ${DB_PASSWORD} volumes: - postgres_data:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U wizamart_user -d wizamart_db"] interval: 10s timeout: 5s retries: 5 deploy: resources: limits: memory: 512M redis: image: redis:7-alpine restart: always command: redis-server --appendonly yes --maxmemory 256mb --maxmemory-policy allkeys-lru volumes: - redis_data:/data healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 10s timeout: 5s retries: 5 deploy: resources: limits: memory: 300M nginx: image: nginx:alpine restart: always ports: - "80:80" - "443:443" volumes: - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro - ./nginx/conf.d:/etc/nginx/conf.d:ro - ./static:/app/static:ro - uploads:/app/uploads:ro - /etc/letsencrypt:/etc/letsencrypt:ro depends_on: - api deploy: resources: limits: memory: 128M volumes: postgres_data: redis_data: uploads: logs: ``` ### 2. Create Dockerfile ```dockerfile # Dockerfile FROM python:3.11-slim # Install system dependencies RUN apt-get update && apt-get install -y \ curl \ && rm -rf /var/lib/apt/lists/* # Install Tailwind CLI RUN curl -sLO https://github.com/tailwindlabs/tailwindcss/releases/latest/download/tailwindcss-linux-x64 \ && chmod +x tailwindcss-linux-x64 \ && mv tailwindcss-linux-x64 /usr/local/bin/tailwindcss WORKDIR /app # Install Python dependencies COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt # Copy application COPY . . # Build Tailwind CSS RUN tailwindcss -i ./static/admin/css/tailwind.css -o ./static/admin/css/tailwind.output.css --minify \ && tailwindcss -i ./static/vendor/css/tailwind.css -o ./static/vendor/css/tailwind.output.css --minify \ && tailwindcss -i ./static/shop/css/tailwind.css -o ./static/shop/css/tailwind.output.css --minify \ && tailwindcss -i ./static/platform/css/tailwind.css -o ./static/platform/css/tailwind.output.css --minify # Create non-root user RUN useradd -m -u 1000 wizamart && chown -R wizamart:wizamart /app USER wizamart EXPOSE 8000 CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000", "--workers", "4"] ``` ### 3. Nginx Configuration ```bash mkdir -p nginx/conf.d ``` ```nginx # nginx/conf.d/wizamart.conf upstream api { server api:8000; } server { listen 80; server_name yourdomain.com; return 301 https://$server_name$request_uri; } server { listen 443 ssl http2; server_name yourdomain.com; ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem; # Security headers add_header X-Frame-Options "SAMEORIGIN" always; add_header X-Content-Type-Options "nosniff" always; # Static files location /static { alias /app/static; expires 30d; add_header Cache-Control "public, immutable"; } location /uploads { alias /app/uploads; expires 7d; } location / { proxy_pass http://api; 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; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; } } ``` ### 4. Deploy ```bash # Create .env file with production values cp .env.example .env nano .env # Set database password export DB_PASSWORD=$(openssl rand -hex 16) echo "DB_PASSWORD=$DB_PASSWORD" >> .env # Build and start docker compose -f docker-compose.prod.yml build docker compose -f docker-compose.prod.yml up -d # Run migrations docker compose -f docker-compose.prod.yml exec api alembic upgrade head # Initialize data docker compose -f docker-compose.prod.yml exec api python scripts/init_production.py ``` --- ## Daily Operations ### View Logs ```bash # All services docker compose -f docker-compose.prod.yml logs -f # Specific service docker compose -f docker-compose.prod.yml logs -f api docker compose -f docker-compose.prod.yml logs -f celery # Last 100 lines docker compose -f docker-compose.prod.yml logs --tail 100 api ``` ### Access Container Shell ```bash # API container docker compose -f docker-compose.prod.yml exec api bash # Database docker compose -f docker-compose.prod.yml exec db psql -U wizamart_user -d wizamart_db # Redis docker compose -f docker-compose.prod.yml exec redis redis-cli ``` ### Restart Services ```bash # Single service docker compose -f docker-compose.prod.yml restart api # All services docker compose -f docker-compose.prod.yml restart ``` ### Deploy Updates ```bash # Pull latest code git pull origin main # Rebuild and restart docker compose -f docker-compose.prod.yml build api celery docker compose -f docker-compose.prod.yml up -d api celery # Run migrations if needed docker compose -f docker-compose.prod.yml exec api alembic upgrade head ``` ### Rollback ```bash # View image history docker images wizamart-api # Tag current as backup docker tag wizamart-api:latest wizamart-api:backup # Rollback to previous docker compose -f docker-compose.prod.yml down api docker tag wizamart-api:previous wizamart-api:latest docker compose -f docker-compose.prod.yml up -d api ``` --- ## Backups ### Database Backup ```bash # Create backup docker compose -f docker-compose.prod.yml exec db pg_dump -U wizamart_user wizamart_db | gzip > backup_$(date +%Y%m%d).sql.gz # Restore backup gunzip -c backup_20240115.sql.gz | docker compose -f docker-compose.prod.yml exec -T db psql -U wizamart_user -d wizamart_db ``` ### Volume Backup ```bash # Backup all volumes docker run --rm \ -v wizamart_postgres_data:/data \ -v $(pwd)/backups:/backup \ alpine tar czf /backup/postgres_$(date +%Y%m%d).tar.gz /data ``` --- ## Monitoring ### Resource Usage ```bash docker stats ``` ### Health Checks ```bash # Check service health docker compose -f docker-compose.prod.yml ps # Test API health curl -s http://localhost:8000/health | jq ``` --- ## Troubleshooting ### Container Won't Start ```bash # Check logs docker compose -f docker-compose.prod.yml logs api # Check container status docker compose -f docker-compose.prod.yml ps -a # Inspect container docker inspect ``` ### Database Connection Issues ```bash # Test from API container docker compose -f docker-compose.prod.yml exec api python -c " from app.core.database import engine with engine.connect() as conn: print('Connected!') " ``` ### Out of Disk Space ```bash # Check disk usage docker system df # Clean up docker system prune -a --volumes ``` ### Memory Issues ```bash # Check memory usage docker stats --no-stream # Increase limits in docker-compose.prod.yml deploy: resources: limits: memory: 2G ``` --- ## Security ### Non-Root User All containers run as non-root users. The Dockerfile creates a `wizamart` user. ### Secret Management ```bash # Use Docker secrets (Swarm mode) echo "your-password" | docker secret create db_password - # Or use environment files # Never commit .env to git ``` ### Network Isolation ```yaml # Add to docker-compose.prod.yml networks: frontend: backend: services: nginx: networks: - frontend api: networks: - frontend - backend db: networks: - backend redis: networks: - backend ``` --- ## Scaling ### Horizontal Scaling ```bash # Scale API containers docker compose -f docker-compose.prod.yml up -d --scale api=3 # Update nginx upstream upstream api { server api_1:8000; server api_2:8000; server api_3:8000; } ``` ### Moving to Kubernetes When you outgrow Docker Compose, see our Kubernetes migration guide (coming soon).