743 lines
15 KiB
Markdown
743 lines
15 KiB
Markdown
# Deployment Guide
|
|
|
|
## Overview
|
|
|
|
This guide provides comprehensive instructions for deploying services in the homelab environment using GitOps principles with Docker Compose and Portainer. All deployments follow infrastructure-as-code practices with version control and automated workflows.
|
|
|
|
## Deployment Architecture
|
|
|
|
### GitOps Workflow
|
|
```
|
|
Developer ──▶ Git Repository ──▶ Portainer ──▶ Docker Compose ──▶ Running Services
|
|
│ │ │ │
|
|
│ │ │ └─▶ Health Checks
|
|
│ │ └─▶ Stack Management
|
|
│ └─▶ Configuration Validation
|
|
└─▶ Documentation Updates
|
|
```
|
|
|
|
### Repository Structure
|
|
```
|
|
homelab/
|
|
├── hosts/
|
|
│ ├── atlantis/ # Atlantis server configs
|
|
│ ├── calypso/ # Calypso server configs
|
|
│ ├── concord_nuc/ # Concord NUC configs
|
|
│ ├── homelab_vm/ # Homelab VM configs
|
|
│ └── raspberry-pi-5-vish/ # Raspberry Pi configs
|
|
├── common/ # Shared configurations
|
|
├── docs/ # Documentation
|
|
└── scripts/ # Automation scripts
|
|
```
|
|
|
|
## Prerequisites
|
|
|
|
### Required Access
|
|
- **Git Repository**: Read access to homelab repository
|
|
- **Portainer Access**: Admin credentials for container management
|
|
- **SSH Access**: Server administration capabilities
|
|
- **Network Access**: Internal network connectivity
|
|
|
|
### Required Tools
|
|
```bash
|
|
# Install required tools
|
|
sudo apt update && sudo apt install -y \
|
|
git \
|
|
docker.io \
|
|
docker-compose \
|
|
curl \
|
|
wget \
|
|
vim
|
|
|
|
# Verify installations
|
|
git --version
|
|
docker --version
|
|
docker-compose --version
|
|
```
|
|
|
|
### Environment Setup
|
|
```bash
|
|
# Clone repository
|
|
git clone https://git.vish.gg/Vish/homelab.git
|
|
cd homelab
|
|
|
|
# Set up environment variables
|
|
export HOMELAB_ENV="production"
|
|
export DOCKER_HOST="tcp://atlantis.vish.local:2376"
|
|
export PORTAINER_URL="http://atlantis.vish.local:9000"
|
|
```
|
|
|
|
## Deployment Methods
|
|
|
|
### Method 1: Portainer Stack Deployment (Recommended)
|
|
|
|
#### Step 1: Access Portainer
|
|
1. Navigate to [Portainer](http://atlantis.vish.local:9000)
|
|
2. Login with admin credentials
|
|
3. Select the appropriate endpoint
|
|
|
|
#### Step 2: Create New Stack
|
|
1. Go to **Stacks** → **Add Stack**
|
|
2. Choose deployment method:
|
|
- **Git Repository** (recommended)
|
|
- **Upload** (for local files)
|
|
- **Web Editor** (for quick edits)
|
|
|
|
#### Step 3: Configure Git Repository
|
|
```yaml
|
|
Repository URL: https://git.vish.gg/Vish/homelab.git
|
|
Reference: refs/heads/main
|
|
Compose Path: hosts/atlantis/service-name.yml
|
|
```
|
|
|
|
#### Step 4: Set Environment Variables
|
|
```bash
|
|
# Common variables
|
|
PUID=1000
|
|
PGID=1000
|
|
TZ=America/New_York
|
|
DOMAIN=vish.local
|
|
|
|
# Service-specific variables
|
|
SERVICE_PORT=8080
|
|
SERVICE_DATA=/mnt/storage/service-name
|
|
```
|
|
|
|
#### Step 5: Deploy Stack
|
|
1. Click **Deploy the Stack**
|
|
2. Monitor deployment logs
|
|
3. Verify service health
|
|
|
|
### Method 2: Command Line Deployment
|
|
|
|
#### Direct Docker Compose
|
|
```bash
|
|
# Navigate to service directory
|
|
cd hosts/atlantis
|
|
|
|
# Deploy service
|
|
docker-compose -f service-name.yml up -d
|
|
|
|
# Check status
|
|
docker-compose -f service-name.yml ps
|
|
|
|
# View logs
|
|
docker-compose -f service-name.yml logs -f
|
|
```
|
|
|
|
#### Using Deployment Scripts
|
|
```bash
|
|
# Run deployment script
|
|
./scripts/deploy-service.sh atlantis service-name
|
|
|
|
# Bulk deployment
|
|
./scripts/deploy-all.sh atlantis
|
|
|
|
# Update existing service
|
|
./scripts/update-service.sh atlantis service-name
|
|
```
|
|
|
|
### Method 3: Ansible Automation
|
|
|
|
#### Playbook Deployment
|
|
```bash
|
|
# Deploy single service
|
|
ansible-playbook -i inventory.ini ansible/deploy-service.yml \
|
|
-e target_host=atlantis \
|
|
-e service_name=plex
|
|
|
|
# Deploy full stack
|
|
ansible-playbook -i inventory.ini ansible/deploy-full-stack.yml \
|
|
-e target_host=atlantis
|
|
|
|
# Update all services
|
|
ansible-playbook -i inventory.ini ansible/update-all.yml
|
|
```
|
|
|
|
## Service Configuration
|
|
|
|
### Docker Compose Template
|
|
```yaml
|
|
version: '3.8'
|
|
|
|
services:
|
|
service-name:
|
|
image: organization/service:latest
|
|
container_name: service-name
|
|
restart: unless-stopped
|
|
|
|
environment:
|
|
- PUID=${PUID:-1000}
|
|
- PGID=${PGID:-1000}
|
|
- TZ=${TZ:-UTC}
|
|
- SERVICE_CONFIG=${SERVICE_CONFIG}
|
|
|
|
volumes:
|
|
- ${DATA_PATH}/config:/config
|
|
- ${DATA_PATH}/data:/data
|
|
- /etc/localtime:/etc/localtime:ro
|
|
|
|
ports:
|
|
- "${SERVICE_PORT}:8080"
|
|
|
|
networks:
|
|
- homelab
|
|
|
|
labels:
|
|
- "traefik.enable=true"
|
|
- "traefik.http.routers.service.rule=Host(`service.${DOMAIN}`)"
|
|
- "traefik.http.services.service.loadbalancer.server.port=8080"
|
|
|
|
healthcheck:
|
|
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
|
|
interval: 30s
|
|
timeout: 10s
|
|
retries: 3
|
|
start_period: 60s
|
|
|
|
networks:
|
|
homelab:
|
|
external: true
|
|
|
|
volumes:
|
|
service-config:
|
|
driver: local
|
|
service-data:
|
|
driver: local
|
|
```
|
|
|
|
### Environment Variables
|
|
```bash
|
|
# Create .env file
|
|
cat > .env << EOF
|
|
# User Configuration
|
|
PUID=1000
|
|
PGID=1000
|
|
TZ=America/New_York
|
|
|
|
# Network Configuration
|
|
DOMAIN=vish.local
|
|
SUBNET=192.168.10.0/24
|
|
|
|
# Storage Configuration
|
|
DATA_ROOT=/mnt/storage
|
|
CONFIG_ROOT=/mnt/config
|
|
BACKUP_ROOT=/mnt/backup
|
|
|
|
# Service Configuration
|
|
SERVICE_PORT=8080
|
|
SERVICE_NAME=example-service
|
|
SERVICE_VERSION=latest
|
|
|
|
# Security Configuration
|
|
SSL_CERT_PATH=/etc/ssl/certs
|
|
SSL_KEY_PATH=/etc/ssl/private
|
|
ADMIN_EMAIL=admin@vish.local
|
|
EOF
|
|
```
|
|
|
|
## Server-Specific Deployments
|
|
|
|
### Atlantis (Primary Server)
|
|
```bash
|
|
# Media services
|
|
./deploy-service.sh atlantis plex
|
|
./deploy-service.sh atlantis sonarr
|
|
./deploy-service.sh atlantis radarr
|
|
|
|
# Storage services
|
|
./deploy-service.sh atlantis nextcloud
|
|
./deploy-service.sh atlantis syncthing
|
|
|
|
# Monitoring services
|
|
./deploy-service.sh atlantis grafana
|
|
./deploy-service.sh atlantis prometheus
|
|
```
|
|
|
|
### Calypso (Secondary Server)
|
|
```bash
|
|
# Development services
|
|
./deploy-service.sh calypso gitea
|
|
./deploy-service.sh calypso portainer
|
|
|
|
# Authentication services
|
|
./deploy-service.sh calypso authentik
|
|
./deploy-service.sh calypso nginx-proxy-manager
|
|
|
|
# Game servers
|
|
./deploy-service.sh calypso minecraft
|
|
./deploy-service.sh calypso satisfactory
|
|
```
|
|
|
|
### Concord NUC (Edge Server)
|
|
```bash
|
|
# Network services
|
|
./deploy-service.sh concord adguard
|
|
./deploy-service.sh concord pihole
|
|
|
|
# IoT services
|
|
./deploy-service.sh concord homeassistant
|
|
./deploy-service.sh concord node-exporter
|
|
|
|
# Media streaming
|
|
./deploy-service.sh concord invidious
|
|
./deploy-service.sh concord piped
|
|
```
|
|
|
|
### Homelab VM (Development)
|
|
```bash
|
|
# AI/ML services
|
|
./deploy-service.sh homelab-vm ollama
|
|
./deploy-service.sh homelab-vm openhands
|
|
|
|
# Communication services
|
|
./deploy-service.sh homelab-vm mattermost
|
|
./deploy-service.sh homelab-vm signal-api
|
|
|
|
# Testing services
|
|
./deploy-service.sh homelab-vm test-environment
|
|
```
|
|
|
|
### Raspberry Pi (Monitoring)
|
|
```bash
|
|
# Monitoring services
|
|
./deploy-service.sh raspberry-pi uptime-kuma
|
|
./deploy-service.sh raspberry-pi glances
|
|
|
|
# Lightweight services
|
|
./deploy-service.sh raspberry-pi immich
|
|
./deploy-service.sh raspberry-pi syncthing
|
|
```
|
|
|
|
## Network Configuration
|
|
|
|
### Docker Networks
|
|
```bash
|
|
# Create homelab network
|
|
docker network create \
|
|
--driver bridge \
|
|
--subnet=172.20.0.0/16 \
|
|
--gateway=172.20.0.1 \
|
|
homelab
|
|
|
|
# Create monitoring network
|
|
docker network create \
|
|
--driver bridge \
|
|
--subnet=172.21.0.0/16 \
|
|
--gateway=172.21.0.1 \
|
|
monitoring
|
|
|
|
# List networks
|
|
docker network ls
|
|
```
|
|
|
|
### Reverse Proxy Configuration
|
|
```yaml
|
|
# Nginx Proxy Manager
|
|
version: '3.8'
|
|
services:
|
|
nginx-proxy-manager:
|
|
image: jc21/nginx-proxy-manager:latest
|
|
container_name: nginx-proxy-manager
|
|
restart: unless-stopped
|
|
ports:
|
|
- "80:80"
|
|
- "443:443"
|
|
- "81:81"
|
|
volumes:
|
|
- ./data:/data
|
|
- ./letsencrypt:/etc/letsencrypt
|
|
environment:
|
|
DB_MYSQL_HOST: "db"
|
|
DB_MYSQL_PORT: 3306
|
|
DB_MYSQL_USER: "npm"
|
|
DB_MYSQL_PASSWORD: "npm"
|
|
DB_MYSQL_NAME: "npm"
|
|
```
|
|
|
|
## Storage Configuration
|
|
|
|
### Volume Mapping
|
|
```yaml
|
|
# Standard volume structure
|
|
volumes:
|
|
- ${DATA_ROOT}/service-name/config:/config
|
|
- ${DATA_ROOT}/service-name/data:/data
|
|
- ${MEDIA_ROOT}:/media:ro
|
|
- ${DOWNLOAD_ROOT}:/downloads
|
|
- /etc/localtime:/etc/localtime:ro
|
|
```
|
|
|
|
### Backup Integration
|
|
```yaml
|
|
# Backup-aware service
|
|
services:
|
|
service-name:
|
|
# ... service configuration ...
|
|
volumes:
|
|
- service-data:/data
|
|
- backup-volume:/backup
|
|
|
|
labels:
|
|
- "backup.enable=true"
|
|
- "backup.schedule=0 2 * * *"
|
|
- "backup.retention=30d"
|
|
|
|
volumes:
|
|
backup-volume:
|
|
driver: local
|
|
driver_opts:
|
|
type: nfs
|
|
o: addr=backup-server.local,rw
|
|
device: ":/mnt/backup/service-name"
|
|
```
|
|
|
|
## Security Configuration
|
|
|
|
### Container Security
|
|
```yaml
|
|
services:
|
|
secure-service:
|
|
# ... other configuration ...
|
|
|
|
# Security options
|
|
security_opt:
|
|
- no-new-privileges:true
|
|
|
|
# Read-only root filesystem
|
|
read_only: true
|
|
|
|
# Temporary filesystem for writable areas
|
|
tmpfs:
|
|
- /tmp
|
|
- /var/tmp
|
|
|
|
# User namespace
|
|
user: "${PUID}:${PGID}"
|
|
|
|
# Capabilities
|
|
cap_drop:
|
|
- ALL
|
|
cap_add:
|
|
- CHOWN
|
|
- SETUID
|
|
- SETGID
|
|
```
|
|
|
|
### Network Security
|
|
```yaml
|
|
# Isolated network configuration
|
|
networks:
|
|
frontend:
|
|
driver: bridge
|
|
internal: false
|
|
backend:
|
|
driver: bridge
|
|
internal: true
|
|
|
|
services:
|
|
web-service:
|
|
networks:
|
|
- frontend
|
|
- backend
|
|
|
|
database:
|
|
networks:
|
|
- backend
|
|
```
|
|
|
|
## Monitoring Integration
|
|
|
|
### Health Checks
|
|
```yaml
|
|
services:
|
|
monitored-service:
|
|
# ... service configuration ...
|
|
|
|
healthcheck:
|
|
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
|
|
interval: 30s
|
|
timeout: 10s
|
|
retries: 3
|
|
start_period: 60s
|
|
|
|
labels:
|
|
- "monitoring.enable=true"
|
|
- "monitoring.port=8080"
|
|
- "monitoring.path=/metrics"
|
|
```
|
|
|
|
### Logging Configuration
|
|
```yaml
|
|
services:
|
|
logged-service:
|
|
# ... service configuration ...
|
|
|
|
logging:
|
|
driver: "json-file"
|
|
options:
|
|
max-size: "10m"
|
|
max-file: "3"
|
|
labels: "service,environment"
|
|
|
|
labels:
|
|
- "logging.enable=true"
|
|
- "logging.service=service-name"
|
|
```
|
|
|
|
## Deployment Validation
|
|
|
|
### Pre-deployment Checks
|
|
```bash
|
|
#!/bin/bash
|
|
# validate-deployment.sh
|
|
|
|
echo "Validating deployment configuration..."
|
|
|
|
# Check Docker Compose syntax
|
|
docker-compose -f $1 config > /dev/null
|
|
if [ $? -eq 0 ]; then
|
|
echo "✅ Docker Compose syntax valid"
|
|
else
|
|
echo "❌ Docker Compose syntax error"
|
|
exit 1
|
|
fi
|
|
|
|
# Check required environment variables
|
|
required_vars=("PUID" "PGID" "TZ" "DOMAIN")
|
|
for var in "${required_vars[@]}"; do
|
|
if [ -z "${!var}" ]; then
|
|
echo "❌ Missing required variable: $var"
|
|
exit 1
|
|
else
|
|
echo "✅ Variable $var is set"
|
|
fi
|
|
done
|
|
|
|
# Check storage paths
|
|
if [ ! -d "$DATA_ROOT" ]; then
|
|
echo "❌ Data root directory does not exist: $DATA_ROOT"
|
|
exit 1
|
|
else
|
|
echo "✅ Data root directory exists"
|
|
fi
|
|
|
|
echo "✅ All validation checks passed"
|
|
```
|
|
|
|
### Post-deployment Verification
|
|
```bash
|
|
#!/bin/bash
|
|
# verify-deployment.sh
|
|
|
|
SERVICE_NAME=$1
|
|
EXPECTED_PORT=$2
|
|
|
|
echo "Verifying deployment of $SERVICE_NAME..."
|
|
|
|
# Check container status
|
|
if docker ps | grep -q $SERVICE_NAME; then
|
|
echo "✅ Container is running"
|
|
else
|
|
echo "❌ Container is not running"
|
|
exit 1
|
|
fi
|
|
|
|
# Check port accessibility
|
|
if curl -f http://localhost:$EXPECTED_PORT/health > /dev/null 2>&1; then
|
|
echo "✅ Service is responding on port $EXPECTED_PORT"
|
|
else
|
|
echo "❌ Service is not responding on port $EXPECTED_PORT"
|
|
fi
|
|
|
|
# Check logs for errors
|
|
if docker logs $SERVICE_NAME 2>&1 | grep -i error; then
|
|
echo "⚠️ Errors found in logs"
|
|
else
|
|
echo "✅ No errors in logs"
|
|
fi
|
|
|
|
echo "✅ Deployment verification complete"
|
|
```
|
|
|
|
## Troubleshooting
|
|
|
|
### Common Issues
|
|
|
|
#### Container Won't Start
|
|
```bash
|
|
# Check container logs
|
|
docker logs container-name
|
|
|
|
# Check resource usage
|
|
docker stats
|
|
|
|
# Verify configuration
|
|
docker-compose config
|
|
|
|
# Check port conflicts
|
|
netstat -tulpn | grep :8080
|
|
```
|
|
|
|
#### Permission Issues
|
|
```bash
|
|
# Fix ownership
|
|
sudo chown -R $PUID:$PGID /mnt/storage/service-name
|
|
|
|
# Check permissions
|
|
ls -la /mnt/storage/service-name
|
|
|
|
# Verify user mapping
|
|
docker exec container-name id
|
|
```
|
|
|
|
#### Network Connectivity
|
|
```bash
|
|
# Test container networking
|
|
docker exec container-name ping google.com
|
|
|
|
# Check network configuration
|
|
docker network inspect homelab
|
|
|
|
# Verify DNS resolution
|
|
docker exec container-name nslookup service.local
|
|
```
|
|
|
|
#### Storage Issues
|
|
```bash
|
|
# Check disk space
|
|
df -h
|
|
|
|
# Verify mount points
|
|
mount | grep storage
|
|
|
|
# Check RAID status
|
|
cat /proc/mdstat
|
|
```
|
|
|
|
### Emergency Procedures
|
|
|
|
#### Service Recovery
|
|
```bash
|
|
# Stop problematic service
|
|
docker-compose -f service.yml down
|
|
|
|
# Remove containers and volumes
|
|
docker-compose -f service.yml down -v
|
|
|
|
# Restore from backup
|
|
./scripts/restore-service.sh service-name
|
|
|
|
# Redeploy service
|
|
docker-compose -f service.yml up -d
|
|
```
|
|
|
|
#### System Recovery
|
|
```bash
|
|
# Stop all services
|
|
docker stop $(docker ps -q)
|
|
|
|
# Clean up system
|
|
docker system prune -a
|
|
|
|
# Restart Docker daemon
|
|
sudo systemctl restart docker
|
|
|
|
# Redeploy critical services
|
|
./scripts/deploy-critical.sh
|
|
```
|
|
|
|
## Automation Scripts
|
|
|
|
### Deployment Automation
|
|
```bash
|
|
#!/bin/bash
|
|
# deploy-service.sh
|
|
|
|
HOST=$1
|
|
SERVICE=$2
|
|
COMPOSE_FILE="hosts/$HOST/$SERVICE.yml"
|
|
|
|
if [ ! -f "$COMPOSE_FILE" ]; then
|
|
echo "Error: Compose file not found: $COMPOSE_FILE"
|
|
exit 1
|
|
fi
|
|
|
|
echo "Deploying $SERVICE on $HOST..."
|
|
|
|
# Validate configuration
|
|
docker-compose -f $COMPOSE_FILE config > /dev/null
|
|
if [ $? -ne 0 ]; then
|
|
echo "Error: Invalid compose configuration"
|
|
exit 1
|
|
fi
|
|
|
|
# Deploy service
|
|
docker-compose -f $COMPOSE_FILE up -d
|
|
|
|
# Wait for service to be ready
|
|
sleep 30
|
|
|
|
# Verify deployment
|
|
./scripts/verify-deployment.sh $SERVICE
|
|
|
|
echo "Deployment complete: $SERVICE"
|
|
```
|
|
|
|
### Update Automation
|
|
```bash
|
|
#!/bin/bash
|
|
# update-service.sh
|
|
|
|
SERVICE=$1
|
|
|
|
echo "Updating $SERVICE..."
|
|
|
|
# Pull latest images
|
|
docker-compose -f hosts/*/$(SERVICE).yml pull
|
|
|
|
# Recreate containers
|
|
docker-compose -f hosts/*/$(SERVICE).yml up -d
|
|
|
|
# Clean up old images
|
|
docker image prune -f
|
|
|
|
echo "Update complete: $SERVICE"
|
|
```
|
|
|
|
## Best Practices
|
|
|
|
### Configuration Management
|
|
- Use environment variables for configuration
|
|
- Store secrets in Docker secrets or external vaults
|
|
- Version control all configuration files
|
|
- Document all custom configurations
|
|
|
|
### Resource Management
|
|
- Set appropriate resource limits
|
|
- Monitor resource usage
|
|
- Plan for capacity growth
|
|
- Implement resource quotas
|
|
|
|
### Security Practices
|
|
- Use non-root users in containers
|
|
- Implement network segmentation
|
|
- Regular security updates
|
|
- Monitor for vulnerabilities
|
|
|
|
### Backup Strategies
|
|
- Automate backup processes
|
|
- Test restore procedures
|
|
- Implement versioned backups
|
|
- Store backups offsite
|
|
|
|
## Related Documentation
|
|
|
|
- **[Service Categories](20-Service-Categories.md)** - Available services overview
|
|
- **[Common Issues](40-Common-Issues.md)** - Troubleshooting guide
|
|
- **[Ansible Automation](50-Ansible-Automation.md)** - Automated deployments
|
|
- **[GitOps Guide](../GITOPS_DEPLOYMENT_GUIDE.md)** - GitOps workflows
|
|
|
|
---
|
|
|
|
*This deployment guide provides comprehensive instructions for deploying and managing services in the homelab environment using modern DevOps practices and tools.* |