# Docker Deployment Guide Complete guide for deploying ZynkTime with Docker. ## Quick Start ### 1. Basic Setup ```bash # Clone and navigate to project cd zynktime # Create environment file cp .env.example .env # Edit with your API key nano .env # Start the application docker-compose up -d # Access at http://localhost:8000 ``` ### 2. Verify Deployment ```bash # Check container status docker-compose ps # View logs docker-compose logs -f # Test health endpoint curl http://localhost:8000/health ``` ## Configuration ### Environment Variables Edit `.env` file: ```env # Required KLEER_API_KEY=your_actual_api_key_here # Optional (with defaults) KLEER_USERNAME=Christopher Juhlin KLEER_COMPANY_ID=1336 ``` ### Docker Compose Options **Development Mode** (with live reload): ```yaml services: zynktime: build: . volumes: - ./static:/app/static:ro - ./:/app:ro # Mount source code environment: - RELOAD=true ``` **Production Mode** (optimized): ```yaml services: zynktime: image: zynktime:1.0.0 restart: always read_only: true security_opt: - no-new-privileges:true cap_drop: - ALL ``` ## Common Operations ### Starting and Stopping ```bash # Start in background docker-compose up -d # Start in foreground (see logs) docker-compose up # Stop containers docker-compose down # Stop and remove volumes docker-compose down -v ``` ### Viewing Logs ```bash # Follow all logs docker-compose logs -f # Last 100 lines docker-compose logs --tail=100 # Specific service logs docker-compose logs -f zynktime ``` ### Updating the Application ```bash # Pull latest code git pull # Rebuild and restart docker-compose up -d --build # Or force recreate docker-compose up -d --force-recreate ``` ### Accessing the Container ```bash # Open bash shell docker-compose exec zynktime bash # Run CLI mode docker-compose exec zynktime python main.py cli # Run tests docker-compose exec zynktime pytest -v ``` ## Production Deployment ### With Nginx Reverse Proxy **nginx.conf:** ```nginx server { listen 80; server_name time.yourdomain.com; location / { proxy_pass http://localhost:8000; 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; } } ``` **docker-compose.yml:** ```yaml version: '3.8' services: zynktime: build: . restart: always expose: - "8000" networks: - nginx-proxy networks: nginx-proxy: external: true ``` ### With Traefik ```yaml version: '3.8' services: zynktime: build: . restart: always networks: - traefik labels: - "traefik.enable=true" - "traefik.http.routers.zynktime.rule=Host(`time.example.com`)" - "traefik.http.routers.zynktime.entrypoints=websecure" - "traefik.http.routers.zynktime.tls.certresolver=letsencrypt" - "traefik.http.services.zynktime.loadbalancer.server.port=8000" networks: traefik: external: true ``` ### SSL/HTTPS Setup **Option 1: Let's Encrypt with Traefik** ```yaml services: traefik: image: traefik:v2.9 command: - "--certificatesresolvers.letsencrypt.acme.email=admin@example.com" - "--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json" - "--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web" ``` **Option 2: Manual SSL with Nginx** ```nginx server { listen 443 ssl http2; server_name time.yourdomain.com; ssl_certificate /path/to/cert.pem; ssl_certificate_key /path/to/key.pem; location / { proxy_pass http://localhost:8000; } } ``` ## Resource Management ### Memory and CPU Limits ```yaml services: zynktime: build: . deploy: resources: limits: cpus: '1.0' memory: 512M reservations: cpus: '0.5' memory: 256M ``` ### Scaling ```bash # Run multiple instances docker-compose up -d --scale zynktime=3 # With load balancer docker-compose up -d --scale zynktime=3 nginx ``` ## Monitoring ### Health Checks ```bash # Check health status docker inspect zynktime | jq '.[0].State.Health' # Watch health status watch -n 5 'docker inspect zynktime | jq ".[0].State.Health"' ``` ### Resource Usage ```bash # Real-time stats docker stats zynktime # Detailed info docker-compose exec zynktime top ``` ### Log Management **Rotate logs:** ```yaml services: zynktime: logging: driver: "json-file" options: max-size: "10m" max-file: "3" ``` **Send to external logging:** ```yaml services: zynktime: logging: driver: "syslog" options: syslog-address: "tcp://logs.example.com:514" ``` ## Backup and Restore ### Backup Configuration ```bash # Backup .env file cp .env .env.backup # Backup logs (if using volume) docker-compose exec zynktime tar -czf /tmp/logs.tar.gz /app/logs docker cp zynktime:/tmp/logs.tar.gz ./logs-backup.tar.gz ``` ### Disaster Recovery ```bash # Export container docker commit zynktime zynktime-backup:$(date +%Y%m%d) docker save zynktime-backup:latest | gzip > zynktime-backup.tar.gz # Restore from backup docker load < zynktime-backup.tar.gz docker-compose up -d ``` ## Troubleshooting ### Container Won't Start ```bash # Check logs docker-compose logs zynktime # Check container details docker inspect zynktime # Verify environment docker-compose config ``` ### Permission Issues ```bash # Fix ownership (if needed) sudo chown -R 1000:1000 ./static ./logs # Check user inside container docker-compose exec zynktime id ``` ### Network Issues ```bash # Test connectivity docker-compose exec zynktime curl http://localhost:8000/health # Check network docker network inspect zynktime-network # Recreate network docker-compose down docker network prune docker-compose up -d ``` ### API Key Issues ```bash # Verify environment variables docker-compose exec zynktime env | grep KLEER # Test API connection docker-compose exec zynktime python -c "from config import Config; Config.validate_config()" ``` ## Security Best Practices ### 1. Run as Non-Root User Already configured in Dockerfile (user: zynktime, UID: 1000) ### 2. Read-Only Filesystem ```yaml services: zynktime: read_only: true tmpfs: - /tmp ``` ### 3. Drop Capabilities ```yaml services: zynktime: cap_drop: - ALL security_opt: - no-new-privileges:true ``` ### 4. Network Isolation ```yaml services: zynktime: networks: - internal # Only expose necessary ports ``` ### 5. Secrets Management ```bash # Use Docker secrets instead of .env echo "my_api_key" | docker secret create kleer_api_key - # In compose file: services: zynktime: secrets: - kleer_api_key ``` ## Performance Optimization ### Image Size Optimization ```dockerfile # Multi-stage build FROM python:3.11-slim as builder WORKDIR /app COPY requirements.txt . RUN pip install --user --no-cache-dir -r requirements.txt FROM python:3.11-slim COPY --from=builder /root/.local /root/.local COPY . /app ``` ### Caching Strategies ```bash # Use BuildKit for better caching DOCKER_BUILDKIT=1 docker-compose build # Cache requirements separately RUN --mount=type=cache,target=/root/.cache/pip \ pip install -r requirements.txt ``` ## CI/CD Integration ### GitHub Actions ```yaml name: Build and Deploy on: push: branches: [main] jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Build and push run: | docker build -t zynktime:latest . docker-compose up -d ``` ### GitLab CI ```yaml deploy: stage: deploy script: - docker-compose build - docker-compose up -d only: - main ``` ## Additional Resources - [Docker Documentation](https://docs.docker.com/) - [Docker Compose Reference](https://docs.docker.com/compose/) - [FastAPI Deployment](https://fastapi.tiangolo.com/deployment/) - [Python Docker Best Practices](https://docs.docker.com/language/python/build-images/)