覚書。
初めてAnsibleを触ってて少し躓いたところがあったので。

 

環境

・Ansible 2.3.0
・Percona server 5.7 (MySQL 5.7_

 

 

my.cnfを配置

Master用とSlave用のmy.cnfをリモート先へ送る。

- name: Copy my.cnf to master
copy: src="roles/dbtier/files/my.cnf.master" dest="/etc/percona-server.conf.d/mysqld.cnf" owner=root group=root mode=0644
when: hostname.stdout.find('db-master') == 0
- name: Copy my.cnf to slave
copy: src="roles/dbtier/files/my.cnf.slave" dest="/etc/percona-server.conf.d/mysqld.cnf" owner=root group=root mode=0644
when: hostname.stdout.find('db-slave') == 0

 

 

 

rootパスワードを取得

MySQL 5.7から/var/log/mysqld.logにパスワードが記載されているので
これを使って初期設定を行うらしい。

- name: Get percona server password
shell: cat /var/log/mysqld.log | grep "temporary password" | awk '{print $11}'
register: mysql_temp_pass

 

 

 

.my.cnfを/rootに設置

Ansibleのmysqlモジュールを使うために/root/.my.cnfにファイルを設置

- name: Copy .my.cnf file
template: src=temp_my.cnf.j2 dest=/root/.my.cnf owner=root group=root mode=0644

temp_my.cnf.j2

connect-expired-passwordが地味に大事

[client]
user=root
password={{ mysql_temp_pass.stdout }}
connect-expired-password

 

 

 

rootパスワードを設定する

一時的なパスワードでは覚えられないので変更します。
パスワードの要件が厳しくなって大文字小文字記号数字で8桁以上とかだった気がする(覚えてない)

- name: Set root password
mysql_user: name=root host=localhost password="{{ mysql_root_pass }}"
ignore_errors: True

 

 

 

新しい.my.cnfを/rootに設置

- name: Override .my.cnf file
template: src=new_my.cnf.j2 dest=/root/.my.cnf owner=root group=root mode=0644

new_my.cnf.j2

connect-expired-passwordを削除したバージョン

[client]
user=root
password={{ mysql_root_pass }}

 

 

 

anonymousユーザーを削除

- name: Remove all anonymous user
mysql_user: name='' host=localhost state=absent

 

 

 

レプリケーションユーザーを作成

- name: Semi-synchronous - Create replication user
mysql_user: >
name="{{ mysql_rep_user }}"
password="{{ mysql_rep_pass }}"
priv="{{ mysql_rep_priv }}"
host="{{ mysql_rep_host }}"
when: hostname.stdout.find('db-master') == 0

 

 

 

FlushコマンドってAnsibleじゃ使えないよね…?

- name: Semi-synchronous - Flush
shell: mysql --defaults-file=/root/.my.cnf -e "FLUSH PRIVILEGES";
shell: mysql --defaults-file=/root/.my.cnf -e "FLUSH TABLES WITH READ LOCK";
when: hostname.stdout.find('db-master') == 0

 

 

 

マスターDBからダンプして、スレーブにインポート

- name: Semi-synchronous - Dump all database
mysql_db: state=dump name=all target=/root/all_db_dump.sql
when: hostname.stdout.find('db-master') == 0
- name: Semi-synchronous - Send all_db_dump.sql
shell: sshpass -p '' scp -o StrictHostKeyChecking=no all_db_dump.sql [email protected]:~/
when: hostname.stdout.find('db-master') == 0
- name: Semi-synchronous - Stop slave if running
mysql_replication: mode=stopslave
when: hostname.stdout.find('db-slave') == 0
- name: Semi-synchronous - Import all_db_dump.sql
shell: mysql --defaults-file=/root/.my.cnf < /root/all_db_dump.sql
when: hostname.stdout.find('db-slave') == 0

 

 

 

マスターのファイル名とポジションの取得

ここが一番詰まった。
Ansibleは異なるホスト間で変数の参照ができないので
ファイル名とポジションの取得はスレーブのときに実行して、実際に実行するコマンドはマスター側で処理をする。

- name: Semi-synchronous - Get the master status
mysql_replication: mode=getmaster
delegate_to: "{{ mysql_master }}"
register: binlog
when: hostname.stdout.find('db-slave') == 0

 

Change master

- name: Semi-synchronous - Change the master
mysql_replication: >
mode=changemaster
master_host="{{ mysql_master }}"
master_user="{{ mysql_rep_user }}"
master_password="{{ mysql_rep_pass }}"
master_log_file={{ binlog.File }}
master_log_pos={{ binlog.Position }}
when: hostname.stdout.find('db-slave') == 0

 

 

 

スレーブの開始

- name: Semi-synchronous - Start slave
mysql_replication: mode=startslave
when: hostname.stdout.find('db-slave') == 0

 

 

 

スレーブの状況確認

Slave_IO_Running と Slave_SQL_RunningがどっちもYesであることを確認

- name: Semi-synchronous - Get Slave_IO_Running
shell: mysql --defaults-file=/root/.my.cnf -e "SHOW SLAVE STATUS\G" | grep "Slave_IO_Running" | awk '{print $2}'
register: SIOR
failed_when: SIOR.stdout not in ["Yes"]
when: hostname.stdout.find('db-slave') == 0
- name: Semi-synchronous - Get Slave_SQL_Running
shell: mysql --defaults-file=/root/.my.cnf -e "SHOW SLAVE STATUS\G" | grep "Slave_SQL_Running:" | awk '{print $2}'
register: SSQLR
failed_when: SSQLR.stdout not in ["Yes"]
when: hostname.stdout.find('db-slave') == 0

 

 

 

マスターでロックしていたのを解除

- name: Semi-synchnorous - Unlock tables
shell: mysql --defaults-file=/root/.my.cnf -e "UNLOCK TABLES"
when: hostname.stdout.find('db-master') == 0
- name: Semi-synchronous - Flush privileges
shell: mysql --defaults-file=/root/.my.cnf -e "FLUSH PRIVILEGES"
when: hostname.stdout.find('db-master') == 0