Automatiza la Recuperación ante Desastres: Un Playbook de Ansible para Disaster Recovery

Automatiza la Recuperación ante Desastres: Un Playbook de Ansible para Disaster Recovery

¿Estás preparado para una caída imprevista de tus servicios? Hoy te traigo un playbook de Ansible que automatiza la recuperación ante desastres (Disaster Recovery) en servidores Linux, restaurando backups, reconfigurando servicios críticos y asegurando el mínimo tiempo de inactividad. Es un proyecto perfecto para quienes buscan potenciar la resiliencia de su infraestructura on-premise o en la nube. ¡Vamos con el playbook y todos sus detalles!

¿Por qué automatizar la recuperación ante desastres con Ansible?

  • Minimiza el tiempo de inactividad: Automatiza todos los pasos necesarios tras una caída o ataque, desde la provisión hasta el arranque de servicios[3].
  • Reduce errores humanos: Al definir un proceso repetible y probado, previenes fallos en momentos de crisis.
  • Fácil adaptación a cambios en la infraestructura: Solo ajustas variables e inventarios frente a nuevos entornos o topologías.

Este playbook cubre:

  • Provisión de un nuevo servidor de respaldo en la nube (ejemplo con AWS EC2).
  • Restauración de backups (archivos, bases de datos).
  • Configuración de parámetros de red y reglas de firewall.
  • Arranque y prueba de servicios críticos (web, base de datos, correo, etc.).

Ideal para tener en tu mochila de herramientas DevOps y olvidarte del pánico cuando todo parece perdido.

Playbook completo: disaster_recovery.yml

Ajusta los vars y el inventario a tu entorno (ejemplo con AWS para restauración de un servidor web + BBDD):

---
- name: Recuperación ante Desastres (Disaster Recovery)
  hosts: localhost
  gather_facts: no
  vars:
    aws_region: us-east-1
    instance_type: t2.micro
    ami_id: "ami-xxxxxxxx"
    key_name: "mi-llave-aws"
    security_group: "mi-grupo-seguridad"
    subnet_id: "subnet-xxxxxxx"
    backup_archive_url: "https://tu-bucket/backup.tar.gz"
    db_backup_url: "https://tu-bucket/backup.sql.gz"
    new_hostname: "servidor-respaldo"
    dns_zone: "ejemplo.com"
    dns_record: "www"
    app_user: "deploy"
    app_dir: "/srv/www"
    services:
      - nginx
      - mysql

  tasks:

    - name: Lanzar nueva instancia EC2 para recuperación
      amazon.aws.ec2_instance:
        name: disaster-recovery-instance
        key_name: "{{ key_name }}"
        vpc_subnet_id: "{{ subnet_id }}"
        instance_type: "{{ instance_type }}"
        image_id: "{{ ami_id }}"
        region: "{{ aws_region }}"
        security_group: "{{ security_group }}"
        wait: true
      register: ec2

    - name: Esperar a que la instancia esté accesible por SSH
      ansible.builtin.wait_for:
        host: "{{ ec2.instance.public_ip_address }}"
        port: 22
        timeout: 300

    - name: Añadir la nueva instancia al inventario dinámicamente
      add_host:
        name: recovery_target
        ansible_host: "{{ ec2.instance.public_ip_address }}"
        ansible_user: ubuntu

    - name: Restaurar archivos de backup en el host de recuperación
      hosts: recovery_target
      gather_facts: yes
      tasks:
        - name: Descargar y descomprimir backup de archivos
          ansible.builtin.unarchive:
            src: "{{ backup_archive_url }}"
            dest: "{{ app_dir }}"
            remote_src: yes

        - name: Descargar y restaurar backup de base de datos
          ansible.builtin.get_url:
            url: "{{ db_backup_url }}"
            dest: /tmp/backup.sql.gz

        - name: Descomprimir backup SQL
          ansible.builtin.shell: gunzip /tmp/backup.sql.gz
          args:
            creates: /tmp/backup.sql

        - name: Restaurar la base de datos
          community.mysql.mysql_db:
            state: import
            target: /tmp/backup.sql
            login_user: root
            login_password: "{{ lookup('env','DB_ROOT_PASSWORD') }}"

        - name: Establecer hostname a la nueva máquina
          ansible.builtin.hostname:
            name: "{{ new_hostname }}"

        - name: Configurar y asegurar firewall
          ansible.builtin.iptables:
            chain: INPUT
            protocol: tcp
            destination_port: [80, 443]
            jump: ACCEPT

        - name: Arrancar servicios críticos
          ansible.builtin.service:
            name: "{{ item }}"
            state: started
            enabled: yes
          loop: "{{ services }}"

        - name: Actualizar DNS para que apunte al nuevo servidor
          community.general.route53:
            zone: "{{ dns_zone }}"
            record: "{{ dns_record }}"
            type: A
            value: "{{ ansible_default_ipv4.address }}"
            state: present
            overwrite: true

        - name: Verificar acceso HTTP a la web restaurada
          ansible.builtin.uri:
            url: "http://{{ ansible_default_ipv4.address }}"
            status_code: 200
    


¿Cómo ejecutar este playbook?

  1. Agrega tus variables reales en la sección de vars (¡no subas tus credenciales a GitHub!).
  2. Necesitas tener los roles y collections de amazon.aws, community.mysql y community.general instaladas (ansible-galaxy collection install cada una).
  3. Accede con tu usuario AWS con permisos para lanzar instancias y modificar DNS.
  4. Lanza el playbook con:
    ansible-playbook disaster_recovery.yml

Consejos extra y troubleshooting

  • Comprueba las quotas de tu cuenta de nube antes de una crisis; ¡no te frenes por límites imprevistos!
  • Puedes probar el playbook con ambientes de staging antes de una emergencia real.
  • Si algún paso falla, ejecuta con -vvv para depurar la causa exacta. Usar --start-at-task puede ahorrar mucho tiempo en la corrección de errores.
  • No olvides automatizar la rotación y el almacenamiento seguro de tus backups.

¡Con este proyecto tienes un arranque potente en automatización de planes de contingencia! Diversifica tus pruebas y ajústalo a tus servicios más críticos. Si tienes dudas o lo adaptas a otros entornos (Azure, GCP...), ¡déjalo en los comentarios!

Avatar

Por Mid