Files
homelab-optimized/ansible/automation/playbooks/synology_backup_orchestrator.yml
Gitea Mirror Bot 5cdf36e545
Some checks failed
Documentation / Deploy to GitHub Pages (push) Has been cancelled
Documentation / Build Docusaurus (push) Has been cancelled
Sanitized mirror from private repository - 2026-04-05 12:11:15 UTC
2026-04-05 12:11:15 +00:00

261 lines
8.7 KiB
YAML

---
# Synology Backup Orchestrator
# Coordinates backups across Atlantis/Calypso with integrity verification
# Run with: ansible-playbook -i hosts.ini playbooks/synology_backup_orchestrator.yml --limit synology
- name: Synology Backup Orchestration
hosts: synology
gather_facts: yes
vars:
backup_retention_days: 30
critical_containers:
- "postgres"
- "mariadb"
- "gitea"
- "immich-server"
- "paperlessngx"
- "authentik-server"
- "vaultwarden"
backup_paths:
atlantis:
- "/volume1/docker"
- "/volume1/media"
- "/volume1/backups"
- "/volume1/documents"
calypso:
- "/volume1/docker"
- "/volume1/backups"
- "/volume1/development"
tasks:
- name: Check Synology system status
shell: |
echo "=== System Info ==="
uname -a
echo "=== Disk Usage ==="
df -h
echo "=== Memory Usage ==="
free -h
echo "=== Load Average ==="
uptime
register: system_status
- name: Display system status
debug:
msg: "{{ system_status.stdout_lines }}"
- name: Check Docker service status
shell: systemctl is-active docker
register: docker_status
failed_when: false
- name: Get running containers
shell: docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Image}}"
register: running_containers
become: yes
- name: Identify critical containers
shell: docker ps --filter "name={{ item }}" --format "{{.Names}}"
register: critical_container_check
loop: "{{ critical_containers }}"
become: yes
- name: Create backup directory structure
file:
path: "/volume1/backups/{{ item }}"
state: directory
mode: '0755'
loop:
- "containers"
- "databases"
- "configs"
- "logs"
become: yes
- name: Stop non-critical containers for backup
shell: |
# Get list of running containers excluding critical ones
critical_pattern="{{ critical_containers | join('|') }}"
docker ps --format "{{.Names}}" | grep -vE "($critical_pattern)" > /tmp/non_critical_containers.txt || true
# Stop non-critical containers
if [ -s /tmp/non_critical_containers.txt ]; then
echo "Stopping non-critical containers for backup..."
cat /tmp/non_critical_containers.txt | xargs -r docker stop
echo "Stopped containers:"
cat /tmp/non_critical_containers.txt
else
echo "No non-critical containers to stop"
fi
register: stopped_containers
when: stop_containers_for_backup | default(false) | bool
become: yes
- name: Backup Docker volumes
shell: |
backup_date=$(date +%Y%m%d_%H%M%S)
backup_file="/volume1/backups/containers/docker_volumes_${backup_date}.tar.gz"
echo "Creating Docker volumes backup: $backup_file"
tar -czf "$backup_file" -C /volume1/docker . 2>/dev/null || true
if [ -f "$backup_file" ]; then
size=$(du -h "$backup_file" | cut -f1)
echo "Backup created successfully: $backup_file ($size)"
else
echo "Backup failed"
exit 1
fi
register: volume_backup
become: yes
- name: Backup database containers
shell: |
backup_date=$(date +%Y%m%d_%H%M%S)
# Backup PostgreSQL databases
for container in $(docker ps --filter "ancestor=postgres" --format "{{.Names}}"); do
echo "Backing up PostgreSQL container: $container"
docker exec "$container" pg_dumpall -U postgres > "/volume1/backups/databases/${container}_${backup_date}.sql" 2>/dev/null || true
done
# Backup MariaDB databases
for container in $(docker ps --filter "ancestor=mariadb" --format "{{.Names}}"); do
echo "Backing up MariaDB container: $container"
docker exec "$container" mysqldump --all-databases -u root > "/volume1/backups/databases/${container}_${backup_date}.sql" 2>/dev/null || true
done
echo "Database backups completed"
register: database_backup
become: yes
- name: Backup container configurations
shell: |
backup_date=$(date +%Y%m%d_%H%M%S)
config_backup="/volume1/backups/configs/container_configs_${backup_date}.tar.gz"
# Find all docker-compose files and configs
find /volume1/docker -name "docker-compose.yml" -o -name "*.env" -o -name "config" -type d | \
tar -czf "$config_backup" -T - 2>/dev/null || true
if [ -f "$config_backup" ]; then
size=$(du -h "$config_backup" | cut -f1)
echo "Configuration backup created: $config_backup ($size)"
fi
register: config_backup
become: yes
- name: Restart stopped containers
shell: |
if [ -f /tmp/non_critical_containers.txt ] && [ -s /tmp/non_critical_containers.txt ]; then
echo "Restarting previously stopped containers..."
cat /tmp/non_critical_containers.txt | xargs -r docker start
echo "Restarted containers:"
cat /tmp/non_critical_containers.txt
rm -f /tmp/non_critical_containers.txt
fi
when: stop_containers_for_backup | default(false) | bool
become: yes
- name: Verify backup integrity
shell: |
echo "=== Backup Verification ==="
# Check volume backup
latest_volume_backup=$(ls -t /volume1/backups/containers/docker_volumes_*.tar.gz 2>/dev/null | head -1)
if [ -n "$latest_volume_backup" ]; then
echo "Volume backup: $latest_volume_backup"
tar -tzf "$latest_volume_backup" >/dev/null 2>&1 && echo "✓ Volume backup integrity OK" || echo "✗ Volume backup corrupted"
fi
# Check database backups
db_backup_count=$(ls /volume1/backups/databases/*.sql 2>/dev/null | wc -l)
echo "Database backups: $db_backup_count files"
# Check config backup
latest_config_backup=$(ls -t /volume1/backups/configs/container_configs_*.tar.gz 2>/dev/null | head -1)
if [ -n "$latest_config_backup" ]; then
echo "Config backup: $latest_config_backup"
tar -tzf "$latest_config_backup" >/dev/null 2>&1 && echo "✓ Config backup integrity OK" || echo "✗ Config backup corrupted"
fi
register: backup_verification
become: yes
- name: Clean old backups
shell: |
echo "Cleaning backups older than {{ backup_retention_days }} days..."
# Clean volume backups
find /volume1/backups/containers -name "docker_volumes_*.tar.gz" -mtime +{{ backup_retention_days }} -delete
# Clean database backups
find /volume1/backups/databases -name "*.sql" -mtime +{{ backup_retention_days }} -delete
# Clean config backups
find /volume1/backups/configs -name "container_configs_*.tar.gz" -mtime +{{ backup_retention_days }} -delete
echo "Cleanup completed"
register: backup_cleanup
become: yes
- name: Generate backup report
copy:
content: |
# Synology Backup Report - {{ inventory_hostname }}
Generated: {{ ansible_date_time.iso8601 }}
## System Status
```
{{ system_status.stdout }}
```
## Running Containers
```
{{ running_containers.stdout }}
```
## Backup Operations
### Volume Backup
```
{{ volume_backup.stdout }}
```
### Database Backup
```
{{ database_backup.stdout }}
```
### Configuration Backup
```
{{ config_backup.stdout }}
```
## Backup Verification
```
{{ backup_verification.stdout }}
```
## Cleanup Results
```
{{ backup_cleanup.stdout }}
```
## Critical Containers Status
{% for container in critical_containers %}
- {{ container }}: {{ 'Running' if container in running_containers.stdout else 'Not Found' }}
{% endfor %}
dest: "/tmp/synology_backup_{{ inventory_hostname }}_{{ ansible_date_time.epoch }}.md"
delegate_to: localhost
- name: Display backup summary
debug:
msg: |
Backup Summary for {{ inventory_hostname }}:
- Volume Backup: {{ 'Completed' if volume_backup.rc == 0 else 'Failed' }}
- Database Backup: {{ 'Completed' if database_backup.rc == 0 else 'Failed' }}
- Config Backup: {{ 'Completed' if config_backup.rc == 0 else 'Failed' }}
- Verification: {{ 'Passed' if backup_verification.rc == 0 else 'Failed' }}
- Report: /tmp/synology_backup_{{ inventory_hostname }}_{{ ansible_date_time.epoch }}.md