来源:芬达的数据库学习笔记
背景
dbops 是一款提供生产级别 MySQL 部署的 playbook 工具,欢迎提 issue。
下面是我的 dbops 的一个 ansible playbook 文件
[root@192-168-199-175 playbooks]# cat single_node.yml
- name: Deploy single-node MySQL server using binary installation
hosts: dbops_mysql
become: true
any_errors_fatal: true
vars_files:
- common_config.yml
vars:
...
mysql_port: 3307
[root@192-168-199-175 playbooks]# cat common_config.yml |grep mysql_port
mysql_port: 3306
我在一个 play 里的 vars_files、vars 里定义了相同的参数 mysql_port,你猜猜,最后这个变量的值应该是多少?
我有两个猜测:
那么,先载入 mysql_port: 3306,后载入 mysql_port: 3307,后者覆盖前者,最终 mysql_port == 3307。
就像 MySQL 一样,vars_files 可以看作是配置文件 my.cnf,而 vars 可以看作是读取 my.cnf 后的特殊设置。因此,后者也会覆盖前者,最终 mysql_port == 3307。
测试结果

答案是,我完全猜错了。
真相:见官方文档
https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_variables.html#variable-precedence-where-should-i-put-a-variable

在阅读官方文档后,我发现 Ansible 的变量设置确实有严格的加载顺序,先加载的变量会被后加载的覆盖。我们现在讨论的案例是,首先加载 vars,然后再加载 vars_files。
dbops 改进
我每个周末都会去发现 dbops 的问题,并且修复他。
原先,使用 dbops 一键部署 MySQL 时,仅需先后调整以下两个文件里的变量:
但我之前设计时完全考虑错了 vars_files 和 vars 的载入顺序,导致我编写 dbops 使用文档时可能会误导了用户,现在我打算重构 playbook 对于变量的载入顺序,并且修正使用文档。
我决定从结构和使用习惯两个方面对其进行修复和调整。修复的方法是将可能需要手动修改的特殊变量从 xxx.yml 文件移至 vars/var_xxx.yml 文件中。这种修复方式并不会影响用户的使用体验,用户依然可以根据需求修改两处的变量,只是之前采用直接在 playbook 的 xxx.yml 文件中修改特殊变量的方式,现在改为在 vars/var_xxx.yml 文件中进行修改。改动如下图:
我的修改会有三个收益:
1. 修复 bug 了。
现在 common_config.yml 只负责通用变量,vars/var_xxx.yml 负责特殊变量,如果有变量名相同时,后者覆盖前者。实际上,如果你熟练运用这个原理,那么在修改变量时,你甚至可以不去改动 common_config.yml,可以将其视为默认值,而将所有需要修改的参数和值都写入 vars/var_xxx.yml。使用起来更灵活。
2. 现在可以更方便地更新 dbops 了。
由于 dbops 经常需要修改代码以开发新功能,这难免会引入新的 bug。作者的时间和精力有限,无法对所有操作系统进行兼容性测试。因此,作者唯一能做的就是建立微信群方便沟通交流,并且尽快修复发现的 bug。在以前,我们需要在更新 dbops 时,备份 common_config.yml 和 xxx.yml 文件,更新完 dbops 后,再将 xxx.yml 文件中的 vars 部分粘贴回 xxx.yml,因为 xxx.yml 文件中的变量和程序逻辑是混在一起的,这很容易出错,导致程序代码逻辑或格式被破坏。现在,我已经将 xxx.yml 和 vars/var_xxx.yml 分离了,变量和程序代码已经分开,恢复变量文件不再那么麻烦,只需要备份和覆盖文件即可。
3. 我可以做默认值功能了
在修复 bug 并实现将 vars 移至 vars_file 之后,我可以实现 dbops 的默认值功能了。事实上,我提供的 common_config.yml 文件中已经包含了全量变量及其默认值。但如果你修改了参数,那么 dbops 原先的默认值是多少,你就无法确认了。因此,我将创建一个 default 目录,它是只读的,将存放用户修改前的 common_config.yml、vars/var_xxx.yml 等文件,它就是 dbops 变量的默认值,可以用于查询默认值。当然了,你可以当他是变量模版来使用。有了默认值,我就可以实现很多依赖于默认值的新功能。
例如,dbops 未来可以提供一个参数,用于禁止使用 dbops 默认密码部署 MySQL,他会判断你设置的密码和默认密码是否相同:
fcs_dbops_deny_default_password: 1 # 0表示false,1表示true
为什么要有这个参数?因为我真的很担心有人未修改密码,直接使用默认密码部署生产数据库,以产生安全问题。对于自测环境或无安全隐患的地方,可以设置 fcs_dbops_deny_default_password: 0,以便于测试。
修复后的效果
现在 xxx.yml 的加载顺序如下:
[root@192-168-199-175 playbooks]# cat master_slave.yml
...
vars_files:
- default/common_config.yml # 加载dbops默认的通用参数
- default/var_master_slave.yml # 加载dbops默认的xxx.yml特殊参数
- common_config.yml # 加载dbops客户定义的的通用参数
- vars/var_master_slave.yml # 加载dbops客户定义的xxx.yml特殊参数
...
[root@192-168-199-175 playbooks]# cat vars/var_master_slave.yml
# vars loading order: common_config -> this file
master_ip: 192.168.199.131
slave_ips:
- 192.168.199.132
- 192.168.199.133
sub_nets: 1%
mysql_port: 3309
[root@192-168-199-175 playbooks]# ansible-playbook master_slave.yml
...
TASK [Display the list of target hosts and additional information] ****************************************************************************************************************************************************************************************************
ok: [192.168.199.131] => {
"msg": [
"Hosts to be affected by Deploy master-slave MySQL server using binary installation: 192.168.199.131, 192.168.199.132, 192.168.199.133",
"MySQL port: 3309",
"MySQL version: 8.0.33",
"Roles to be executed: ../roles/pre_check_and_set, ../roles/mysql_server, ../roles/make_replication",
"Master IP: 192.168.199.131",
"Slave IPs: 192.168.199.132, 192.168.199.133"
]
}
...
由于 vars/var_master_slave.yml 是最后加载的,所以我部署的 MySQL 不是 3306 端口,而是 3309 端口了。
我已经做出了修改,你可以下载最新版本进行试用。你可以在 gitee 上看到我提交的 commit,以了解我修改了哪些内容。使用前请测试。
gitee 仓库地址:
https://gitee.com/fanderchan/dbops
如有功能开发需求或遇到 Bug,请提交问题(issue),您也可以扫描二维码加入我们的微信群,与我们一起探讨 dbops,以及 MySQL、openGauss、ansible 的相关话题。dbops 是高效的 playbook 工具集,保证绝对不收费。该微信群仅供学习交流使用,没有任何广告或商业活动。
