AnsibleでMySQLのリプリケーションする
この数日はインフラエンジニアやってます。
冪等性を保証するためにスピードが遅くなるのはスタートアップでは致命的かもしれませんが、万が一の再構築のケースを考えるとここで一生懸命作っておくのが将来のリスクに備えることかと思います。
時間を決めて、ここまでにうまくいかなかったら直で書くという選択が必要だと思ってます。
さて、MySQLのリプリケーションです。Master/Slaveですね。 負荷分散やサーバダウンに備えるためにもProductionでは必須です。
元はhttps://github.com/bennojoy/mysqlです。
私の環境でも試行錯誤して動くようになりました。
https://github.com/shohey1226/Ansible にあげておきますが、下記のような感じ。
---
- name: install mysql
yum: name={{ item }} state=latest
with_items:
- mysql
- mysql-server
- MySQL-python
- name: Copy the my.cnf file
template: src=my.cnf.j2 dest=/etc/my.cnf
notify:
- restart mysqld
- name: start mysqld process
service: name=mysqld state=started enabled=yes
- name: update mysql root password for all root accounts
mysql_user: name=root host={{ item }} password={{ mysql_root_db_pass }}
with_items:
- "{{ ansible_hostname }}"
- 127.0.0.1
- ::1
- localhost
when: ansible_hostname != 'localhost'
- name: copy .my.cnf file with root password credentials
template: src=.my.cnf.j2 dest=~/.my.cnf mode=0600
- name: ensure anonymous users are not in the database
mysql_user: name='' host={{ item }} state=absent
with_items:
- localhost
- name: remove the test database
mysql_db: name=test state=absent
- name: Create the database's
mysql_db: name={{ item.name }} state=present
with_items: mysql_db
when: mysql_db|lower() != 'none'
- name: Create the database users
mysql_user: name={{ item.name }} password={{ item.pass|default("foobar") }}
priv={{ item.priv|default("*.*:ALL") }} state=present host={{ item.host | default("localhost") }}
with_items: mysql_users
when: mysql_users|lower() != 'none'
- name: Create the replication users
mysql_user: name={{ item.name }} host="%" password={{ item.pass|default("foobar") }}
priv=*.*:"REPLICATION SLAVE" state=present
with_items: mysql_repl_user
when: mysql_repl_role == 'master'
- name: Check if slave is already configured for replication
mysql_replication: mode=getslave
ignore_errors: true
register: slave
when: mysql_repl_role == 'slave'
- name: Get the current master servers replication status
mysql_replication: mode=getmaster
delegate_to: "{{ mysql_repl_master }}"
register: repl_stat
when: slave|failed and mysql_repl_role == 'slave' and mysql_repl_master is defined
- name: Change the master in slave to start the replication
mysql_replication: mode=changemaster master_host={{ mysql_repl_master }} master_log_file={{ repl_stat.File }} master_log_pos={{ repl_stat.Position }} master_user={{ mysql_repl_user[0].name }} master_password={{ mysql_repl_user[0].pass }}
when: slave|failed and mysql_repl_role == 'slave' and mysql_repl_master is defined
これを使うためにはマスターは下記のように呼び出し、
---
- hosts: db-master-hosts
remote_user: root
roles:
- mysql
vars:
mysql_root_db_pass: root_pass
mysql_port: 3306
mysql_bind_address: "0.0.0.0"
mysql_db_id: 1
mysql_repl_role: master
mysql_db:
- name: hogehoge
replicate: yes
mysql_users:
- name: a_user
pass: a_user_pass
priv: "hogehoge.*:ALL"
host: app1
- name: a_user2
pass: a_user_pass2
priv: "hogehgoe.*:ALL"
host: app2
mysql_repl_user:
- name: repel_user
pass: repel_pass
スレーブは、
---
- hosts: db-slave-hosts
remote_user: root
roles:
- mysql
vars:
mysql_root_db_pass: root_pass
mysql_port: 3306
mysql_bind_address: "0.0.0.0"
mysql_db_id: 2
mysql_repl_role: slave
mysql_repl_master: master_host_name
mysql_users:
- name: a_user
pass: a_user_pass
priv: "hogehoge.*:ALL"
host: app1
- name: a_user2
pass: a_user_pass2
priv: "hogehoge.*:ALL"
host: app2
mysql_db:
- name: hogehoge
mysql_repl_user:
- name: repel_user
pass: repel_pass
これで必要に応じてガンガンSlaveを作れそうですね!!!