# 🐳 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