使用 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_replica2. 安装正确的 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.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 模块渲染配置模板,并通过 '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: 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 中使用 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: 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"