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を作れそうですね!!!