DBAtlas · 数据库运维图谱

使用 Ansible 实现数据库自动化

症状

目标:使用 Ansible 使数据库安装、配置、用户和备份任务可重复且幂等(重复运行同一个 playbook 不会破坏系统)。

1. 定义 inventory 和组

在 inventory 中按数据库角色对服务器分组;将主库、副本和备份服务器放在不同的组中。使用静态 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. 安装正确的 collection(community.postgresql / community.mysql / community.mongodb)

Ansible core 现在将数据库模块放在独立的 collection 中发布;通过 requirements.yml 安装对应引擎的 collection。PostgreSQL 使用 community.postgresql(postgresql_db、postgresql_user、postgresql_privs),MySQL/MariaDB 使用 community.mysql(mysql_db、mysql_user),MongoDB 使用 community.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 模块渲染配置模板,并通过 'notify' 将其与 handler 关联。

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 中使用 mysql_user 的 priv 字段。

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 中打开 →