Ansible로 MySQL HA 설치하기

snooby·2022년 8월 17일
2

☁ Cloud

목록 보기
15/24
post-thumbnail

VM 구성

Ansible을 사용할 것이니 managed Node와 controll node 2개가 기본 필요하고,
MySQL HA를 구성하기 위해 controll node를 2개 구성하여 총 3개의 vm을 생성하였습니다.

우선 MySQL HA를 구성하기 위해
1. Ansible 설치 후 서버와 통신시키기
2. MySQL 설치 및 세팅
3. MySQL MHA 구성하기

로 단계를 나눠서 진행해보겠습니다.

1. Ansible 설치 후 서버와 통신시키기

Managed Node에 Ansible 설치

기본적으로 모든 서버의 python 버전이 일치해야하므로 일치하는지 확인합니다.

python3 --version

Managed Node 역할을 할 서버에만 Ansible을 설치합니다.

sudo apt install ansible

# 설치 확인
ansible --version

자신의 pc os에 따라 설치 방법이 다르니 이곳을 참고하여 자신의 운영체제에 맞게 설치하세요.

대부분의 작업이 Root 권한이 필요하여 sudo로 작업하게 됩니다.

sshpass 설치
앤서블 명령어 옵션중 --ask-pass 를 사용할 경우 sshpass 설치가 필요하다.

sudo apt install sshpass

ansible 세팅

/etc/ansible이 ansible의 홈입니다.

  1. ansible.cfg의 ansible 환경 설정 일부를 수정합니다.

  2. hosts에 ansible inventory로 스크립트 날릴 원격서버를 정의합니다.

  3. ansible 환경변수를 정의한 후

export ANSIBLE_HOME='/etc/ansible'
ehco $ANSIBLE_HOME

4. ssh 연결 키 세팅
host에 정의한 서버와 통신이 잘되는지 확인해봅니다.

ansible all -m ping

지금 진행해보면 다음처럼 연결이 안된다고 뜰 것입니다.

이는 서로 통신하는 데 필요한 key값이 없어서 그러한 것인데요.

key-gen으로 키값을 미리 생성 후 각 서버에 복사하여 해결해보도록 하겠습니다.

# 키 생성
ssh-keygen
# 계속 엔터를 누릅니다.

# 각 서버에 키 복사
scp $HOME/.ssh/id_rsa.pub 복사할 서버:id_rsa.pub
scp $HOME/.ssh/id_rsa.pub 복사할 서버:id_rsa.pub

이후 다시 접속 확인을 해보면 잘 접속되는 것을 확인할 수 있습니다.

이를 playbook으로 실행해봅시다.

---
- name: Test connectiong
  hosts: all
  tasks:
        - name: test connection
          ping:
ansible-playbook test-playbook.yml

잘 실행되는 것을 확인할 수 있습니다.

2. MySQL 설치 및 세팅

MySQL를 controll node에도 함께 설치하기 위해 앞선 과정에서 hosts파일에 controll node 서버 주소를 작성했습니다.

1. hosts 파일 그룹 서버 생성

이 2 controll node를 그룹으로 지정하여 쉽게 다루게 하기 위하여 hosts파일을 다시 수정해보겠습니다.
이 둘은 결국 MySQL-replica가 될 서버이므로 mysql-replicas라는 그룹명으로 지정하겠습니다.

2. 플레이북 생성

db-server-playbook.yml 파일에 MySQL 설치 세팅 시작 파일을 작성해보겠습니다.

