Files
michaelschiemer/deployment/ansible/README.md
Michael Schiemer 36ef2a1e2c
Some checks failed
🚀 Build & Deploy Image / Determine Build Necessity (push) Failing after 10m14s
🚀 Build & Deploy Image / Build Runtime Base Image (push) Has been skipped
🚀 Build & Deploy Image / Build Docker Image (push) Has been skipped
🚀 Build & Deploy Image / Run Tests & Quality Checks (push) Has been skipped
🚀 Build & Deploy Image / Auto-deploy to Staging (push) Has been skipped
🚀 Build & Deploy Image / Auto-deploy to Production (push) Has been skipped
Security Vulnerability Scan / Check for Dependency Changes (push) Failing after 11m25s
Security Vulnerability Scan / Composer Security Audit (push) Has been cancelled
fix: Gitea Traefik routing and connection pool optimization
- Remove middleware reference from Gitea Traefik labels (caused routing issues)
- Optimize Gitea connection pool settings (MAX_IDLE_CONNS=30, authentication_timeout=180s)
- Add explicit service reference in Traefik labels
- Fix intermittent 504 timeouts by improving PostgreSQL connection handling

Fixes Gitea unreachability via git.michaelschiemer.de
2025-11-09 14:46:15 +01:00

379 lines
11 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Ansible Deployment Configuration
This directory contains Ansible playbooks and configuration for deploying the Custom PHP Framework to production.
## Directory Structure
```
deployment/ansible/
├── ansible.cfg # Ansible configuration
├── inventory/
│ ├── production.yml # Production server inventory
│ └── local.yml # Local testing inventory
├── playbooks/
│ ├── deploy-update.yml # Deploy application updates
│ ├── system-maintenance.yml # Betriebssystem-Updates & Wartung
│ ├── rollback.yml # Rollback deployments
│ ├── setup-infrastructure.yml # Provision core stacks
│ ├── setup-production-secrets.yml # Deploy secrets
│ ├── setup-wireguard.yml # Setup WireGuard VPN server
│ ├── add-wireguard-client.yml # Add WireGuard client
│ ├── sync-code.yml # Git-based code sync
│ └── README-WIREGUARD.md # WireGuard documentation
├── scripts/ # Helper scripts for secrets & credentials
├── roles/ # Reusable roles (e.g. application stack)
├── secrets/
│ ├── .gitignore # Prevent committing secrets
│ └── production.vault.yml.example # Example vault file
└── templates/
├── application.env.j2 # Application stack environment
├── gitea-app.ini.j2 # Gitea configuration
├── minio.env.j2 # MinIO environment
├── monitoring.env.j2 # Monitoring stack environment
├── wireguard-client.conf.j2 # WireGuard client config
└── wireguard-server.conf.j2 # WireGuard server config
## Roles
Stack-spezifische Aufgaben liegen in `roles/` (z.B. `application`, `traefik`, `registry`). Playbooks wie `setup-infrastructure.yml` importieren diese Rollen direkt. Die Application-Rolle kann mit Variablen wie `application_sync_files=false` oder `application_compose_recreate="always"` konfiguriert werden (siehe `playbooks/deploy-update.yml` als Beispiel). Die neue `system`-Rolle hält Betriebssystem-Pakete aktuell und konfiguriert optionale Unattended-Upgrades bevor Docker-Stacks neu gestartet werden.
## Prerequisites
1. **Ansible Installed**:
```bash
pip install ansible
```
2. **SSH Access**:
- SSH key configured at `~/.ssh/production`
- Key added to production server's authorized_keys for `deploy` user
3. **Ansible Vault Password**:
- Create `.vault_pass` file in `secrets/` directory
- Add vault password to this file (one line)
- File is gitignored for security
- 📖 **Detaillierte Dokumentation:** [docs/guides/vault-password.md](../docs/guides/vault-password.md)
## Setup Instructions
### 1. Create Production Secrets
```bash
cd deployment/ansible/secrets
# Copy example file
cp production.vault.yml.example production.vault.yml
# Edit with your actual secrets
nano production.vault.yml
# Encrypt the file
ansible-vault encrypt production.vault.yml
# Enter vault password when prompted
```
### 2. Store Vault Password
```bash
# Create vault password file
echo "your-vault-password-here" > secrets/.vault_pass
# Secure the file
chmod 600 secrets/.vault_pass
```
**📖 Für detaillierte Informationen:** Siehe [docs/guides/vault-password.md](../docs/guides/vault-password.md)
### 3. Configure SSH Key
```bash
# Generate SSH key if needed
ssh-keygen -t ed25519 -f ~/.ssh/production -C "ansible-deploy"
# Copy public key to production server
ssh-copy-id -i ~/.ssh/production.pub deploy@94.16.110.151
```
## Running Playbooks
### Deploy Production Secrets
**First-time setup** - Deploy secrets to production server:
```bash
ansible-playbook playbooks/setup-production-secrets.yml \
--vault-password-file secrets/.vault_pass
```
### Deploy Application Update
**Automated via Gitea Actions** - Or run manually:
```bash
ansible-playbook playbooks/deploy-update.yml \
-e "image_tag=sha-abc123" \
-e "git_commit_sha=abc123" \
-e "deployment_timestamp=$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
-e "docker_registry_username=gitea-user" \
-e "docker_registry_password=your-registry-password"
```
### Rollback Deployment
**Rollback to previous version**:
```bash
ansible-playbook playbooks/rollback.yml
```
**Rollback to specific version**:
```bash
ansible-playbook playbooks/rollback.yml \
-e "rollback_to_version=2025-01-28T15-30-00"
```
### Setup WireGuard VPN
**First-time setup** - Install WireGuard VPN server:
```bash
ansible-playbook -i inventory/production.yml playbooks/setup-wireguard.yml
```
**Add a client**:
```bash
ansible-playbook -i inventory/production.yml playbooks/add-wireguard-client.yml \
-e "client_name=myclient"
```
Siehe [playbooks/README-WIREGUARD.md](playbooks/README-WIREGUARD.md) für detaillierte Anleitung.
### System Maintenance ausführen
Führt die `system`-Rolle aus, aktualisiert Paketquellen, führt OS-Upgrades durch und aktiviert optional Unattended-Upgrades.
```bash
ansible-playbook -i inventory/production.yml \
playbooks/system-maintenance.yml
```
Tipp: Mit `--check` lässt sich zunächst ein Dry-Run starten, um anstehende Updates zu prüfen.
## Ansible Vault Operations
### View Encrypted File
```bash
ansible-vault view secrets/production.vault.yml \
--vault-password-file secrets/.vault_pass
```
### Edit Encrypted File
```bash
ansible-vault edit secrets/production.vault.yml \
--vault-password-file secrets/.vault_pass
```
### Change Vault Password
```bash
ansible-vault rekey secrets/production.vault.yml \
--vault-password-file secrets/.vault_pass
```
### Decrypt File (Temporarily)
```bash
ansible-vault decrypt secrets/production.vault.yml \
--vault-password-file secrets/.vault_pass
# DO NOT COMMIT DECRYPTED FILE!
# Re-encrypt when done
ansible-vault encrypt secrets/production.vault.yml \
--vault-password-file secrets/.vault_pass
```
## Testing Playbooks
### Test with Check Mode (Dry Run)
```bash
ansible-playbook playbooks/deploy-update.yml \
--check \
-e "image_tag=test"
```
### Test Connection
```bash
ansible production -m ping
```
### Verify Inventory
```bash
ansible-inventory --list -y
```
### System Maintenance Dry Run
```bash
ansible-playbook -i inventory/production.yml \
playbooks/system-maintenance.yml \
--check
```
## Security Best Practices
1. **Never commit unencrypted secrets**
- `production.vault.yml` must be encrypted
- `.vault_pass` is gitignored
- Use `.example` files for documentation
2. **Rotate secrets regularly**
- Update vault file
- Re-run `setup-production-secrets.yml`
- Restart affected services
3. **Limit SSH key access**
- Use separate SSH key for Ansible
- Limit key to `deploy` user only
- Consider IP restrictions
4. **Vault password security**
- Store vault password in secure password manager
- Don't share via insecure channels
- Use different passwords for dev/staging/prod
## Troubleshooting
### Vault Decryption Failed
**Error**: `Decryption failed (no vault secrets were found)`
**Solution**:
```bash
# Verify vault password is correct
ansible-vault view secrets/production.vault.yml \
--vault-password-file secrets/.vault_pass
# If password is wrong, you'll need the original password to decrypt
```
### SSH Connection Failed
**Error**: `Failed to connect to the host`
**Solutions**:
```bash
# Test SSH connection manually
ssh -i ~/.ssh/production deploy@94.16.110.151
# Check SSH key permissions
chmod 600 ~/.ssh/production
chmod 644 ~/.ssh/production.pub
# Verify SSH key is added to server
ssh-copy-id -i ~/.ssh/production.pub deploy@94.16.110.151
```
### Docker Registry Authentication Failed
**Error**: `unauthorized: authentication required`
**Solution**:
```bash
# Verify registry credentials in vault file
ansible-vault view secrets/production.vault.yml \
--vault-password-file secrets/.vault_pass
# Test registry login manually on production server
docker login registry.michaelschiemer.de
```
### Service Not Starting
**Check service logs**:
```bash
# SSH to production server
ssh -i ~/.ssh/production deploy@94.16.110.151
# Check Docker Compose service logs
docker compose -f {{ app_stack_path }}/docker-compose.yml logs app
docker compose -f {{ app_stack_path }}/docker-compose.yml logs nginx
# Check stack status
docker compose -f {{ app_stack_path }}/docker-compose.yml ps
```
## CI/CD Integration
These playbooks are automatically executed by Gitea Actions workflows:
- **`.gitea/workflows/production-deploy.yml`** - Calls `deploy-update.yml` on push to main
- **`.gitea/workflows/update-production-secrets.yml`** - Calls `setup-production-secrets.yml` on manual trigger
- **`.gitea/workflows/system-maintenance.yml`** - Führt `system-maintenance.yml` geplant oder manuell aus, um Pakete aktuell zu halten
Vault password is stored as Gitea Actions secret: `ANSIBLE_VAULT_PASSWORD`
## Inventory Variables
All zentralen Variablen werden in `group_vars/production.yml` gepflegt und können bei Bedarf im Inventory überschrieben werden. Häufig verwendete Werte:
| Variable | Beschreibung | Standardwert |
|----------|--------------|--------------|
| `deploy_user_home` | Home-Verzeichnis des Deploy-Users | `/home/deploy` |
| `stacks_base_path` | Basispfad für Docker Compose Stacks | `/home/deploy/deployment/stacks` |
| `app_stack_path` | Pfad zum Application Stack | `/home/deploy/deployment/stacks/production` |
| `backups_path` | Ablageort für Deployment-Backups | `/home/deploy/deployment/backups` |
| `docker_registry` | Interner Registry-Endpunkt (lokal) | `localhost:5000` |
| `docker_registry_external` | Externer Registry-Endpunkt | `registry.michaelschiemer.de` |
| `app_domain` | Produktions-Domain | `michaelschiemer.de` |
| `health_check_url` | Health-Check Endpoint | `https://michaelschiemer.de/health` |
| `max_rollback_versions` | Anzahl vorgehaltener Backups | `5` |
| `system_update_packages` | Aktiviert OS-Paketupdates via `system`-Rolle | `true` |
| `system_apt_upgrade` | Wert für `apt upgrade` (z.B. `dist`) | `dist` |
| `system_enable_unattended_upgrades` | Aktiviert `unattended-upgrades` | `true` |
| `system_enable_unattended_reboot` | Steuert automatische Reboots nach Updates | `false` |
| `system_unattended_reboot_time` | Reboot-Zeitfenster (wenn aktiviert) | `02:00` |
| `system_enable_unattended_timer` | Aktiviert Systemd-Timer für apt | `true` |
| `system_enable_docker_prune` | Führt nach Updates `docker system prune` aus | `false` |
## Backup Management
Backups are automatically created before each deployment:
- **Location**: `/home/deploy/backups/`
- **Retention**: Last 5 versions kept
- **Contents**:
- `current_image.txt` - Previously deployed image
- `stack_status.txt` - Stack status before deployment
- `deployment_metadata.txt` - Deployment details
### List Available Backups
```bash
ssh -i ~/.ssh/production deploy@94.16.110.151 \
"ls -lh /home/deploy/backups/"
```
### Manual Backup
```bash
ansible-playbook playbooks/deploy-update.yml \
--tags backup \
-e "image_tag=current"
```
## Support
For issues with:
- **Playbooks**: Check this README and playbook comments
- **Vault**: See Ansible Vault documentation
- **Deployment**: Review Gitea Actions logs
- **Production**: SSH to server and check Docker logs