간단하고 기초적인 앤서블 실습으로 Redhat Ansible workshop의 실습 후 자료를 가지고 작성한 내용이다.
그래서 대부분 내용이 당시 실습 내용과 유사하다.
환경설명
VMware Workstation 가상머신 사용.
Centos 7 1708 minimal.
설치
별다른 작업없이 아래 커맨드 만으로 설치가 가능하다.
설정
인벤토리 등록
앤서블 플레이북 사용시 특정 인벤토리를 지정해서 사용하기도 하지만 사용하지 않을경우 default로 /etc/ansible/hosts 파일을 참조한다.
아래에 사용할 인벤토리 설정 파일에 대한 자세한 내용 등은 인벤토리 설명 공식 문서 에서 볼 수 있다.
본 글에서는 테스트를 위해 web1과 web2의 패턴으로 나누어서 등록하게 되는데
- web1의 경우 접속 방법을 변수로 일괄 처리, host_key 방식을 사용
- web2의 경우 접속 방법을 개별 입력, ssh user/pass 사용.(비권장)
[web1]
node-2 ansible_host=192.168.8.12
node-3 ansible_host=192.168.8.13
[web2]
node-4 ansible_host=192.168.8.14 ansible_user=root ansible_ssh_pass=qwe123 ansible_connection=ssh
node-5 ansible_host=192.168.8.15 ansible_user=root ansible_ssh_pass=qwe123 ansible_connection=ssh
[web1:vars]
ansible_ssh_private_key_file=~/.ssh/id_rsa
호스트 키 설정
web1의 경우에서 host_key를 사용하게 되는데 최초 접속 시 호스트 키 등록여부를 물어보게 되므로 이를 패스하기 위한 설정이다. 해당 부분을 처리해 주지 않으면 ssh 처음 접속시 key 등록 여부를 묻기 때문에 스크립트 실행이 불가능하다.
실패 예시 :
[root@localhost .ssh]# ansible node-2 -m ping
The authenticity of host '192.168.8.12 (192.168.8.12)' can't be established.
ECDSA key fingerprint is SHA256:TQNGTl9QstcNpy6Hda+fLtS5aTMWHIsvHZue/Y0M50k.
ECDSA key fingerprint is MD5:11:0a:3e:ed:db:df:04:39:7d:d2:73:bd:f3:ad:74:19.
Are you sure you want to continue connecting (yes/no)?
/etc/ansible/ansible.cfg 파일에 아래 부분으로 수정 ( default는 주석처리 되어있음 )
host_key_checking = False
위와 같이 직접 수정하거나 아래 스크립트로 바로 바꿔줄 수도 있다.
sed -i '/host_key_checking/c\host_key_checking = False' /etc/ansible/ansible.cfg
호스트 키 생성&복사
위에서 ssh 접속시 사용할 키가 아직 없기 때문에 키를 생성해 주어야한다. 위의 키 파일 위치와 아래 생성될 위치는 동일해야한다.
ssh-keygen -t rsa -N "" -f ~/.ssh/id_rsa
그리고 ssh-copy-id 를 통해 생성한 키를 복사하도록 한다. -o StrictHostKeyChecking 부분은 앞서 host_key_checking = false와 동일 맥락이다. 어차피 한번 확인할 부분이니 그냥 해줘도 무방하다.
ssh-copy-id -o StrictHostKeyChecking=no 192.168.8.12
ssh-copy-id -o StrictHostKeyChecking=no 192.168.8.13
연결 확인
연결 확인을 위해서는 ping 모듈을 사용하면 된다. 모듈은 명령 집합이라고 생각하면 된다. ping 모듈은 접속확인과 python 가능 여부를 확인한다고 ping 모듈 문서에서 확인할 수 있다.
[root@localhost .ssh]# ansible all -m ping -o
node-2 | SUCCESS => {"changed": false, "ping": "pong"}
node-4 | SUCCESS => {"changed": false, "ping": "pong"}
node-3 | SUCCESS => {"changed": false, "ping": "pong"}
node-5 | SUCCESS => {"changed": false, "ping": "pong"}
[root@localhost .ssh]#
디버그
대부분 에러는 출력으로 나오지만 -v verbose 옵션을 통해 문제를 발견하거나 할 수 있다.
[root@localhost .ssh]# ansible all -m ping -o -v
Using /etc/ansible/ansible.cfg as config file
node-2 | SUCCESS => {"changed": false, "ping": "pong"}
node-3 | SUCCESS => {"changed": false, "ping": "pong"}
node-4 | SUCCESS => {"changed": false, "ping": "pong"}
node-5 | SUCCESS => {"changed": false, "ping": "pong"}
[root@localhost .ssh]# ansible all -m ping -o -vv
ansible 2.4.2.0
config file = /etc/ansible/ansible.cfg
configured module search path = [u'/root/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
ansible python module location = /usr/lib/python2.7/site-packages/ansible
executable location = /usr/bin/ansible
python version = 2.7.5 (default, Aug 4 2017, 00:39:18) [GCC 4.8.5 20150623 (Red Hat 4.8.5-16)]
Using /etc/ansible/ansible.cfg as config file
META: ran handlers
node-2 | SUCCESS => {"changed": false, "ping": "pong"}
node-3 | SUCCESS => {"changed": false, "ping": "pong"}
node-4 | SUCCESS => {"changed": false, "ping": "pong"}
node-5 | SUCCESS => {"changed": false, "ping": "pong"}
META: ran handlers
META: ran handlers
위의 예제와 같이 다수의 v 옵션을 지원하며 필요에 따라 5개까지 붙여서 확인할 수 있다.
[root@localhost .ssh]# ansible all -m ping -o | wc -l
4
[root@localhost .ssh]# ansible all -m ping -o -v | wc -l
5
[root@localhost .ssh]# ansible all -m ping -o -vv | wc -l
14
[root@localhost .ssh]# ansible all -m ping -o -vvv | wc -l
79
[root@localhost .ssh]# ansible all -m ping -o -vvvv | wc -l
81
[root@localhost .ssh]# ansible all -m ping -o -vvvvv | wc -l
199
실행
먼저 Ansible이 어떻게 동작하는지 알아보면 아래 그림을 참고하면되고 간단하게 알아보면
Playbook은 YAML 형태에 의해 Playbook이 작성되고 각 Playbook에는 순차적(위에서 아래로) 실행되는 코드가 들어있다.
Inventory는 앞서 설정한것처럼 작업될 대상이 정의되며,
Module은 포함하며 모듈은 특정 타겟에 대한 작업을 하기 위한 도구라고 볼 수 있으며, Playbook에 포함되거나 AD-HOC으로 실행된다.
모듈
간단하게 설명하고 넘어가면 모듈은 모듈 라이브러리라고도 불리며 제공되는 것도 있으며 직접 작성하여 사용할 수도 있고 공유되기도 한다.
현재 사용할 수 있는 모듈은 이곳에서 확인할 수 있다.
앞서 테스트에 사용한 PING 모듈은 DOS의 Ping 처럼 접속/서비스를 확인할 수 있는 도구이며, file 모듈과 같이 파일에 대해 작업할 수 있는 모듈도 있으며 yum 모듈과 같은 패키지 작업을 지원하는 모듈도 있다.
AD-HOC
AD-HOC은 앞서 사용한 PING 모듈 형태로 실행되는 것을 말한다.
command 모듈을 사용하면 특정 명령어를 전송하고 이에 대한 응답을 확인도 가능하다.
[root@localhost .ssh]# ansible all -m command -a "ip route get 8.8.8.8" -o
node-3 | SUCCESS | rc=0 | (stdout) 8.8.8.8 via 192.168.8.2 dev ens33 src 192.168.8.13 \n cache
node-2 | SUCCESS | rc=0 | (stdout) 8.8.8.8 via 192.168.8.2 dev ens33 src 192.168.8.12 \n cache
node-5 | SUCCESS | rc=0 | (stdout) 8.8.8.8 via 192.168.8.2 dev ens33 src 192.168.8.15 \n cache
node-4 | SUCCESS | rc=0 | (stdout) 8.8.8.8 via 192.168.8.2 dev ens33 src 192.168.8.14 \n cache
[root@localhost .ssh]#
AD-HOC은 주로 임시(테스트)로 쓰이기도 하고 처음 앤서블을 접할때 이해하고 접근하는데 많은 도움이 된다.
ANSIBLE과 같은 자동화 배포 툴은 Playbook에 핵심이 있지만 AD-HOC을 사용하게 되면 부분 테스트/1회성 전체 명령과 같은 경우에 큰 도움이 된다.
AD-HOC은 주로 모듈을 사용하게 되며 모듈은 Playbook과 AD-HOC 모두에서 동일하게 쓰일 수 있다.
AD-HOC 모듈을 통해 httpd를 설치하고 실행하려면 아래 두 줄만으로 가능하다.
ansible web1 -m yum -a "name=httpd state=present"
ansible web1 -m service -a "name=httpd state=started"
다양한 방법이 있겠지만 아래와 같은 형태로 80포트 오픈으로 확인할 수도 있다.
[root@localhost .ssh]# ansible web1 -m wait_for -a "port=80" -o
node-3 | SUCCESS => {"changed": false, "elapsed": 0, "path": null, "port": 80, "search_regex": null, "state": "started"}
node-2 | SUCCESS => {"changed": false, "elapsed": 0, "path": null, "port": 80, "search_regex": null, "state": "started"}
[root@localhost .ssh]#
Playbook
Playbook은 모듈을 YAML 형태로 작성하는 것으로 이해를 더 쉽게 하기 위해 위의 작업을 YAML로 작성하면 아래와 같다.
---
- hosts: web2
name: Install the apache web service and run
tasks:
- name: install httpd
yum:
name: httpd
state: present
- name: start httpd
service:
name: httpd
state: started
- name: wait 80 port
wait_for:
port: 80
위와 같이 httpd.yaml 파일로 작성한 뒤 실행하면 아래와 같이 출력된다.
[root@localhost ~]# ansible-playbook httpd.yaml
PLAY [Install the apache web service and run] *******************************************************************
TASK [Gathering Facts] ******************************************************************************************
ok: [node-5]
ok: [node-4]
TASK [install httpd] ********************************************************************************************
changed: [node-5]
changed: [node-4]
TASK [start httpd] **********************************************************************************************
changed: [node-5]
changed: [node-4]
TASK [wait 80 port] *********************************************************************************************
ok: [node-5]
ok: [node-4]
PLAY RECAP ******************************************************************************************************
node-4 : ok=4 changed=2 unreachable=0 failed=0
node-5 : ok=4 changed=2 unreachable=0 failed=0
[root@localhost ~]#
Ansible의 특징 중 하나는 멱등성인데 위의 플레이북을 다시 실행하면 아래와 같은 결과를 얻는데, 멱등성은 간단하게 여러번 실행하더라도 결과가 달라지지 않는 다는 것을 의미한다.
그래서 yum 모듈의 httpd 패키지를 present 상태로 되도록 한 코드에 대해서는 여러번 반복 실행을 하더라도 동일한 결과를 갖게 된다. 이 부분이 변경될 경우 결과에 최초 실행때 나온 것처럼 "changed" 상태로 나오게 된다.
[root@localhost ~]# ansible-playbook httpd.yaml
PLAY [Install the apache web service and run] *******************************************************************
TASK [Gathering Facts] ******************************************************************************************
ok: [node-5]
ok: [node-4]
TASK [install httpd] ********************************************************************************************
ok: [node-5]
ok: [node-4]
TASK [start httpd] **********************************************************************************************
ok: [node-5]
ok: [node-4]
TASK [wait 80 port] *********************************************************************************************
ok: [node-5]
ok: [node-4]
PLAY RECAP ******************************************************************************************************
node-4 : ok=4 changed=0 unreachable=0 failed=0
node-5 : ok=4 changed=0 unreachable=0 failed=0
[root@localhost ~]#