---
- hosts: mysql-replicas 

  vars:
    mysql_root_password: "1234"
    mysql_mha_username: "mha_user"
    mysql_mha_password: "1234"

  tasks:
    - name: apt update
      become: yes
      apt: update_cache=yes

    - name: install mysql
      become: yes
      apt: name=mysql-server update_cache=yes cache_valid_time=3600 state=present

    - name: start up the mysql service
      service: name=mysql
               enabled=yes
               state=started
               #shell: "systemctl start mysql"

    - name: ensure mysql is enabled to run on startup
      service: name=mysql state=started enabled=true

    - name: Install required software
      apt: name={{ item }} state=present
      become: yes
      with_items:
        - python-mysqldb

    - name: find temporary pwd
      shell: "sudo grep 'temporary password' /var/log/mysqld.log | awk '{print $13}'"
      register: temporary_password

    - name: debug temporary pwd
      debug:
        msg: "{{ temporary_password.stdout }}"

    - name: check mha user created
      shell: sudo MYSQL_PWD={{ temporary_password.stdout }} mysql -u root --connect-expired-password -se "SELECT EXISTS(SELECT 1 FROM mysql.user WHERE user = '{{ mysql_mha_username }}')"
      register: CREATED

    - name: create mha/replicator user
      shell: sudo MYSQL_PWD={{ temporary_password.stdout }} mysql -u root -e "create user '{{ mysql_mha_username }}'@'%' identified by '{{ mysql_mha_password }}'"
      when: CREATED.stdout|int == 0

    - name: grant privileges to mha user
      shell: sudo MYSQL_PWD={{ temporary_password.stdout }} mysql -u root -e "grant all on *.* to '{{ mysql_mha_username }}'@'%'; flush privileges;"

    - name: create a new database
      mysql_db: name=testdb state=present login_user="{{ mysql_mha_username }}" login_password="{{ mysql_root_password }}"

    - name: add sample data to database
      copy: src=dump.sql dest=/tmp/dump.sql

전체 코드는 위와 같습니다.
한번 위 코드를 조각조각 잘라서 각 코드가 무엇을 의미하는지 설명해보겠습니다.

- hosts: mysql-replicas  

  vars:
    mysql_root_password: "1234"
    mysql_mha_username: "mha_user"
    mysql_mha_password: "1234"
  • hosts는 아래서 정의할 task들을 실행할 서버로 여기서는 mysql-replicas 그룹에 정의된 서버에서 실행할 예정이므로 그룹명을 작성하였습니다.
  • vars는 아래서 사용할 공통 변수를 정의하여 아래에서 매번 반복적으로 작성하지 않고 {{ 변수명 }} 이런식으로 사용할 수 있도록 합니다.
tasks:
    - name: apt update
      become: yes
      apt: update_cache=yes
  • 이제부터 tasks: 단위안에 이 파일이 진행할 업무(일)에 대해서 정의합니다.
    보시다싶이 tasks는 여러개 정의할 수 있으며 tasks에 해당하는 일은 tasks 들어쓰기 안에서 -name을 유니크하게 정의하고 작성하면됩니다.
  • 위의 태스크는 apt update 라는 이름을 가지며, 이름에서도 유추할 수 있듯 앞으로 apt 명령어로 실행을 하기위해 apt update를 시키는 task입니다.
  • become:yes는 sudo 권한을 가진다는 의미로 sudo 를 붙이고 명령어를 실행시키는 것과 같습니다.
  • apt:는 apt 명령어로 뭘 하겠다는 거고
  • update_cache=yes는 update 하라는 명령어 입니다.
- name: install mysql
      become: yes
      apt: name=mysql-server update_cache=yes cache_valid_time=3600 state=present
  • 궁극의 mysql 설치하는 task입니다.
    쭉 보면 알겠지만 name은 이 task가 어떤일을 하는지 명시적으로 알 수 있게 작성하는 것이 좋습니다. 디버깅도 편하고 실제 플레이북을 실행시키면 아래에서 볼 수 있지만 각 태스크 단계가 진행중, 잘 완료됨 등을 표시해주는데 task명을 통해 보여주기에 명시적으로 작성되어야 파악도 쉽습니다.
  • 여기도 sudo 권한으로 apt명령어를 사용하여 mysql-server라는 패키지명의 패키지를 update 진행하여 설치하라는 의미이고
  • state=present는 패키지를 설치하라는 의미입니다. installed와 동일한 의미로 사용됩니다.
  • cache_valid_time=3600 지정된 시간보다 오래걸릴 경우 리프레시하라는 의미입니다.
 - name: start up the mysql service
      service: name=mysql
               enabled=yes
               state=started
               #shell: "systemctl start mysql"
  • 설치한 mysql을 실행시킵니다.
    실행시켜서 사용자 생성, table생성 등을 진행하기 위함입니다.
- name: ensure mysql is enabled to run on startup
      service: name=mysql state=started enabled=true
  • 계속해서 startup 상태인지 확인합니다.
