- Ansible을 이용한 시스템 구성관리(1) – Vagrant를 이용한 테스트 가상환경 만들기
- Ansible을 이용한 시스템 구성관리(2) – ansible로 nginx 설치 – roles, handler, template, vars
- Ansible을 이용한 시스템 구성관리(3) – ansible로 mysql(mariadb) 설치 자동화
- Ansible을 이용한 시스템 구성관리(4) – wordpress (nginx+mariadb+php) 설치 자동화
이번장에서는 ansible을 이용하여 centos7기반에 database 설치를 자동화 해보겠습니다. centos7부터는 기본 database가 mariadb로 변경되었습니다. 따라서 yum install mysql 명령을 통해 database를 설치해도 mariadb가 설치됩니다. 사용자 입장에서는 mysql과 mariadb는 거의 차이가 없으므로 동일한 db로 봐도 무방합니다. 실습에서도 mysql과 mariadb를 따로 구분하지 않고 playbook을 작성해 보겠습니다.
엔서블 서버에 접속
$ vagrant ssh ansible-server
ansible-galaxy로 mysql role 생성
ansible-galaxy명령으로 ansible 기본 디렉토리 구조를 생성합니다.
$ cd roles $ ang init mysql - mysql was created successfully $ tree mysql mysql |-- README.md |-- defaults | `-- main.yml |-- files |-- handlers | `-- main.yml |-- meta | `-- main.yml |-- tasks | `-- main.yml |-- templates |-- tests | |-- inventory | `-- test.yml `-- vars `-- main.yml
db 설치 playbook 작성
$ vi /roles/mysql/install_db.yml
dbservers에 속한 서버들에 mysql 설치 명령을 수행합니다. vars 하위의 변수정보와 install.yml task를 조합하여 실행되도록 아래와 같이 작성합니다. 이때 명령이 sudo권한으로 실행되도록 become:yes를 설정합니다.
--- - hosts: dbservers become: yes vars_files: - vars/main.yml tasks: - include: tasks/install.yml
설치 환경 변수 작성
mysql 설치시 사용할 변수 정보를 아래와 같이 작성합니다. 설정한 변수 정보는 playbook 작성시 또는 jinja2 template파일 작성시 참조하여 사용할 수 있습니다.
$ vi /roles/mysql/vars/main.yml
--- # vars file for mysql mysql_collation: utf8mb4_unicode_ci mysql_encoding: utf8mb4 mysql_bind_address: 0.0.0.0 mysql_max_connections: 200 mysql_root_password: cjstk1 mysql_user_db_name: wordpress mysql_user: wordpress mysql_user_password: wordpress123!
DB 설치 task 작성
- epel 저장소 업데이트
- mariadb-server 설치
- mysql support library 설치
- my.cnf 파일 템플릿 적용
- mariadb 시작
- root 패스워드 및 권한 수정
- test database 삭제
- 신규 database 생성
- 익명 user 삭제
- 신규 user 작성 및 권한 수정
task에서 mysql 설치시 이미 정의된 모듈을 사용하였는데 자세한 사용법은 아래 링크에서 확인 가능합니다.
mysql_db module
https://docs.ansible.com/ansible/latest/modules/mysql_db_module.html
state 종류
- present – DB를 설치합니다.
- absent – DB를 삭제합니다.
- dump – DB 데이터를 dump합니다.
- import – DB 데이터를 import합니다.
mysql_user module
https://docs.ansible.com/ansible/latest/modules/mysql_user_module.html
state 종류
- present – user를 추가합니다.
- absent – user를 삭제합니다.
$ vi /roles/mysql/tasks/install.yml
--- - name: install epel-release action: "{{ ansible_pkg_mgr }} name=epel-release state=latest" - name: install mysql server action: "{{ ansible_pkg_mgr }} name=mariadb-server state=present" - name: install python mysql support library action: "{{ ansible_pkg_mgr }} name=MySQL-python state=latest" - name: copy my.cnf file template: src=my.cnf.j2 dest=/etc/my.cnf mode=0600 - name: start mysql server action: service name=mariadb state=started enabled=true - name: update mysql root password mysql_user: login_user: root login_password: "{{ mysql_root_password }}" name: root host: "{{ item }}" password: "{{ mysql_root_password }}" check_implicit_admin: yes priv: "*.*:ALL,GRANT" with_items: - "{{ ansible_hostname }}" - 127.0.0.1 - ::1 - localhost - name: remove test db mysql_db: login_user: root login_password: "{{ mysql_root_password }}" db: test state: absent - name: create a new db mysql_db: login_user: root login_password: "{{ mysql_root_password }}" name: "{{ mysql_user_db_name }}" collation: "{{ mysql_collation }}" encoding: "{{ mysql_encoding }}" state: present - name: delete anonymouse user mysql_user: login_user: root login_password: "{{ mysql_root_password }}" name: "" host_all: yes state: absent - name: create a new user mysql_user: login_user: root login_password: "{{ mysql_root_password }}" name: "{{ mysql_user }}" password: "{{ mysql_user_password }}" priv: "{{ mysql_user_db_name }}.*:ALL,GRANT" host: "%" state: present
.my.cnf jinja 파일 작성
실습에서는 my.cnf 기본 설정을 거의 변경없이 사용합니다. 예제에서는 bind-address, max-connection 값을 유동적으로 설정해 보기 위해 변수 처리하였습니다.
$ vi /roles/mysql/templates/my.cnf.j2
[client] port = 3306 socket = /var/run/mysqld/mysqld.sock [mysqld_safe] socket = /var/run/mysqld/mysqld.sock nice = 0 [mysqld] user = mysql pid-file = /var/run/mysqld/mysqld.pid socket = /var/run/mysqld/mysqld.sock port = 3306 basedir = /usr datadir = /var/lib/mysql tmpdir = /tmp lc_messages_dir = /usr/share/mysql lc_messages = en_US skip-external-locking bind-address = {{ mysql_bind_address }} max_connections = {{ mysql_max_connections }} connect_timeout = 5 wait_timeout = 600 max_allowed_packet = 16M thread_cache_size = 128 sort_buffer_size = 4M bulk_insert_buffer_size = 16M tmp_table_size = 32M max_heap_table_size = 32M # * InnoDB default_storage_engine = InnoDB # you can't just change log file size, requires special procedure #innodb_log_file_size = 50M innodb_buffer_pool_size = 256M innodb_log_buffer_size = 8M innodb_file_per_table = 1 innodb_open_files = 400 innodb_io_capacity = 400 innodb_flush_method = O_DIRECT
playbook 실행
$ cd /roles/mysql $ anp install_db.yml PLAY [dbservers] *********************************************************************************************************************************************** TASK [Gathering Facts] ***************************************************************************************************************************************** ok: [192.168.1.2] TASK [install epel-release] ************************************************************************************************************************************ changed: [192.168.1.2] TASK [install mysql server] ************************************************************************************************************************************ changed: [192.168.1.2] TASK [install python mysql support library] ******************************************************************************************************************** changed: [192.168.1.2] TASK [copy my.cnf file] **************************************************************************************************************************************** changed: [192.168.1.2] TASK [start mysql server] ************************************************************************************************************************************** changed: [192.168.1.2] TASK [update mysql root password] ****************************************************************************************************************************** changed: [192.168.1.2] => (item=ansible-client002) changed: [192.168.1.2] => (item=127.0.0.1) changed: [192.168.1.2] => (item=::1) changed: [192.168.1.2] => (item=localhost) TASK [remove test db] ****************************************************************************************************************************************** changed: [192.168.1.2] TASK [create a new db] ***************************************************************************************************************************************** changed: [192.168.1.2] TASK [delete anonymouse user] ********************************************************************************************************************************** changed: [192.168.1.2] TASK [create a new user] *************************************************************************************************************************************** changed: [192.168.1.2] PLAY RECAP ***************************************************************************************************************************************************** 192.168.1.2 : ok=11 changed=10 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
mariadb 설치 확인
client서버에 접속하여 mysql 프로세스를 확인하고 root 계정으로 로그인하면 생성한 wordpress 계정 및 신규 database를 확인할 수 있습니다. database 정보에서는 test database가 삭제되었고 user 정보에서는 anonymous 유저가 삭제된것을 확인 할수 있습니다. 또한 root유저로는 외부에서 db접속이 불가능하고 신규로 생성한 wordpress유저만 외부에서 접근 가능하도록 세팅된것을 확인할 수 있습니다.
이렇게 설정하는 이유는 root유저의 경우 database의 모든 권한을 가지고 있기 때문에 외부에 노출되면 해킹이나 권한 남용의 위험성이 있어서입니다. 이를 막기 위해 제한된 권한을 가진 user를 새로 생성하여 서비스에서 사용하도록 설정한 것입니다.
$ vagrant ssh ansible-client002 $ ps -ef | grep mysql mysql 8591 1 0 03:19 ? 00:00:00 /bin/sh /usr/bin/mysqld_safe --basedir=/usr mysql 8753 8591 0 03:19 ? 00:00:00 /usr/libexec/mysqld --basedir=/usr --datadir=/var/lib/mysql --plugin-dir=/usr/lib64/mysql/plugin --log-error=/var/log/mariadb/mariadb.log --pid-file=/var/run/mariadb/mariadb.pid --socket=/var/lib/mysql/mysql.sock $ mysql -u root -p Enter password: Welcome to the MariaDB monitor. Commands end with ; or \g. Your MariaDB connection id is 17 Server version: 5.5.64-MariaDB MariaDB Server Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. MariaDB [(none)]> show databases; +--------------------+ | Database | +--------------------+ | information_schema | | mysql | | performance_schema | | wordpress | +--------------------+ 4 rows in set (0.00 sec) MariaDB [(none)]> use mysql Reading table information for completion of table and column names You can turn off this feature to get a quicker startup with -A Database changed MariaDB [mysql]> select user, host from user; +-----------+-------------------+ | user | host | +-----------+-------------------+ | wordpress | % | | root | 127.0.0.1 | | root | ::1 | | root | ansible-client002 | | root | localhost | +-----------+-------------------+ 6 rows in set (0.00 sec)
mysql 삭제 playbook 작성
dbservers에 속한 서버들에 mysql 삭제 명령을 수행합니다. vars하위의 변수정보와 remove.yml task를 조합하여 작업을 수행합니다. 이때 명령어는 sudo권한으로 실행됩니다.( become:yes )
$ vi /roles/mysql/remove_db.yml
--- - hosts: dbservers become: yes vars_files: - vars/main.yml tasks: - include: tasks/remove.yml
DB삭제 task 작성
- epel 저장소 업데이트
- 생성한 databases 삭제
- mariadb-server 삭제
- mysql support library 삭제
$ vi /roles/mysql/tasks/remove.yml
--- - name: install epel-release action: "{{ ansible_pkg_mgr }} name=epel-release state=latest" - name: delete databases mysql_db: login_user: root login_password: "{{ mysql_root_password }}" name: "{{ mysql_user_db_name }}" state: absent - name: remove mysql server action: "{{ ansible_pkg_mgr }} name=mariadb-server state=absent" - name: remove python mysql support library action: "{{ ansible_pkg_mgr }} name=MySQL-python state=absent"
playbook 실행
$ cd /roles/mysql $ anp remove_db.yml
$ anp remove_db.yml PLAY [dbservers] *********************************************************************************************************************************************** TASK [Gathering Facts] ***************************************************************************************************************************************** ok: [192.168.1.2] TASK [install epel-release] ************************************************************************************************************************************ changed: [192.168.1.2] TASK [delete databases] **************************************************************************************************************************************** changed: [192.168.1.2] TASK [remove mysql server] ************************************************************************************************************************************* changed: [192.168.1.2] TASK [remove python mysql support library] ********************************************************************************************************************* changed: [192.168.1.2] PLAY RECAP ***************************************************************************************************************************************************** 192.168.1.2 : ok=5 changed=4 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
mysql 삭제 확인
vagrant로 클라이언트 서버에 접속하여 mysql 프로세스를 확인하면 프로세스가 존재하지 않는것을 확인 할 수 있습니다.
$ vagrant ssh ansible-client002 $ ps -ef | grep mysql vagrant 1982 6332 0 08:07 pts/0 00:00:00 grep --color=auto mysql
외부 접속 테스트
Vagrantfile 수정
Host PC의 13306 port를 통해 mysql서버의 3306 port에 접근할수 있도록 port forwarding을 설정해 보겠습니다. 아래와 같이 Vagrant파일의 forwarded_port정보를 수정합니다. 실습에서는 두개의 Port를 다르게 했지만 Host PC에 충돌하는 port가 없다면 동일하게 설정해도 무방합니다.
#ansible-client002 config.vm.define "ansible-client002" do |cfg| cfg.vm.box = "centos/7" cfg.vm.provider "virtualbox" do |vb| vb.name = "ansible-client002" end cfg.vm.host_name = "ansible-client002" cfg.vm.network "public_network", ip: "192.168.1.2" cfg.vm.network "forwarded_port", guest: 3306, host: 13306, auto_correct: true cfg.vm.synced_folder "../shared_data", "/shared_data", disabled: true cfg.vm.provision "shell", path: "enable_ssh_password_auth.sh" end
수정 내용을 반영하기 위해 VM을 재시작 ( vagrant halt => vagrant up ) 합니다.
$ vagrant halt ansible-client002 ==> ansible-client002: Attempting graceful shutdown of VM... $ vagrant up ansible-client002 Bringing machine 'ansible-client002' up with 'virtualbox' provider... ==> ansible-client002: Checking if box 'centos/7' version '1905.1' is up to date... ==> ansible-client002: Clearing any previously set forwarded ports... ... 생략
Mysql WorkBench 접속 테스트
아래와 같이 설정하여 접속 테스트를 합니다. 접속정보는 로컬의 vm이므로 127.0.0.1을 입력하고 port는 위에서 설정한 13306 port를 그리고 계정정보에는 ansible에서 새로 생성한 계정인 wordpress / wordpress123!을 입력합니다.
접속이 정상적으로 이루어지면 화면을 통해 wordpress database가 노출됨을 확인할 수 있습니다. root 유저가 아니므로 권한이 설정된 wordpress database만 보여지게 됩니다.
ansible을 이용하여 mysql을 설치해보았습니다. 생각보다 복잡한 작업이지만 playbook에 작성된 내용을 통해 작업이 진행되는 상황을 쉽게 파악하고 수정할 수 있게 되었습니다. 또한 다수의 서버에 동일한 환경을 빠르게 구축할 수 있게 되었습니다.
실습시 사용한 소스는 아래 github에서 확인할 수 있습니다.
https://github.com/codej99/ansible-web-application.git