# 🐳 Docker Compose Guide *Comprehensive guide for Docker Compose best practices in the homelab* ## Overview This guide covers Docker Compose best practices, patterns, and standards used throughout the homelab infrastructure for consistent, maintainable, and secure container deployments. ## File Structure Standards ### Naming Conventions - **Service files**: `service-name.yml` or `service-name.yaml` - **Stack names**: Use descriptive, kebab-case names - **Container names**: Include service and host identifier - **Volume names**: Prefix with service name for clarity ### Directory Organization ``` host-name/ ├── service-name/ │ ├── docker-compose.yml │ ├── .env │ ├── config/ │ └── data/ └── service-name.yml (simple services) ``` ## Compose File Best Practices ### Version and Services ```yaml version: '3.8' # Use stable version services: service-name: image: official/image:tag # Always pin versions container_name: service-name-hostname restart: unless-stopped # Standard restart policy ``` ### Environment Variables ```yaml # Prefer environment files env_file: - .env # Or explicit environment variables environment: - PUID=1000 - PGID=1000 - TZ=America/New_York ``` ### Volume Management ```yaml volumes: # Named volumes for data persistence - service-data:/app/data # Bind mounts for configuration - ./config:/app/config:ro # Host paths for media/large data - /mnt/storage/media:/media:ro volumes: service-data: driver: local ``` ### Network Configuration ```yaml networks: default: name: service-network # Or use existing networks proxy: external: true name: nginx-proxy-manager_default ``` ## Security Best Practices ### User and Permissions ```yaml services: app: user: "1000:1000" # Run as non-root user # Or use environment variables environment: - PUID=1000 - PGID=1000 ``` ### Resource Limits ```yaml services: app: deploy: resources: limits: memory: 512M cpus: '0.5' reservations: memory: 256M ``` ### Security Options ```yaml services: app: security_opt: - no-new-privileges:true # Read-only root filesystem when possible read_only: true tmpfs: - /tmp - /var/tmp ``` ## Common Patterns ### Reverse Proxy Integration ```yaml services: app: labels: # Nginx Proxy Manager - "traefik.enable=true" - "traefik.http.routers.app.rule=Host(`app.domain.com`)" # Or Traefik labels - "traefik.http.services.app.loadbalancer.server.port=8080" ``` ### Health Checks ```yaml services: app: healthcheck: test: ["CMD", "curl", "-f", "http://localhost:8080/health"] interval: 30s timeout: 10s retries: 3 start_period: 60s ``` ### Dependency Management ```yaml services: app: depends_on: database: condition: service_healthy database: healthcheck: test: ["CMD", "pg_isready", "-U", "postgres"] ``` ## GitOps Integration ### Portainer Stack Deployment - **Repository**: `https://git.vish.gg/Vish/homelab.git` - **Branch**: `main` - **Compose file path**: `host-name/service-name.yml` - **Environment variables**: Managed in Portainer UI ### File Path Standards ``` Atlantis/service-name.yml # Primary NAS services Calypso/service-name.yml # Secondary NAS services homelab_vm/service-name.yml # VM-based services concord_nuc/service-name.yml # NUC services raspberry-pi-5-vish/service-name.yml # Pi services ``` ### Environment File Management ```bash # .env file structure PUID=1000 PGID=1000 TZ=America/New_York SERVICE_PORT=8080 DATA_PATH=/mnt/storage/service-name ``` ## Service Categories ### Media Services ```yaml services: plex: image: plexinc/pms-docker:latest environment: - PLEX_CLAIM=claim-token - PLEX_UID=1000 - PLEX_GID=1000 volumes: - plex-config:/config - /mnt/media:/media:ro ports: - "32400:32400" ``` ### Database Services ```yaml services: postgres: image: postgres:15-alpine environment: - POSTGRES_DB=appdb - POSTGRES_USER=appuser - POSTGRES_PASSWORD_FILE=/run/secrets/db_password secrets: - db_password volumes: - postgres-data:/var/lib/postgresql/data secrets: db_password: "REDACTED_PASSWORD" ./secrets/db_password.txt ``` ### Web Applications ```yaml services: webapp: image: nginx:alpine volumes: - ./html:/usr/share/nginx/html:ro - ./nginx.conf:/etc/nginx/nginx.conf:ro labels: - "traefik.enable=true" - "traefik.http.routers.webapp.rule=Host(`app.local`)" ``` ## Monitoring Integration ### Prometheus Metrics ```yaml services: app: labels: - "prometheus.io/scrape=true" - "prometheus.io/port=9090" - "prometheus.io/path=/metrics" ``` ### Logging Configuration ```yaml services: app: logging: driver: "json-file" options: max-size: "10m" max-file: "3" # Or use centralized logging logging: driver: "loki" options: loki-url: "http://loki:3100/loki/api/v1/push" ``` ## Backup Considerations ### Volume Backup Strategy ```yaml # Backup-friendly volume structure volumes: app-config: driver: local driver_opts: type: none o: bind device: /mnt/backup/app/config app-data: driver: local driver_opts: type: none o: bind device: /mnt/backup/app/data ``` ### Database Backup ```yaml services: db-backup: image: postgres:15-alpine command: | sh -c " while true; do pg_dump -h postgres -U $$POSTGRES_USER $$POSTGRES_DB > /backup/backup_$$(date +%Y%m%d_%H%M%S).sql sleep 86400 done" volumes: - ./backups:/backup depends_on: - postgres ``` ## Troubleshooting ### Common Issues #### Port Conflicts ```bash # Check port usage netstat -tulpn | grep :8080 docker ps --format "table {{.Names}}\t{{.Ports}}" ``` #### Volume Permissions ```bash # Fix volume permissions sudo chown -R 1000:1000 /path/to/volume sudo chmod -R 755 /path/to/volume ``` #### Network Issues ```bash # Inspect networks docker network ls docker network inspect network-name # Test connectivity docker exec container-name ping other-container ``` ### Debugging Commands ```bash # View logs docker-compose logs -f service-name # Execute commands in container docker-compose exec service-name bash # Validate compose file docker-compose config # Check service status docker-compose ps ``` ## Performance Optimization ### Resource Management ```yaml services: app: deploy: resources: limits: memory: 1G cpus: '1.0' # Use init system for proper signal handling init: true # Optimize for specific workloads sysctls: - net.core.somaxconn=1024 ``` ### Storage Optimization ```yaml # Use tmpfs for temporary data tmpfs: - /tmp:size=100M,noexec,nosuid,nodev # Optimize volume drivers volumes: fast-data: driver: local driver_opts: type: tmpfs device: tmpfs o: size=1G ``` ## Validation and Testing ### Pre-deployment Checks ```bash # Validate syntax docker-compose config # Check for security issues docker-compose config | docker run --rm -i hadolint/hadolint # Test deployment docker-compose up --dry-run ``` ### Health Monitoring ```yaml services: app: healthcheck: test: ["CMD-SHELL", "curl -f http://localhost:8080/health || exit 1"] interval: 30s timeout: 10s retries: 3 start_period: 40s ``` ## Related Documentation - [GitOps Deployment Guide](docs/GITOPS_DEPLOYMENT_GUIDE.md) - GitOps workflow and deployment procedures - [Security Guidelines](docs/security/SECURITY_GUIDELINES.md) - Security best practices for containers - [Monitoring Architecture](docs/MONITORING_ARCHITECTURE.md) - Monitoring and observability setup --- **Status**: ✅ Docker Compose standards implemented across all homelab services