- name: Install required software
      apt: name={{ item }} state=present
      become: yes
      with_items:
        - python-mysqldb
  • 이후 과정을 진행하기 위해 필요한 패키지를 설치합니다.
    플레이북 작업이 추가되며 여러개의 패키지가 설치될 수도 있으니 with_itmes를 사용해 설치할 패키지목록을 리스트로 작성 후 {{ item }}을 사용하여 설치되게끔 작성하였습니다.
 - name: find temporary pwd
      shell: "sudo grep 'temporary password' /var/log/mysqld.log | awk '{print $13}'"
      register: temporary_password
- name: debug temporary pwd
      debug:
        msg: "{{ temporary_password.stdout }}"
  • 현재 유저 기본 root 유저의 비밀번호를 찾아 debug 태스크를 사용해 출력하게끔 한것입니다.
  • 리는 mha구성이 목적이므로 root사용자가 아니라 mha를 진행하기위한 사용자를 만들것이므로 필요없지만, 어떻게 비밀번호를 찾고, 플레이북 실행시 출력되게 하려면 debug를 사용하는 구나를 아는 데 목적을 둡시다.
- name: check mha user created
      shell: MYSQL_PWD={{ temporary_password.stdout }} mysql -u root --connect-expired-password -se "SELECT EXISTS(SELECT 1 FROM mysql.user WHERE user = '{{ mysql_mha_username }}')"
      register: CREATED
      become: yes
  • mha사용자를 만들기 전에 해당 사용자가 존재하는 경우는 만들면 안되니 존재하는지 확인해봅니다.
  • shell안에 실행시킬 쿼리문을 작성합니다. 실행 시 권한 문제가 생기지 않고 become:yes sudo권한으로 진행합니다.
  • 실행문 결과를 CREATED변수에 담습니다.
 - name: create mha/replicator user
      shell: MYSQL_PWD={{ temporary_password.stdout }} mysql -u root -e "create user '{{ mysql_mha_username }}'@'%' identified by '{{ mysql_mha_password }}'"
      when: CREATED.stdout|int == 0
      become: yes
  • 위에서 사용자가 없을 경우 사용자를 만들도록 합니다.
  • create시, user명@'localhost'대신 user명@'%'를 사용하면 외부에서도 접속이 가능합니다.
- name: grant privileges to mha user
      shell: MYSQL_PWD={{ temporary_password.stdout }} mysql -u root -e "grant all on *.* to '{{ mysql_mha_username }}'@'%'; flush privileges;"
      become: yes
  • 생성한 mha 사용자에게 모든 권한을 부여해줍니다.
- name: create a new database
      mysql_db: name=testdb state=present login_user="{{ mysql_mha_username }}" login_password="{{ mysql_root_password }}"
  • 방금 생성한 mha유저로 접속해서 testdb라는 db를 만듭니다.
 - name: add sample data to database
      copy: src=dump.sql dest=/tmp/dump.sql
  • testdb db 안에 테이블을 만들고 데이터를 넣는 쿼리 dump.sql을 사용해 데이터를 넣어줍니다.

dump.sql

CREATE TABLE IF NOT EXISTS test (           
  message varchar(255) NOT NULL         
  ) ENGINE=MyISAM DEFAULT CHARSET=utf8;         
  INSERT INTO test(message) VALUES('Ansible To Do List');
  INSERT INTO test(message) VALUES('Get ready');         
  INSERT INTO test(message) VALUES('Ansible is fun')
ansible-playbook db-server-playbook.yml

3. 확인

우리가 생성한 값들이 잘 들어가 있는지 확인해봅시다.

생성한 mha유저로 로그인

 mysql -u mha_user -p


비밀번호 입력을 원할 시, 우리가 생성 시 지정한 비밀번호 1234를 입력하면 로그인됩니다.

testdb 접속

use testdb

우리가 생성한 testdb가 잘 생성된것을 볼 수 있습니다.

table 목록 확인

table의 입력한 값 확인

dump.sql이 잘 실행되었음을 볼 수 있습니다.

여기까지 Control node와 manage node를 만들고 유저 생성 후 테이블 생성 데이터 입력까지 해보았습니다.
이제 MySQL MHA를 구성해봅시다.

3. MySQL MHA 구성하기

1. 환경 변수 초기세팅

사용할 변수값을 hosts파일안에 한번에 정의해두겠습니다.

profile
데이터를 가치있게 다루고 싶은 개발자 🐥

0개의 댓글