DBAtlas · Атлас эксплуатации баз данных

Автоматизация баз данных с Ansible

Симптом

Цель: сделать задачи установки, настройки, управления пользователями и резервного копирования баз данных воспроизводимыми и идемпотентными (повторный запуск того же playbook не ломает систему) с помощью Ansible.

1. Определите inventory и группы

Группируйте серверы в inventory по роли базы данных; размещайте primary-, replica- и backup-серверы в отдельных группах. Используйте статический INI/YAML inventory или динамический inventory для облака (aws_ec2, gcp_compute). Переменные групп размещайте в group_vars/, а переменные отдельных хостов — в host_vars/.

PostgreSQL

[pg_primary]
db1.example.local

[pg_replica]
db2.example.local

[postgres:children]
pg_primary
pg_replica

2. Установите нужную коллекцию (community.postgresql / community.mysql / community.mongodb)

Ansible core теперь поставляет модули для баз данных в отдельных коллекциях; установите коллекцию для вашего движка через requirements.yml. Используйте community.postgresql (postgresql_db, postgresql_user, postgresql_privs) для PostgreSQL, community.mysql (mysql_db, mysql_user) для MySQL/MariaDB и community.mongodb для MongoDB. На целевом хосте должен быть установлен соответствующий Python-клиент (psycopg2, PyMySQL, pymongo).

PostgreSQL

# requirements.yml
collections:
  - name: community.postgresql

# install:
ansible-galaxy collection install -r requirements.yml

MySQL

collections:
  - name: community.mysql

MongoDB

collections:
  - name: community.mongodb

3. Шифруйте секреты с Ansible Vault

Не оставляйте пароли баз данных, секреты репликации и учётные данные суперпользователя открытым текстом; храните их в зашифрованном файле переменных с ansible-vault. Расшифровывайте во время выполнения с --ask-vault-pass или --vault-password-file. Тогда секреты можно безопасно хранить в Git, а playbook остаётся идемпотентным.

PostgreSQL

ansible-vault create group_vars/postgres/vault.yml
# contents:
vault_pg_admin_password: "S3cret!"

# run:
ansible-playbook site.yml --ask-vault-pass

4. Создайте структуру ролей (roles/postgres, roles/mysql)

Создайте по одной роли на каждый движок и разделите логику по подкаталогам tasks/, defaults/, templates/ и handlers/. Такая структура повышает переиспользуемость: defaults/main.yml — для значений по умолчанию, templates/ — для шаблонов конфигурации jinja2, handlers/ — для логики «перезапуск, только если что-то изменилось». Каркас роли можно создать командой 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.yml

5. Пишите задачи установки и настройки идемпотентно

Установите пакет, инициализируйте каталог данных и сформируйте postgresql.conf/my.cnf из шаблона; при изменении конфигурации перезапускайте сервис через handler. Модули идемпотентны: уже установленный пакет не переустанавливается, а handler не срабатывает, если файл не изменился. Формируйте шаблон конфигурации модулем template и связывайте его с handler через '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: restarted

MySQL

- name: my.cnf template
  ansible.builtin.template:
    src: my.cnf.j2
    dest: /etc/mysql/my.cnf
  notify: restart mysql

6. Определите задачи для баз данных и пользователей

Создавайте базу данных, пользователей и привилегии с помощью модулей; пароль берите из переменной Vault. Модули community.postgresql идемпотентны: если пользователь/БД существует, они не создают его заново, а применяют только разницу. Привилегии выдавайте отдельно через postgresql_privs; в MySQL используется поле priv модуля 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: present

MySQL

- name: application user
  community.mysql.mysql_user:
    name: app_user
    password: "{{ vault_app_password }}"
    priv: 'appdb.*:ALL'
    state: present

7. Добавьте задачу бэкапа и расписание

Разверните скрипт бэкапа из шаблона и запланируйте его через ansible.builtin.cron; тогда задание бэкапа тоже управляется как код. Вынесите в переменные целевой каталог бэкапа, срок хранения и расписание. Модуль cron идемпотентен и определяет запись по 'name', поэтому повторный запуск не создаёт дубликат.

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"
Открыть в DBAtlas →