--- # 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