fix(ansible): 一主多从从库强制只读

- mysql-instance.cnf.j2 按 mysql_node_role=replica 注入 read-only/super-read-only,
  阻止业务直接写入从库导致主从数据分叉(复制线程与复制管理语句不受影响)
- 账号配置任务在从库上临时放开只读、配置完成后回锁,
  避免 cnf 只读拒绝 ALTER/CREATE USER;主库与 standalone 不受影响
This commit is contained in:
Hungerdream
2026-07-31 18:49:21 +08:00
parent 716e816a66
commit 454df86021
3 changed files with 30 additions and 0 deletions
+12
View File
@@ -452,15 +452,27 @@
EOF EOF
if ! /usr/bin/mysql --defaults-extra-file="$client_file" -e 'SELECT 1' >/dev/null 2>&1; then if ! /usr/bin/mysql --defaults-extra-file="$client_file" -e 'SELECT 1' >/dev/null 2>&1; then
cat >"$sql_file" <<'EOF' cat >"$sql_file" <<'EOF'
{% if topology == 'primary_replica' and inventory_hostname != mysql_primary_host_value %}
SET GLOBAL super_read_only = OFF;
SET GLOBAL read_only = OFF;
{% endif %}
ALTER USER 'root'@'localhost' IDENTIFIED BY '{{ mysql_root_password_value | replace("'", "''") }}'; ALTER USER 'root'@'localhost' IDENTIFIED BY '{{ mysql_root_password_value | replace("'", "''") }}';
EOF EOF
/usr/bin/mysql --protocol=socket --socket={{ mysql_run_dir }}/mysql.sock -uroot <"$sql_file" /usr/bin/mysql --protocol=socket --socket={{ mysql_run_dir }}/mysql.sock -uroot <"$sql_file"
fi fi
cat >"$sql_file" <<'EOF' cat >"$sql_file" <<'EOF'
{% if topology == 'primary_replica' and inventory_hostname != mysql_primary_host_value %}
SET GLOBAL super_read_only = OFF;
SET GLOBAL read_only = OFF;
{% endif %}
CREATE USER IF NOT EXISTS 'root'@'%' IDENTIFIED BY '{{ mysql_root_password_value | replace("'", "''") }}'; CREATE USER IF NOT EXISTS 'root'@'%' IDENTIFIED BY '{{ mysql_root_password_value | replace("'", "''") }}';
ALTER USER 'root'@'%' IDENTIFIED BY '{{ mysql_root_password_value | replace("'", "''") }}'; ALTER USER 'root'@'%' IDENTIFIED BY '{{ mysql_root_password_value | replace("'", "''") }}';
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' WITH GRANT OPTION; GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' WITH GRANT OPTION;
FLUSH PRIVILEGES; FLUSH PRIVILEGES;
{% if topology == 'primary_replica' and inventory_hostname != mysql_primary_host_value %}
SET GLOBAL read_only = ON;
SET GLOBAL super_read_only = ON;
{% endif %}
EOF EOF
/usr/bin/mysql --defaults-extra-file="$client_file" <"$sql_file" /usr/bin/mysql --defaults-extra-file="$client_file" <"$sql_file"
executable: /bin/bash executable: /bin/bash
+12
View File
@@ -355,15 +355,27 @@
EOF EOF
if ! /usr/bin/mysql --defaults-extra-file="$client_file" -e 'SELECT 1' >/dev/null 2>&1; then if ! /usr/bin/mysql --defaults-extra-file="$client_file" -e 'SELECT 1' >/dev/null 2>&1; then
cat >"$sql_file" <<'EOF' cat >"$sql_file" <<'EOF'
{% if topology == 'primary_replica' and inventory_hostname != mysql_primary_host_value %}
SET GLOBAL super_read_only = OFF;
SET GLOBAL read_only = OFF;
{% endif %}
ALTER USER 'root'@'localhost' IDENTIFIED BY '{{ mysql_root_password_value | replace("'", "''") }}'; ALTER USER 'root'@'localhost' IDENTIFIED BY '{{ mysql_root_password_value | replace("'", "''") }}';
EOF EOF
/usr/bin/mysql --protocol=socket --socket={{ mysql_run_dir }}/mysql.sock -uroot <"$sql_file" /usr/bin/mysql --protocol=socket --socket={{ mysql_run_dir }}/mysql.sock -uroot <"$sql_file"
fi fi
cat >"$sql_file" <<'EOF' cat >"$sql_file" <<'EOF'
{% if topology == 'primary_replica' and inventory_hostname != mysql_primary_host_value %}
SET GLOBAL super_read_only = OFF;
SET GLOBAL read_only = OFF;
{% endif %}
CREATE USER IF NOT EXISTS 'root'@'%' IDENTIFIED BY '{{ mysql_root_password_value | replace("'", "''") }}'; CREATE USER IF NOT EXISTS 'root'@'%' IDENTIFIED BY '{{ mysql_root_password_value | replace("'", "''") }}';
ALTER USER 'root'@'%' IDENTIFIED BY '{{ mysql_root_password_value | replace("'", "''") }}'; ALTER USER 'root'@'%' IDENTIFIED BY '{{ mysql_root_password_value | replace("'", "''") }}';
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' WITH GRANT OPTION; GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' WITH GRANT OPTION;
FLUSH PRIVILEGES; FLUSH PRIVILEGES;
{% if topology == 'primary_replica' and inventory_hostname != mysql_primary_host_value %}
SET GLOBAL read_only = ON;
SET GLOBAL super_read_only = ON;
{% endif %}
EOF EOF
/usr/bin/mysql --defaults-extra-file="$client_file" <"$sql_file" /usr/bin/mysql --defaults-extra-file="$client_file" <"$sql_file"
executable: /bin/bash executable: /bin/bash
+6
View File
@@ -53,6 +53,12 @@ binlog-expire-logs-seconds={{ mysql_binlog_expire_logs_seconds }} # binlog 过
gtid-mode=ON # 启用 GTID(全局事务标识符) gtid-mode=ON # 启用 GTID(全局事务标识符)
enforce-gtid-consistency=ON # 强制 GTID 一致性(确保复制安全) enforce-gtid-consistency=ON # 强制 GTID 一致性(确保复制安全)
relay-log={{ mysql_binlog_dir }}/relay-bin # 中继日志路径(从库重放 binlog 使用) relay-log={{ mysql_binlog_dir }}/relay-bin # 中继日志路径(从库重放 binlog 使用)
{% if mysql_node_role | default('') == 'replica' %}
# 从库强制只读:阻止业务直接写入从库导致主从数据分叉
# 复制线程与 CHANGE REPLICATION SOURCE 等复制管理语句不受影响
read-only=ON
super-read-only=ON
{% endif %}
{% endif %} {% endif %}
# ============================================================================= # =============================================================================