批量部署mysql 8.0须先拆inventory为mysql_masters/mysql_slaves组,动态生成my.cnf(log-bin/read_only等按组控制),用mysql用户执行mysqld --initialize-insecure并确保datadir属主和my.cnf权限正确,mysql_user模块需指定socket路径并预先切换root认证方式。

直接批量部署 MySQL 8.0,必须先拆 inventory 分组、动态生成配置、用 mysql 用户初始化数据目录——否则哪怕 Playbook 语法全对,也会卡在 ERROR 2003 (HY000): Can't connect to MySQL server 或 Seconds_Behind_Master: NULL。
inventory 必须物理拆成 mysql_masters / mysql_slaves 组
Ansible 不会猜哪台是主库。把所有节点塞进 [dbservers],再靠 when: inventory_hostname == 'db1' 切逻辑,扩容时改主机名就得同步修几十处任务和模板,极易漏。
正确做法是硬分组:
-
[mysql_masters]:只放 1 台(MGR 场景可多台),负责写入 + 生成 binlog -
[mysql_slaves]:可多台,只读 + 拉 relay log -
[mysql_arbiters](可选):仅跑 MGR 仲裁,不存数据
后续所有 my.cnf.j2 判断、mysql_user 权限设置、复制链路配置,都基于 group_names 做分支,不依赖主机名。
my.cnf.j2 模板里 log-bin / read_only / skip-slave-start 必须动态控制
MySQL 主从角色由配置加载时行为锁定,不是靠启动后 SET 临时切换的。写死或漏配,会导致从库被误写、主库复制线程自启、从库拉不到日志。
模板关键段落必须这样写:
{% if 'mysql_masters' in group_names %}
log-bin = /data/mysql/binlog/mysql-bin
binlog-format = ROW
skip-slave-start = 1
{% else %}
read_only = ON
relay-log = /data/mysql/relaylog/relay-bin
skip-slave-start = 0
{% endif %}
注意三点:
-
server-id必须全局唯一:主库用100,从库用201、202这类递增值,不能全写1 -
/etc/my.cnf文件权限必须是644,否则mysqld启动时报Failed to open config file,但日志不提示权限问题 -
skip-slave-start = 1在主库设为1,防止误启复制;从库必须设为0,否则START SLAVE不生效
mysqld --initialize-insecure 必须用 mysql 用户执行且 datadir 属主严格匹配
MySQL 8.0 废弃了 mysql_install_db,改用 mysqld --initialize-insecure。这个命令对用户和路径权限极其敏感:
- 必须用
mysql用户执行,不能用root直接跑,否则报Failed to find valid data directory -
datadir(如/data/mysql)需提前chown -R mysql:mysql /data/mysql - 命令必须显式指定
--user=mysql和--basedir,例如:mysqld --initialize-insecure --user=mysql --basedir=/usr/local/mysql --datadir=/data/mysql -
--initialize-insecure跳过生成临时 root 密码,适合自动化场景;若要密码初始化,得换--initialize并额外处理密码提取逻辑
mysql_user 模块连不上新实例?先检查 socket 连接和 root 认证方式
刚初始化的 MySQL 实例默认只允许 localhost socket 连接,且 Ubuntu 默认用 auth_socket 插件认证 root,不认密码。
Ansible 中 mysql_user 模块失败常见原因:
- 没加
login_unix_socket: /tmp/mysql.sock参数,模块默认走 TCP,连不上 - 没提前执行
ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'xxx',导致密码认证失败 - 没开
skip-grant-tables就想用空密码连,会被拒绝 - 远程连接未放开:配置文件中
bind-address仍是127.0.0.1,且防火墙未放行3306
建议初始化后立即用 command 模块执行一次本地 SQL 修改认证方式,再用 mysql_user 创建其他账号——别指望一个模块搞定所有认证路径。
真正卡住的地方往往不在 Playbook 写法,而在 datadir 属主是否为 mysql、/etc/my.cnf 权限是不是 644、以及 mysql_user 连接时有没有明确指定 socket 路径。这些细节不手动验证一遍,光看任务 success 状态毫无意义。











