Automatización de bases de datos con Ansible
Síntoma
Objetivo: hacer que las tareas de instalación, configuración, usuarios y backup de bases de datos sean repetibles e idempotentes (volver a ejecutar el mismo playbook no rompe el sistema) con Ansible.
1. Definir el inventario y los grupos
Agrupe los servidores en el inventario por rol de base de datos; coloque los servidores primarios, réplicas y de backup en grupos separados. Use un inventario estático INI/YAML o un inventario dinámico para la nube (aws_ec2, gcp_compute). Coloque las variables de grupo en group_vars/ y las específicas de cada host en host_vars/.
PostgreSQL
[pg_primary]
db1.example.local
[pg_replica]
db2.example.local
[postgres:children]
pg_primary
pg_replica2. Instalar la colección correcta (community.postgresql / community.mysql / community.mongodb)
Ansible core ahora distribuye los módulos de bases de datos en colecciones separadas; instale la colección de su motor mediante requirements.yml. Use community.postgresql (postgresql_db, postgresql_user, postgresql_privs) para PostgreSQL, community.mysql (mysql_db, mysql_user) para MySQL/MariaDB y community.mongodb para MongoDB. El cliente Python correspondiente (psycopg2, PyMySQL, pymongo) debe estar instalado en el host de destino.
PostgreSQL
# requirements.yml
collections:
- name: community.postgresql
# install:
ansible-galaxy collection install -r requirements.ymlMySQL
collections:
- name: community.mysqlMongoDB
collections:
- name: community.mongodb3. Cifrar los secretos con Ansible Vault
No deje en texto plano las contraseñas de la base de datos, los secretos de replicación ni las credenciales de superusuario; guárdelos en un archivo de variables cifrado con ansible-vault. Descifre en tiempo de ejecución con --ask-vault-pass o --vault-password-file. Así los secretos pueden guardarse de forma segura en Git y el playbook sigue siendo idempotente.
PostgreSQL
ansible-vault create group_vars/postgres/vault.yml
# contents:
vault_pg_admin_password: "S3cret!"
# run:
ansible-playbook site.yml --ask-vault-pass4. Configure la estructura de roles (roles/postgres, roles/mysql)
Cree un rol por motor y divida la lógica en las subcarpetas tasks/, defaults/, templates/ y handlers/. Esta estructura mejora la reutilización: defaults/main.yml para los valores predeterminados, templates/ para las plantillas de configuración jinja2, handlers/ para la lógica de 'reiniciar solo si algo cambió'. Puede generar el esqueleto del rol con ansible-galaxy init roles/postgres.
PostgreSQL
ansible-galaxy init roles/postgres
# roles/postgres/
# defaults/main.yml
# tasks/main.yml
# templates/postgresql.conf.j2
# handlers/main.yml5. Escriba tareas de instalación y configuración idempotentes
Instale el paquete, inicialice el directorio de datos y genere postgresql.conf/my.cnf a partir de una plantilla; reinicie el servicio mediante un handler cuando cambie la configuración. Los módulos son idempotentes: un paquete ya instalado no se reinstala, y el handler no se dispara si el archivo no cambió. Genere la plantilla de configuración con el módulo template y vincúlela al handler con 'notify'.
PostgreSQL
- name: postgresql.conf template
ansible.builtin.template:
src: postgresql.conf.j2
dest: /etc/postgresql/16/main/postgresql.conf
notify: restart postgresql
# handlers/main.yml
- name: restart postgresql
ansible.builtin.service:
name: postgresql
state: restartedMySQL
- name: my.cnf template
ansible.builtin.template:
src: my.cnf.j2
dest: /etc/mysql/my.cnf
notify: restart mysql6. Defina las tareas de base de datos y usuarios
Cree la base de datos, los usuarios y los privilegios con módulos; tome la contraseña de una variable de Vault. Los módulos community.postgresql son idempotentes: si el usuario/la BD existe, no lo recrean, solo aplican la diferencia. Otorgue los privilegios por separado con postgresql_privs; en MySQL se usa el campo priv de mysql_user.
PostgreSQL
- name: application database
community.postgresql.postgresql_db:
name: appdb
state: present
- name: application user
community.postgresql.postgresql_user:
name: app_user
password: "{{ vault_app_password }}"
db: appdb
state: presentMySQL
- name: application user
community.mysql.mysql_user:
name: app_user
password: "{{ vault_app_password }}"
priv: 'appdb.*:ALL'
state: present7. Agregue la tarea de backup y su programación
Despliegue el script de backup desde una plantilla y prográmelo con ansible.builtin.cron; así el job de backup también se gestiona como código. Convierta en variables el directorio destino del backup, el periodo de retención y la programación. El módulo cron es idempotente e identifica la entrada por 'name', por lo que volver a ejecutarlo no la duplica.
PostgreSQL
- name: nightly backup (cron)
ansible.builtin.cron:
name: "pg dump nightly"
minute: "0"
hour: "2"
job: "pg_dump -Fc appdb > /backup/appdb_$(date +\\%F).dump"