맘가는 대로
Ansible 로 LAMP 구성하기 본문
LAMP, 그리고 자동화
LAMP 는 Linux, Apache Web server, MySQL, PHP 를 모아서 쓴 약자로, 오랫동안 사용되어 대표적인 리눅스 웹 서버 구성이라고 할 수 있다. 그렇기에 많이 사용될 것이고, 많이 사용되면 편의성은 물론, 절차중의 실수를 줄이기 위해 자동화를 도입하는 것이 좋다고 할 수 있다.
이 글에서는 Ansible 을 통해 1 대의 서버에 LAMP 구성을 자동적으로 할 수 있도록 할 예정이다.
LAMP 를 Ansible 로 구성해보기
LAMP 는 그 이름에서 바로 구성요소들을 알 수 있다. 1 대의 서버에 4 가지 구성요소를 구현하려면 서버 스펙도 충분히 필요할 것이기 때문에 4 core / 4 GB 로 대상 서버를 구성할 것이다. 다만, Ansible 마스터 서버는 그대로 둔다.
아래는 해당되는 Vagrantfile 이다.
$NODE_COUNT=1
Vagrant.configure("2") do |config|
config.vm.box = "centos/7"
config.vm.provider "virtualbox" do |v|
v.cpus = 1
v.memory = 256
end
config.vm.provision "shell", inline: "
sudo timedatectl set-timezone Asia/Seoul
sudo systemctl restart rsyslog
sudo yum install -y vim
"
(1..$NODE_COUNT).each do |i|
config.vm.define "node-#{i}" do |n|
n.vm.hostname = "node-#{i}"
n.vm.network "private_network", ip: "10.10.10.#{9 + i}"
n.vm.provider "virtualbox" do |v|
v.cpus = 4
v.memory = 4096
end
end
end
config.vm.define "ansible" do |a|
a.vm.hostname = "ansible"
a.vm.network "private_network", ip: "10.10.10.100"
a.vm.synced_folder "./.vagrant", "/vagrant/.vagrant", type: "rsync"
a.vm.provision "shell", inline: "
sudo find /vagrant -name 'private_key' -exec chmod 400 {} \\;
sudo yum install -y ansible
"
end
end
다만, 이는 예시이기 때문에 이전의 글을 보았던 사람들이라면 바로 알겠지만, 굳이 따라서 할 필요는 없다. 요점은 스펙을 충분히 구한다는 것이다.
서버가 생성이 되면 직접 원하는 스펙으로 구성이 되었는지 확인해본다. 다만, 직접 들어가서 확인하는 것이 아닌 Ansible CLI 를 이용하여 확인한다.
CPU 확인
메모리 확인
-i 를 통해 인벤토리 파일을 지정하며, -a 를 통해 실행하려는 명령어를 입력한다. 마지막으로 쓴 단어는 해당되는 노드를 나타낸다. -a 옵션은 앤서블 모듈의 인수들을 나타내기 위해 사용되지만, 모듈이 지정되지 않았을 때는 단순히 접속한 쉘에서 명령어를 실행한다. 노드는 이름 전체를 사용해도 되지만 패턴 매칭 방식이기 때문에 공통되는 단어를 사용해서 표시해도 된다.
이렇게 확인하는 이유는 단순하다. 익숙해지기 위함이며 편리하게 확인이 가능하다는 점을 알 수 있기 위해서이다.
- CLI 로 구성하기
all:
hosts:
ansible:
ansible_connection: local
children:
test:
hosts:
node-1:
ansible_host: 10.10.10.10
ansible_ssh_private_key_file: /vagrant/.vagrant/machines/node-1/virtualbox/private_key
이를 통해 알 수 있는 점은 호스트와 접속 키 파일은 지정해주었지만, 유저와 root 로의 변환을 지정하지는 않았다는 것이다. 그런데 ping 모듈과 -a 를 통한 명령어는 잘 사용이 되었기 때문에 유저를 지정하지 않았음에도 잘 되었다는 것을 알 수 있다. 이유를 알기 위해 디버깅을 해보자.
None 이라는 유저명을 사용했다는 것을 알 수 있다. 이럴 경우 보통의 SSH 와 같이 접속을 시도한 유저명이 사용되었다는 것이다. 즉, 커맨드창에 보이는 vagrant 를 사용하여 접속했다는 것을 알 수 있다. vagrant 를 사용하여 서버 환경을 구성할 때에는 vagrant 일반 유저인 것이 표준이다. 즉, vagrant 계정으로 패키지를 사용할 수는 없다.
또한 이는 Ansible 의 DEFAULT_REMOTE_USER 변수와 관계가 있다.
이를 해결하기 위해서 원격 노드에서 root 권한을 사용할 수 있도록 설정을 해준다.
결과창이 길어서 일부만 올린다.
명령어를 입력할 때 -become 옵션을 추가해서 실행했다. 즉, vagrant 계정으로 접속하되, 모듈을 실행할 때는 root 권한을 이용하도록 하는 것이다.
-a 옵션의 name 은 설치할 패키지의 이름을, state 는 목표로 하는 패키지 설치의 상태이다. 즉, httpd 패키지가 현재 설치되어있는 것을 원한다고 표현한 것이다.
웹 서버 설치만으로 충분하지 않다. PHP 도 설치한다. 다만, PHP 는 어플리케이션 용도이기 때문에 Apache 웹 서버와 MySQL DBMS 의 연결성을 충분히 고려하여 패키지 설치를 한다.
php 와 php-mysql 패키지를 설치한다. 맞다. name 요소에 ',' 를 통해 구분해준다면 한번에 여러개의 패키지를 설치할 수 있다. 굳이 나눌 필요가 없었긴 하지만 차근차근 해나가도록 하자.
MySQL 을 설치한다.
이런, 설치할 때 알아챘지만 이제 CentOS 에서 기본 제공되는 MySQL DBMS 는 MariaDB 로 대체되었다. 이는 CentOS 가 RHEL 의 복제판이기 때문에 생긴 현상이다. Oracle 의 MySQL 에 대해서 RedHat 은 기본적으로 사용하지 않도록 정책을 설정하였고, 이는 라이선스와 관련이 있다. 관심이 있는 사람은 관련되어 매뉴얼을 찾아볼 것을 권한다.
이유는 그렇다쳐도, MariaDB 를 사용하는 것에 큰 문제는 없다. MariaDB 5 버전은 최대한 MySQL 과의 호환성을 고려했기 때문에 차이가 거의 없어서 일반적으로 MySQL 을 사용하는 것과 같다.
이제 Apache 와 MySQL(MariaDB) 의 데몬을 올려보자.
데몬을 올릴 때에는 Ansible 의 service 모듈을 사용한다. 다만, 인수명이 조금 이상하다고 느낄 수 있는 사람이 있다. state 라는 상태를 나타내는 인수에는 started 를, enabled 라는 서버 시작시 데몬이 같이 시작됨을 의미하는 enable 에 과거형을 사용했다. 이는 Ansible 이 단순히 절차를 만족하는 도구가 아닌 상태를 확인하고 실행하는 의미를 갖고 있기 때문에 상태를 의미하는 과거형 동사를 사용했다. 이는 Ansible 의 멱등성과도 관계가 있다.
이러한 인수 지정을 통해 바로 의미를 파악할 수 있다는 장점도 있지만, 필요할 때에만 실행되어 지정한 상태로 설정된다는 선언적인 요소이기도 하다.
service 모듈은 여러개의 이름을 받지 않으니 하나씩 실행한다.
자, 이제 접속해보자.
방화벽 때문에 바로 접속이 안될 것으로 생각했는데, 바로 됐다. vagrant 에서는 방화벽이 초기에 올라오지 않도록 되어있는 것 같다. 이건 이것대로 조금 충격이긴 한데, 우선은 넘긴다.
자, 그러면 MySQL(MariaDB) 가 남아있다. 일반적으로 MySQL 을 설치하면 mysql_secure_installation 스크립트를 통해 초기 보안 설정을 진행하겠지만, 해당 스크립트는 비밀번호를 인수로 받지 않기 때문에 Ansible 로 직접 설정을 진행할 것이다.
MySQL 을 위한 파이썬 모듈이 필요하다는 응답을 받았다. 이에 응해주도록 하자.
다시 MySQL 유저 설정을 해보자
되었다. MySQL 사용자 계정을 추가할 때는 mysql_user 모듈을 사용한다. login_user 는 접속에 사용하는 유저의 이름을, name 은 추가하거나 삭제하려는 유저의 이름을, password 는 설정하려는 비밀번호를, priv 는 설정하려는 권한을 의미한다.
다시 해보자.
같은 명령어인데 지금은 안된다. 지금까지는 접속에 비밀번호를 사용하지 않았고, 방금의 설정으로 비밀번호를 넣어줬기 때문에 안된 것일 수 있다. 실제 어떤지 다시 확인해보자. 다만, 지금은 Ansible 모듈이 아닌 명령어로 확인한다.
결과는 잘 표시되지만 어떤지 정확히 보이지 않는다. 조금 옵션을 넣어보자.
다시 확인한다.
잘 실행됐다.
이제 PHP 정보와 PHP 를 통해 MySQL 접근이 가능한지 확인해보자.
우선, PHP 전용의 DB 와 유저를 추가해준다.
PHP 정보를 보여주는 페이지를 위해 아파치 웹 서버에 관련된 페이지를 넣어주자. 다만, 가정은 항상 Ansible 마스터에서 노드로 전달해준다는 것을 잊지 않도록 한다. 직접 서버에 넣어주면 자동화의 의미가 없다.
우선, PHP 코드는 다음과 같다.
<?php phpinfo(); ?>
이 코드를 phpinfo.php 파일로 저장하여 관련되어 웹 서버에 넣어주려고 한다. 목표 디렉토리는 /var/www/html 이다.
파일을 옮길 때에는 copy 모듈을 사용한다. src 는 사용하려는 원본 파일을, dest 는 원격지에서 목적지를 설정하며, mode 는 파일의 권한을 의미한다.
접속하여 확인한다.
역시 스크립트 언어의 편리함이랄까, 별도의 데몬 재시작 없이 파일을 넣어준 것만으로 바로 원하는 앱이 실행된다. 이제 db 와 연결이 되는지도 확인해보자.
아래는 DB 연결을 확인하는 PHP 코드이다. chkdb.php 파일로 저장할 것이다.
<?php
$servername = "localhost";
$database = "lamp-test";
$username = "lamp-test";
$password = "test1234";
$conn = new mysqli($servername, $username, $password, $database);
if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
}
echo "Connected successfully";
?>
잘 설정되었다. 이를 통해 기본적인 LAMP 구성을 마쳤다고 할 수 있다.
LAMP 의 구성요소들을 설치하고 각 구성요소들의 연결 여부까지 확인하였다. 다만, 이는 매우 기본적인 구성이기 때문에 원하는 구성등에 따라 더 달라질 수 있다. 예를 들어 아직 구성하지 않은 방화벽을 추가로 구성한다거나, 성능등의 이유로 네트워크 통신이 아닌 유닉스 소켓 통신을 사용할 수도 있을 것이다. 다만, 이들 모두 보통의 구성은 아니기도 하고 필요하다면, 직접 찾아보는 것도 좋은 방법이다.
- 플레이북으로 구성하기
CLI 로 구성하기를 끝까지 따라왔다면 정말 수고가 많았다고 말하고 싶다. 다만, Ansible 의 진정한 힘은 플레이북에서도 나오기 때문에 플레이북으로 구성하는 것을 아는 것도 좋다.
여태까지는 명령어를 입력하면서 했으므로 기존의 방법과 크게 다른 것이 없었지만, 플레이북을 작성하여 구성하는 것은 앞으로의 가능성에 크게 한발을 딛는다는 생각으로 봐주었으면 한다.
CLI 를 통해 진행했을 때, 패키지 설치 -> 설정 -> 연동 순으로 하였다. 하지만 개별적으로 조금씩 비효율적이거나 절차를 줄일 수 있는 과정들이 있었다. 플레이북을 통한 구성을 통해 절차적인 효율성을 노릴 수 있다.
다만, CLI 를 통해 구성하는 것과 크게 다르지는 않다. (아직까지는....)
자, 새로운 시작을 위해 기존 VM 을 지우고 다시 시작하자.
그리고 phpinfo.php 파일과 chkdb.php 파일을 미리 작성한 뒤 아래와 같이 플레이북을 작성한다.
---
- hosts: node-1
become: true
vars:
mysql_root_password: test1234
mysql_php_user: lamp-test
mysql_php_password: test1234
tasks:
- name: Install packages needed
yum:
name:
- httpd
- php
- php-mysql
- mariadb
- mariadb-server
- MySQL-python
- name: Start and enable httpd
service:
name: httpd
state: started
enabled: yes
- name: Start and enable MariaDB
service:
name: mariadb
state: started
enabled: yes
- name: Add password for root in mariadb
mysql_user:
login_user: root
name: root
password: "{{ mysql_root_password }}"
- name: Delete anonymous user in mariadb
mysql_user:
name: ''
state: absent
host_all: yes
login_user: root
login_password: "{{ mysql_root_password }}"
- name: Delete test database
mysql_db:
name: test
state: absent
login_user: root
login_password: "{{ mysql_root_password }}"
- name: Add php database
mysql_db:
name: lamp-test
login_user: root
login_password: "{{ mysql_root_password }}"
- name: Add php user in mariadb
mysql_user:
name: "{{ mysql_php_user }}"
password: "{{ mysql_php_password }}"
priv: 'lamp-test.*:ALL'
login_user: root
login_password: "{{ mysql_root_password }}"
- name: Copy phpinfo.php into html directory
copy:
src: /vagrant/phpinfo.php
dest: /var/www/html/
owner: apache
group: apache
mode: 0744
- name: Copy chkdb.php into html directory
copy:
src: /vagrant/chkdb.php
dest: /var/www/html/
owner: apache
group: apache
mode: 0744
길다면 길다고 할 수 있겠지만, 이 플레이북 하나로 여태 LAMP 구성을 단번에 끝낸다고 생각하면 매우 짧다고 할 수 있지 않을까? CLI 로 했던 것과 다를 것이 없다. 다만, 코드로 작성하였을 때에 여러가지 편의성을 더했다.
우선, 첫 6 줄을 보자
- hosts: node-1
become: true
vars:
mysql_root_password: test1234
mysql_php_user: lamp-test
mysql_php_password: test1234
hosts 를 통해 적용할 서버를 지정해준다. 현재는 node-1 서버 1 개에 LAMP 를 설치하므로 node-1 이라고 작성하였다.
그리고 become 을 통해 root 권한으로 실행한다고 나타내주었다. 알 수 있겠지만 YUM 설치에서 root 권한이 필요했기 때문이다.
vars 구역을 통해 자주 사용하는 것들을 변수화하였다. 이를 통해 vars 구역안에서의 변화를 통해 많은 곳에 사용되는 정보를 한번에 바꿔줄 수 있다.
변수는 yaml 형식을 따르기 때문에 <변수명>: <값> 으로 지정이 가능하며, 변수명은 자유롭게 작성이 가능하다.
다음 구역을 보자
tasks:
- name: Install packages needed
yum:
name:
- httpd
- php
- php-mysql
- mariadb
- mariadb-server
- MySQL-python
- name: Start and enable httpd
service:
name: httpd
state: started
enabled: yes
- name: Start and enable MariaDB
service:
name: mariadb
state: started
enabled: yes
Ansible 을 통해 실행되는 작업들을 표시하기 위해 tasks 구역에 원하는 작업들을 적어놓는다.
각 작업은 모듈과 모듈 인수를 필요로 하고, name 을 통해 작업명을 표시할 수 있다. 필수는 아니지만 무엇을 하는지 혹은 어떤 목적으로 하는지 등등을 적을 수 있기 때문에 작성하는 것이 좋다.
CLI 를 통해 설치한 패키지들을 yum 모듈을 통해 바로 설치하는 것을 볼 수 있다. yum 의 name 인수에 yaml 의 리스트 표현으로 필요한 패키지들을 모두 작성하였다. state 는 별도로 표시하지 않았는데, 별도 표시를 하지 않으면 present 로 적용되기 때문이다.
service 모듈을 통해 httpd 와 mariadb 데몬을 시작하고 enable 상태가 되게 하였다.
다음 작업들은 DB 작업들이다.
- name: Add password for root in mariadb
mysql_user:
login_user: root
name: root
password: "{{ mysql_root_password }}"
- name: Delete anonymous user in mariadb
mysql_user:
name: ''
state: absent
host_all: yes
login_user: root
login_password: "{{ mysql_root_password }}"
- name: Delete test database
mysql_db:
name: test
state: absent
login_user: root
login_password: "{{ mysql_root_password }}"
- name: Add php database
mysql_db:
name: lamp-test
login_user: root
login_password: "{{ mysql_root_password }}"
- name: Add php user in mariadb
mysql_user:
name: "{{ mysql_php_user }}"
password: "{{ mysql_php_password }}"
priv: 'lamp-test.*:ALL'
login_user: root
login_password: "{{ mysql_root_password }}"
MariaDB 의 root 계정에 비밀번호를 설정하고, 익명 계정을 지우고, test DB 를 지웠다. 이는 보안 목적의 작업이다.
다음은 php 전용 계정과 DB 를 추가하였다. 이는 어플리케이션 운용 목적의 작업니다.
다음 작업은 최종적으로 php 어플리케이션을 적용하는 것이다.
- name: Copy phpinfo.php into html directory
copy:
src: /vagrant/phpinfo.php
dest: /var/www/html/
owner: apache
group: apache
mode: 0744
- name: Copy chkdb.php into html directory
copy:
src: /vagrant/chkdb.php
dest: /var/www/html/
owner: apache
group: apache
mode: 0744
미리 작성해둔 phpinfo.php 파일과 chkdb.php 파일을 node-1 서버로 옮겨주었다. PHP 어플리케이션은 바로 실행되어 보여주는 스크립트성 언어이기 때문에 별도의 데몬 재시작은 필요치 않아서 파일만 옮겨주어도 충분하다.
이를 보면 변수를 추가한 것 이외에는 CLI 를 통해 구성한 것과 크게 다르지 않다. 다만, 순서나 묶어서 사용하는 등의 절차적인 차이가 있을 뿐이다.
자, 이제 실행해보자
ansible-playbook -i hosts.yaml lamp.yaml
결과는 길게 나오기 때문에 각자 확인하는 것으로 하자.
가벼운 시작
이 글을 통해 한 노드에 대해 웹 서버를 구성하는 것은 어느 정도 감이 올 것이다. 다만, 이것이 끝이 아니다. 자동화는 1 대의 서버가 아닌 기본 100 대 이상의 서버를 소수의 사람이 관리할 수 있게 나온 도구이다. 그렇다면, 1000 대, 2000 대, 혹은 1 만대가 넘는 서버는 어떻게 가능할까?
앞으로 계속 차근차근 나아가다 보면 규모의 문제뿐만이 아니라는 것도 알 수 있을 것이다.
또한 앞으로 CLI 보다는 플레이북에 집중할 것이기 때문에, 플레이북 실행시 잘 알 수 없는 문제는 디버깅을 하는 습관을 들이도록 하자.
출처
'자동화 > 앤서블' 카테고리의 다른 글
앤서블에서 변수 사용하기 (0) | 2019.11.23 |
---|---|
Ansible 을 통해 파일 작성하기 (0) | 2019.11.03 |
앤서블 인벤토리 설정 (0) | 2019.06.09 |
앤서블 실습 환경 구성 (0) | 2019.06.08 |
앤서블의 구조와 작동 방식 (0) | 2019.06.02 |