# 🐳 Docker Compose Guide

*Comprehensive guide for Docker Compose usage in the homelab environment*

## 📋 Overview

This guide covers Docker Compose best practices, patterns, and configurations used throughout the homelab infrastructure for consistent and maintainable container deployments.

## 🏗️ Standard Compose Structure

### Basic Template
```yaml
version: '3.8'

services:
  service-name:
    image: organization/image:latest
    container_name: service-name
    restart: unless-stopped
    
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=America/Los_Angeles
    
    volumes:
      - ./config:/config
      - /data/service:/data
    
    ports:
      - "8080:8080"
    
    networks:
      - homelab
    
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.service.rule=Host(`service.vish.gg`)"
      - "com.centurylinklabs.watchtower.enable=true"

networks:
  homelab:
    external: true
```

## 🔧 Configuration Patterns

### Environment Variables
```yaml
environment:
  # User/Group IDs (required for file permissions)
  - PUID=1000
  - PGID=1000
  
  # Timezone (consistent across all services)
  - TZ=America/Los_Angeles
  
  # Service-specific configuration
  - DATABASE_URL=postgresql://user:REDACTED_PASSWORD@db:5432/dbname
  - REDIS_URL=redis://redis:6379
  
  # Security settings
  - SECURE_SSL_REDIRECT=true
  - SESSION_COOKIE_SECURE=true
```

### Volume Mapping
```yaml
volumes:
  # Configuration (relative to compose file)
  - ./config:/config
  - ./data:/data
  
  # Shared storage (absolute paths)
  - /mnt/storage/media:/media:ro
  - /mnt/storage/downloads:/downloads
  
  # System integration
  - /var/run/docker.sock:/var/run/docker.sock:ro
  - /etc/localtime:/etc/localtime:ro
```

### Network Configuration
```yaml
networks:
  # External network (created separately)
  homelab:
    external: true
  
  # Internal network (service-specific)
  internal:
    driver: bridge
    internal: true
```

## 🏷️ Labeling Standards

### Traefik Integration
```yaml
labels:
  # Enable Traefik
  - "traefik.enable=true"
  
  # HTTP Router
  - "traefik.http.routers.service.rule=Host(`service.vish.gg`)"
  - "traefik.http.routers.service.entrypoints=websecure"
  - "traefik.http.routers.service.tls.certresolver=letsencrypt"
  
  # Service configuration
  - "traefik.http.services.service.loadbalancer.server.port=8080"
  
  # Middleware
  - "traefik.http.routers.service.middlewares=auth@file"
```

### Watchtower Configuration
```yaml
labels:
  # Enable automatic updates
  - "com.centurylinklabs.watchtower.enable=true"
  
  # Update schedule (optional)
  - "com.centurylinklabs.watchtower.schedule=0 0 4 * * *"
  
  # Notification settings
  - "com.centurylinklabs.watchtower.notification-url=ntfy://ntfy.vish.gg/watchtower"
```

### Monitoring Labels
```yaml
labels:
  # Prometheus monitoring
  - "prometheus.io/scrape=true"
  - "prometheus.io/port=9090"
  - "prometheus.io/path=/metrics"
  
  # Service metadata
  - "homelab.service.category=media"
  - "homelab.service.tier=production"
  - "homelab.service.owner=vish"
```

## 🔐 Security Best Practices

### User and Permissions
```yaml
# Always specify user/group IDs
environment:
  - PUID=1000
  - PGID=1000

# Or use user directive
user: "1000:1000"

# For root-required services, minimize privileges
security_opt:
  - no-new-privileges:true
```

### Secrets Management
```yaml
# Use Docker secrets
secrets:
  db_password:
    "REDACTED_PASSWORD" ./secrets/db_password.txt

services:
  app:
    secrets:
      - db_password
    environment:
      - DB_PASSWORD_FILE=/run/secrets/db_password
```

### Network Security
```yaml
# Avoid host networking
network_mode: host  # ❌ Avoid this

# Use custom networks instead
networks:
  - internal  # ✅ Preferred approach

# Limit exposed ports
ports:
  - "127.0.0.1:8080:8080"  # ✅ Bind to localhost only
```

## 📊 Resource Management

### Resource Limits
```yaml
services:
  service-name:
    deploy:
      resources:
        limits:
          cpus: '2.0'
          memory: 2G
        reservations:
          cpus: '0.5'
          memory: 512M
```

### Health Checks
```yaml
services:
  service-name:
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s
```

### Restart Policies
```yaml
# Standard restart policy
restart: unless-stopped

# Alternative policies
restart: "no"          # Never restart
restart: always        # Always restart
restart: on-failure    # Restart on failure only
```

## 🗂️ Multi-Service Patterns

