12 KiB
12 KiB
🚀 Service Deployment Guide
🟡 Intermediate Guide
This guide covers how to deploy new services in the homelab infrastructure, following established patterns and best practices used across all 176 Docker Compose configurations.
🎯 Deployment Philosophy
🏗️ Infrastructure as Code
- All services are defined in Docker Compose files
- Configuration is version-controlled in Git
- Ansible automates deployment and management
- Consistent patterns across all services
🔄 Deployment Workflow
Development → Testing → Staging → Production
↓ ↓ ↓ ↓
Local PC → Test VM → Staging → Live Host
📋 Pre-Deployment Checklist
✅ Before You Start
- Identify the appropriate host for your service
- Check resource requirements (CPU, RAM, storage)
- Verify network port availability
- Review security implications
- Plan data persistence strategy
- Consider backup requirements
🎯 Host Selection Criteria
| Host Type | Best For | Avoid For |
|---|---|---|
| Synology NAS | Always-on services, media, storage | CPU-intensive tasks |
| Proxmox VMs | Isolated workloads, testing | Resource-constrained apps |
| Physical Hosts | AI/ML, gaming, high-performance | Simple utilities |
| Edge Devices | IoT, networking, lightweight apps | Heavy databases |
🐳 Docker Compose Patterns
📝 Standard Template
Every service follows this basic structure:
version: '3.9'
services:
service-name:
image: official/image:latest
container_name: Service-Name
hostname: service-hostname
# Security hardening
security_opt:
- no-new-privileges:true
user: 1026:100 # Synology user mapping (adjust per host)
read_only: true # For stateless services
# Health monitoring
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 60s
# Restart policy
restart: on-failure:5
# Resource limits
deploy:
resources:
limits:
memory: 512M
cpus: '0.5'
reservations:
memory: 256M
# Networking
networks:
- service-network
ports:
- "8080:80"
# Data persistence
volumes:
- /volume1/docker/service:/data:rw
- /etc/localtime:/etc/localtime:ro
# Configuration
environment:
- TZ=America/Los_Angeles
- PUID=1026
- PGID=100
env_file:
- .env
# Dependencies
depends_on:
database:
condition: service_healthy
# Supporting services (database, cache, etc.)
database:
image: postgres:15
container_name: Service-DB
# ... similar configuration
networks:
service-network:
name: service-network
ipam:
config:
- subnet: 192.168.x.0/24
volumes:
service-data:
driver: local
🔧 Host-Specific Adaptations
Synology NAS (Atlantis, Calypso, Setillo)
# User mapping for Synology
user: 1026:100
# Volume paths
volumes:
- /volume1/docker/service:/data:rw
- /volume1/media:/media:ro
# Memory limits (conservative)
deploy:
resources:
limits:
memory: 1G
Proxmox VMs (Homelab, Chicago, Bulgaria)
# Standard Linux user
user: 1000:1000
# Volume paths
volumes:
- ./data:/data:rw
- /etc/localtime:/etc/localtime:ro
# More generous resources
deploy:
resources:
limits:
memory: 4G
cpus: '2.0'
Physical Hosts (Anubis, Guava)
# GPU access (if needed)
runtime: nvidia
environment:
- NVIDIA_VISIBLE_DEVICES=all
# High-performance settings
deploy:
resources:
limits:
memory: 16G
cpus: '8.0'
📁 Directory Structure
🗂️ Standard Layout
/workspace/homelab/
├── HostName/
│ ├── service-name/
│ │ ├── docker-compose.yml
│ │ ├── .env
│ │ ├── config/
│ │ └── README.md
│ └── service-name.yml # Simple services
├── docs/
└── ansible/
📝 File Naming Conventions
- Simple services:
service-name.yml - Complex services:
service-name/docker-compose.yml - Environment files:
.envorstack.env - Configuration:
config/directory
🔐 Security Best Practices
🛡️ Container Security
# Security hardening
security_opt:
- no-new-privileges:true
- apparmor:docker-default
- seccomp:unconfined # Only if needed
# User namespaces
user: 1026:100 # Non-root user
# Read-only filesystem
read_only: true
tmpfs:
- /tmp
- /var/tmp
# Capability dropping
cap_drop:
- ALL
cap_add:
- CHOWN # Only add what's needed
🔑 Secrets Management
# Use Docker secrets for sensitive data
secrets:
db_password:
"REDACTED_PASSWORD" ./secrets/db_password.txt
services:
app:
secrets:
- db_password
environment:
- DB_PASSWORD_FILE=/run/secrets/db_password
🌐 Network Security
# Custom networks for isolation
networks:
frontend:
internal: false # Internet access
backend:
internal: true # No internet access
services:
web:
networks:
- frontend
- backend
database:
networks:
- backend # Database isolated from internet
📊 Monitoring Integration
📈 Health Checks
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 60s
🏷️ Prometheus Labels
labels:
- "prometheus.io/scrape=true"
- "prometheus.io/port=8080"
- "prometheus.io/path=/metrics"
- "service.category=media"
- "service.tier=production"
📊 Logging Configuration
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
labels: "service,environment"
🚀 Deployment Process
1️⃣ Local Development
# Create service directory
mkdir -p ~/homelab-dev/new-service
cd ~/homelab-dev/new-service
# Create docker-compose.yml
cat > docker-compose.yml << 'EOF'
# Your service configuration
EOF
# Test locally
docker-compose up -d
docker-compose logs -f
2️⃣ Testing & Validation
# Health check
curl -f http://localhost:8080/health
# Resource usage
docker stats
# Security scan
docker scout cves
# Cleanup
docker-compose down -v
3️⃣ Repository Integration
# Add to homelab repository
cp -r ~/homelab-dev/new-service /workspace/homelab/TargetHost/
# Update documentation
echo "## New Service" >> /workspace/homelab/TargetHost/README.md
# Commit changes
git add .
git commit -m "Add new-service to TargetHost"
4️⃣ Ansible Deployment
# Deploy using Ansible
cd /workspace/homelab/ansible
ansible-playbook -i inventory.ini deploy-service.yml \
--extra-vars "target_host=atlantis service_name=new-service"
# Verify deployment
ansible atlantis -i inventory.ini -m shell \
-a "docker ps | grep new-service"
🔧 Service-Specific Patterns
🎬 Media Services
# Common media service pattern
services:
media-service:
image: linuxserver/service:latest
environment:
- PUID=1026
- PGID=100
- TZ=America/Los_Angeles
volumes:
- /volume1/docker/service:/config
- /volume1/media:/media:ro
- /volume1/downloads:/downloads:rw
ports:
- "8080:8080"
🗄️ Database Services
# Database with backup integration
services:
database:
image: postgres:15
environment:
- POSTGRES_DB=appdb
- POSTGRES_USER=appuser
- POSTGRES_PASSWORD_FILE=/run/secrets/db_password
volumes:
- db_data:/var/lib/postgresql/data
- ./backups:/backups
secrets:
- db_password
healthcheck:
test: ["CMD-SHELL", "pg_isready -U appuser -d appdb"]
🌐 Web Services
# Web service with reverse proxy
services:
web-app:
image: nginx:alpine
labels:
- "traefik.enable=true"
- "traefik.http.routers.webapp.rule=Host(`app.example.com`)"
- "traefik.http.services.webapp.loadbalancer.server.port=80"
volumes:
- ./html:/usr/share/nginx/html:ro
📋 Deployment Checklist
✅ Pre-Deployment
- Service configuration reviewed
- Resource requirements calculated
- Security settings applied
- Health checks configured
- Backup strategy planned
- Monitoring integration added
✅ During Deployment
- Service starts successfully
- Health checks pass
- Logs show no errors
- Network connectivity verified
- Resource usage within limits
- Security scan completed
✅ Post-Deployment
- Service accessible via intended URLs
- Monitoring alerts configured
- Backup jobs scheduled
- Documentation updated
- Team notified of new service
- Performance baseline established
🚨 Troubleshooting Deployment Issues
🔍 Common Problems
Container Won't Start
# Check logs
docker-compose logs service-name
# Check resource constraints
docker stats
# Verify image availability
docker pull image:tag
# Check port conflicts
netstat -tulpn | grep :8080
Permission Issues
# Fix ownership (Synology)
sudo chown -R 1026:100 /volume1/docker/service
# Fix permissions
sudo chmod -R 755 /volume1/docker/service
Network Issues
# Check network connectivity
docker exec service-name ping google.com
# Verify DNS resolution
docker exec service-name nslookup service-name
# Check port binding
docker port service-name
Resource Constraints
# Check memory usage
docker stats --no-stream
# Check disk space
df -h
# Monitor resource limits
docker exec service-name cat /sys/fs/cgroup/memory/memory.limit_in_bytes
🔄 Update & Maintenance
📦 Container Updates
# Update single service
docker-compose pull
docker-compose up -d
# Update with Watchtower (automated)
# Watchtower handles updates automatically for tagged containers
🔧 Configuration Changes
# Apply configuration changes
docker-compose down
# Edit configuration files
docker-compose up -d
# Rolling updates (zero downtime)
docker-compose up -d --no-deps service-name
🗄️ Database Migrations
# Backup before migration
docker exec db-container pg_dump -U user dbname > backup.sql
# Run migrations
docker-compose exec app python manage.py migrate
# Verify migration
docker-compose exec app python manage.py showmigrations
📊 Performance Optimization
⚡ Resource Tuning
# Optimize for your workload
deploy:
resources:
limits:
memory: 2G # Set based on actual usage
cpus: '1.0' # Adjust for CPU requirements
reservations:
memory: 512M # Guarantee minimum resources
🗄️ Storage Optimization
# Use appropriate volume types
volumes:
# Fast storage for databases
- /volume1/ssd/db:/var/lib/postgresql/data
# Slower storage for archives
- /volume1/hdd/archives:/archives:ro
# Temporary storage
- type: tmpfs
target: /tmp
tmpfs:
size: 100M
🌐 Network Optimization
# Optimize network settings
networks:
app-network:
driver: bridge
driver_opts:
com.docker.network.bridge.name: br-app
com.docker.network.driver.mtu: 1500
📋 Next Steps
- Monitoring Setup: Configure monitoring for your new service
- Backup Configuration: Set up automated backups
- Troubleshooting Guide: Common deployment issues
- Service Categories: Find similar services for reference
Remember: Start simple, test thoroughly, and iterate based on real-world usage. Every service in this homelab started with this basic deployment pattern.