Автоматизация баз данных с 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_replica2. Установите нужную коллекцию (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.ymlMySQL
collections:
- name: community.mysqlMongoDB
collections:
- name: community.mongodb3. Шифруйте секреты с 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-pass4. Создайте структуру ролей (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.yml5. Пишите задачи установки и настройки идемпотентно
Установите пакет, инициализируйте каталог данных и сформируйте 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: restartedMySQL
- name: my.cnf template
ansible.builtin.template:
src: my.cnf.j2
dest: /etc/mysql/my.cnf
notify: restart mysql6. Определите задачи для баз данных и пользователей
Создавайте базу данных, пользователей и привилегии с помощью модулей; пароль берите из переменной 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: presentMySQL
- name: application user
community.mysql.mysql_user:
name: app_user
password: "{{ vault_app_password }}"
priv: 'appdb.*:ALL'
state: present7. Добавьте задачу бэкапа и расписание
Разверните скрипт бэкапа из шаблона и запланируйте его через 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"