8.0 KiB
8.0 KiB
🐳 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.ymlorservice-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
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
# Prefer environment files
env_file:
- .env
# Or explicit environment variables
environment:
- PUID=1000
- PGID=1000
- TZ=America/New_York
Volume Management
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
networks:
default:
name: service-network
# Or use existing networks
proxy:
external: true
name: nginx-proxy-manager_default
Security Best Practices
User and Permissions
services:
app:
user: "1000:1000" # Run as non-root user
# Or use environment variables
environment:
- PUID=1000
- PGID=1000
Resource Limits
services:
app:
deploy:
resources:
limits:
memory: 512M
cpus: '0.5'
reservations:
memory: 256M
Security Options
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
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
services:
app:
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 60s
Dependency Management
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
# .env file structure
PUID=1000
PGID=1000
TZ=America/New_York
SERVICE_PORT=8080
DATA_PATH=/mnt/storage/service-name
Service Categories
Media Services
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
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
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
services:
app:
labels:
- "prometheus.io/scrape=true"
- "prometheus.io/port=9090"
- "prometheus.io/path=/metrics"
Logging Configuration
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
# 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
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
# Check port usage
netstat -tulpn | grep :8080
docker ps --format "table {{.Names}}\t{{.Ports}}"
Volume Permissions
# Fix volume permissions
sudo chown -R 1000:1000 /path/to/volume
sudo chmod -R 755 /path/to/volume
Network Issues
# Inspect networks
docker network ls
docker network inspect network-name
# Test connectivity
docker exec container-name ping other-container
Debugging Commands
# 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
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
# 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
# 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
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 - GitOps workflow and deployment procedures
- Security Guidelines - Security best practices for containers
- Monitoring Architecture - Monitoring and observability setup
Status: ✅ Docker Compose standards implemented across all homelab services