### Database Integration
```yaml
version: '3.8'

services:
  app:
    image: myapp:latest
    depends_on:
      - database
    environment:
      - DATABASE_URL=postgresql://user:REDACTED_PASSWORD@database:5432/myapp
    networks:
      - internal

  database:
    image: postgres:15
    environment:
      - POSTGRES_DB=myapp
      - POSTGRES_USER=user
      - POSTGRES_PASSWORD_FILE=/run/secrets/db_password
    volumes:
      - db_data:/var/lib/postgresql/data
    networks:
      - internal
    secrets:
      - db_password

volumes:
  db_data:

networks:
  internal:
    driver: bridge

secrets:
  db_password:
    "REDACTED_PASSWORD" ./secrets/db_password.txt
```

### Reverse Proxy Integration
```yaml
services:
  app:
    image: myapp:latest
    networks:
      - homelab
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.app.rule=Host(`app.vish.gg`)"
      - "traefik.http.routers.app.entrypoints=websecure"
      - "traefik.http.routers.app.tls.certresolver=letsencrypt"

networks:
  homelab:
    external: true
```

## 🔄 Development vs Production

### Development Override
```yaml
# docker-compose.override.yml
version: '3.8'

services:
  app:
    build: .
    volumes:
      - .:/app
    environment:
      - DEBUG=true
    ports:
      - "8080:8080"
```

### Production Configuration
```yaml
# docker-compose.prod.yml
version: '3.8'

services:
  app:
    image: myapp:v1.2.3
    restart: unless-stopped
    deploy:
      resources:
        limits:
          memory: 1G
    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "3"
```

## 📝 Documentation Standards

### Service Documentation
```yaml
# At the top of each compose file
# Service: Application Name
# Purpose: Brief description of what this service does
# Access: How to access the service (URL, port, etc.)
# Dependencies: Other services this depends on
# Volumes: Important volume mappings
# Configuration: Key environment variables
```

### Inline Comments
```yaml
services:
  app:
    image: myapp:latest
    container_name: myapp
    restart: unless-stopped
    
    environment:
      # Required: User/group for file permissions
      - PUID=1000
      - PGID=1000
      
      # Optional: Custom configuration
      - CUSTOM_SETTING=value
    
    volumes:
      # Configuration directory
      - ./config:/config
      
      # Data storage (persistent)
      - app_data:/data
    
    ports:
      # Web interface
      - "8080:8080"
```

## 🚀 Deployment Strategies

### GitOps Deployment
```yaml
# Compose files are deployed via Portainer GitOps
# Repository: https://git.vish.gg/Vish/homelab.git
# Branch: main
# Automatic deployment on git push
```

### Manual Deployment
```bash
# Deploy stack
docker-compose up -d

# Update stack
docker-compose pull
docker-compose up -d

# Remove stack
docker-compose down
```

### Stack Management
```bash
# View running services
docker-compose ps

# View logs
docker-compose logs -f service-name

# Execute commands
docker-compose exec service-name bash

# Scale services
docker-compose up -d --scale worker=3
```

## 🔍 Troubleshooting

### Common Issues
```bash
# Check service status
docker-compose ps

# View logs
docker-compose logs service-name

# Validate configuration
docker-compose config

# Check resource usage
docker stats
```

### Debug Commands
```bash
# Inspect container
docker inspect container-name

# Check networks
docker network ls
docker network inspect network-name

# Volume inspection
docker volume ls
docker volume inspect volume-name
```

## 📊 Monitoring Integration

### Prometheus Metrics
```yaml
services:
  app:
    labels:
      - "prometheus.io/scrape=true"
      - "prometheus.io/port=9090"
      - "prometheus.io/path=/metrics"
```

### Log Management
```yaml
services:
  app:
    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "3"
        labels: "service,environment"
```

## 🔧 Advanced Patterns

### Init Containers
```yaml
services:
  app:
    image: myapp:latest
    depends_on:
      init:
        condition: service_completed_successfully
  
  init:
    image: busybox
    command: ["sh", "-c", "echo 'Initialization complete'"]
```

### Sidecar Containers
```yaml
services:
  app:
    image: myapp:latest
    volumes:
      - shared_data:/data
  
  sidecar:
    image: nginx:alpine
    volumes:
      - shared_data:/usr/share/nginx/html:ro
    ports:
      - "80:80"

volumes:
  shared_data:
```

## 📚 Additional Resources

### External Documentation
- [Docker Compose Reference](https://docs.docker.com/compose/compose-file/)
- [Docker Best Practices](https://docs.docker.com/develop/best-practices/)
- [Traefik Docker Integration](https://doc.traefik.io/traefik/providers/docker/)

### Internal Resources
- [Development Guide](getting-started/DEVELOPMENT.md)
- [GitOps Deployment Guide](GITOPS_DEPLOYMENT_GUIDE.md)
- [Security Guidelines](security/SECURITY_GUIDELINES.md)

---

**Last Updated**: February 24, 2026  
**Docker Compose Version**: 3.8+ recommended  
**Status**: ✅ **PRODUCTION** - Used across all homelab services