419 lines
8.0 KiB
Markdown
419 lines
8.0 KiB
Markdown
# 🐳 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 |