A gentle introduction to Ansible
앤서블에 대한 개략적인 개념 정립해보는 가시다님 스터디 1주차 아티클
Ansible 소개
파이썬의 모듈과 SSH 만을 이용하여 원격 호스트에 명령을 수행하도록 도와주는 Configuration Management 도구이다. 모두가 알다시피 별도의 에이전트를 설치하지 않고도 단순히 SSH 접속만 가능하다면 멱등성을 보장할 수 있는 상태에서 스크립트를 일관되게 적용할 수 있다는 것으로 인기를 끈다. 특히 파이썬을 내부적으로 사용하는데 대부분의 리눅스 구현체가 파이썬이 기본 설치되어 있기 때문에 동작할 수 있는 것이다.
앤서블의 작성과 테스트를 위해서는 다음 스텝을 거쳐서 진행할 수 있다.
ansible.cfg
파일을 작성하고 확인한다.inventory
파일을 생성한다. 이 때 그룹 변수와 호스트 변수를 생성한다.ansible-inventory
명령어를 이용하여 호스트와 그룹 등록 여부를 확인한다.ansible -m ping {{ group | host }}
명령어를 통해 마스터 노드에서 원격 노드로 Ping 모듈이 성공하는 지를 확인한다.- 간단한 Playbook을 작성하고 테스트한다.
--list-hosts
와--list-tasks
및--check
플래그를 활용한다.- 필요하면
ansible-vault
옵션을 활용하여 암호화를 적용할 수 있다.
Ansible은 컨트롤 노드에서 리모트 노드에 연결하여 앤서블 모듈이라는 프로그램을 실행하고 완료되면 리모트 노드에서 제거하는 방식이 된다. 마스터(컨트롤러) 노드를 보면 원격 노드에 접속해서 모듈을 실행시키는 노드이다. 리모트 노드를 보면 컨트롤 노드에 의해 처리되는 머신이다. 컨트롤러 노드는 리모트 노드에 연결하여 모듈을 사용하는데 이 때 인증 처리가 필요하며 SSH 프로토콜을 이용한다.
인증 처리
인증 처리는 컨트롤러 노드가 리모트 노드로 접속하여 모듈을 수행하기 위해 인증이 필요하다. 그 때 SSH 프로토콜이 필요하다고 했다. Key-based ID와 PW-based ID라고 하는 2가지 방식이 있다. 당연히 리모트 노드는 사전 요건으로서 sshd root 접속을 허용해야 하며 해당 접속을 허용할 수 있는 방법은 /etc/ssh/sshd_config
에서 그 SSH 설정을 확인하면 된다. 방화벽이 열려있는지도 확인한다. 컨트롤러 노드는 리모트 노드에 SSH 키를 기반으로 접속하고 ec2-user
를 통하여 1차 접속한다. 루트 권한을 에스컬레이션 해서 받기 위해서 become 설정도 역시 둘 수 있다. 다시 말하면 SSH Key가 컨트롤러에 묶여있고 컨트롤러는 해당 키를 이용하여 리모트 노드들 간의 SSH 인증을 시도하는데 그 컨트롤러를 이용하는 노드들이 바로 ansible.cfg와 inventory 그리고 playbook이 있는 것이다.
# inventory 파일이 어디 있을까요?
[defaults]
host_key_checking = Falseask_pass = False
inventory=./inventory# root escalation 방법 등을 명시해준다.[privilege_escalation]
become = true
become_method = sudo
become_user = root
become_ask_pass = false
ansible.cfg 파일을 통한 앤서블 설정 적용
ansible.cfg 파일에는 적용의 우선순위가 있다. 먼저 ANSIBLE_CONFIG 라는 환경 변수가 설정되면 이를 따르고, 이후 ansible.cfg의 현재 폴더에서 찾아보고, 이후에는 home ansible.cfg 뿐만이 아니라 inventory, host 및 group 변수 등 다른 곳에서도 유사하게 적용된다. 아직 내가 주로 저장하는 곳은 없지만 아무래도 ./ansible.cfg
에 저장하면 유용할 것으로 보인다.
# ansible.cfg[defaults] # 앤서블 작업을 위한 기본값 설정
inventory = ./inventory # inventory 파일의 위치를 지정한다
remote_user = root # 리모트 접속 시 어느 유저로 접속할 것인가를 지정한다
ask_pass = false # SSH 암호를 묻는 메시지 표시 여부 지정[privilege_escalation]
# 보안 및 감사로 인해 원격 호스트에 권한이 없는 사용자를 연결하고
# 에스컬레이션을 해서 루트 사용자로 가져오는 여부를 사용 설정하는 것이다.
become = true # 권한 에스컬레이션을 해야한다.
become_method = sudo # 권한 에스컬레이션 시 사용자를 전환한다.
become_user = root # 리모트 노드에서 전환할 사용자를 지정하는 부분이다.
become_ask_pass = false # 에스컬레이션 시 암호를 묻는 것인가?
module
- module은 Ansible에서 사용되는 작은 프로그램이다. 컨트롤러 노드가 리모트 노드에게 SSH 프로토콜을 통해 모듈이라는 프로그램을 실행한다. 그 때 인자를 전달해준다.
- 대표적인 Ansible 모듈로는
copy, file, yum, apt, user
모듈 등이 있는데 yum 패키지 매니저를 이용하여 설치하고 업데이트하는 등의 작업을 수행한다. - 예를 들어 copy 모듈을 사용하면
web-servers
라는 그룹 또는 호스트에게copy
라는 모듈을 사용하여 인자로src
와dest
를 전달한다.
ansible web-servers -m copy -a "src=/etc/hosts dest=/tmp/hosts"
- 또한 file 이라는 모듈을 사용하면 인자로 dest, owner, group, state를 전달할 수 있게 된다.
ansible db-servers -m file -a "dest=/path/to/c mode=755 owner=ec2-user group=admin state=directory"
- 마지막 all 이라고 하는 그룹 또는 호스트에게 user 모듈을 사용하여 name, password 혹은 name, state를 인자로 전달한다.
ansible all -m user -a "name=foo password=<crypted password here>"
ansible all -m user -a "name=foo state=absent"
inventory
- 컨트롤러 노드가 리모트 노드를 관리할 때 필요한 텍스트 파일이며 리모트 노드를 그룹화하고 해당 그룹들의 변수 및 SSH 키파일 경로 관리 등을 지정하는 것이다.
- IP 기반으로도 인벤토리를 지정할 수도 있고 또한 도메인 이름 기반으로도 지정한다.
[web-servers]
host1 http_port=80 maxRequestPerChild=888 # 호스트에 대한 변수들
host2 http_port=443 maxRequestPerChild=400
# web-server라는 그룹에 host1과 host2의 그룹이 있다. 그룹 간의 공통 변수다.[web-servers:vars]
ntp_server=centos7.org
proxy=bastion.com...
- all:vars는 모든 호스트에게 적용하는 변수이다. 또한 my-ubuntu:vars는 my-ubuntu 그룹에게만 적용하는 변수를 의미한다. 여기서 어떠한 사용자는 임의의 SSH 키 파일을 인증해서 접속하라는 내용을 명시한다.
[my-amz-linux2]
cc.cc.cc.cc
cc.cc.cc.cc
[my-ubuntu]
xx.xx.xx.xx
xx.xx.xx.xx user=ansible_sigrid # 호스트 뒤에 변수를 붙이면 호스트 변수 선언이 된다[all:vars] # 그룹명 뒤에 vars를 붙이면 그룹 변수 선언이 된다
ansible_user = ec2-user
ansible_ssh_private_key_file = ~/ssh-key.pem[my-ubuntu:vars]
ansible_user = ubuntu
- 기본적으로는 IP 주소를 넣어야 하지만 /etc/hosts에 도메인 매핑을 할 경우 도메인을 넣어줄 수도 있다. 중괄호를 통하여 그룹화가 가능하고 중첩된 그룹일 경우
:children
이라는 접미사를 추가하면 된다.
[webservers]
webl.example.com
web2.example.com[db]
db01.example.com
db02.example.com[datacenter:children]
webservers
dbserver
- 인벤토리를 확인할 수 있으며
ansible-inventory -i ./inventory --list
명령어를 통해 JSON 형태를 통하여 확인할 수 있다. 기본 설정은 localhost이다.
Sigrid 🌙 ~ ansible-inventory -i ./inventory --list[WARNING]: Unable to parse /Users/sigridjineth/inventory as an inventory source
[WARNING]: No inventory was parsed, only implicit localhost is available
{
"_meta": {
"hostvars": {}
},
"all": {
"children": [
"ungrouped"
]
}
}
Playbook
Ansible을 이용하여 원격 노드에 명령어를 보내기 위해서는 ad-hoc하게 요청을 보내는 방법과 플레이북을 이용하는 방법, 그리고 Role을 사용하는 방법으로 크게 3가지가 있다. ad-hoc은 단순하게 일회성으로 리눅스 명령어 한 줄을 이용하여 모듈을 수행하는 방법이다. 아주 기초적인 방식인데 이러한 ad-hoc 실행을 스크립트로 말게 되면 바로 플레이북이 된다. 스크립트 성으로 실행하겠다고 하는 것은 2번 이상의 경우일 때 재사용을 위하여 사용하게 된다. 하기 예시는 all이라는 그룹을 대상으로 user 모듈을 사용한다. name과 state 인자를 이용하여 User를 생성하는 스크립트로 말아본 것이다.
ansible playbook에서 적용되는 변수 우선순위는 다음과 같은데 먼저 ansible-playbook 명령어와 동시에 넣은 파라미터가 우선순위로 적용되며 그 이후에는 플레이 변수가 있고 호스트 변수와 그룹 변수가 후순위로 적용된다.
---
- hosts: all
vars:
user: ansible2 tasks:
- name: Create User {{ user }}
ansible.builtin.user:
name: "{{ user }}" # 플레이 북에 직접 변수를 입력할 수 있다
state: present
centos7_hosts 라는 그룹이 있고 해당 그룹에 shell 모듈과 debug 모듈을 이용하여 2개의 태스크를 등록하도록 한 것이다. shell 모듈에서는 pwd라는 쉘 명령을 수행하고 register를 선언하게 되면 result라는 변수에 저장하겠다고 하는 의미가 된다.
- name: Ansible Test
hosts: centos7_hosts
tasks:
- name: Test
shell: pwd
register: result
- name: Display pwd output
debug:
msg: "{{ result }}"
Facts라는 개념이 있다. Playbook에서는 컨트롤러 노드에서 자동으로 검색하는 변수들인데 예를 들어서 OS가 우분투 22.04 버전 이상인 리모트 노드에서만 특정한 태스크를 동작시키거나 하는 액션을 플레이북에서 실행할 수 있게 된다. 앤서블이 관리 호스트에서 자동으로 검색한 변수가 되며 조건문이나 반복문 또는 관리 호스트에서 수집한 값에 의존하는 명려문들의 어떤 사용 가능한 호스트별 정보를 가져온다. 그 대상이 되는 것은 호스트 이름, 커널 버전, 네트워크 인터페이스 이름 등이 된다. 그런데 부하에 대해서 크게 걱정하지 않을 때야 상관없으나 노드를 관리하는 대수가 수십, 수백 대가 될 경우 컨트롤러 노드가 플레이북을 매번 실행할 때마다 해당 노드 대수들에 대해 변수 값을 불러온 이후에야 값을 수행할 수 있으므루 부하가 될 수 있다. 이 때는 Facts 값을 캐싱할 수 있다.
혹은 Facts를 더 이상 가져올 필요가 없다고 판단되면 gather_facts: no
옵션을 주입하기만 하면 된다. 또한 탭을 사용하기 보다는 space 두 번으로 구조를 구분할 수 있다. yml 파일이어야 한다.
# my-own-playbook.yml -- ansible-playbook -e user=sigrid my-own-playbook.yml
# 위와 같이 ansible-playbook을 실행할 때 변수를 넣어줄 수도 있다---
- hosts: all
tasks:
- name: Print message
debug:
msg: Hello CloudNet@ Ansible Study
다음을 한 번 구동해보자. 호스트를 /etc/ansible/hosts
를 통해서 지정해줘도 되고 만약 빠르게 테스트하고 싶다면 호스트를 localhost로 바꾸어서 시도하는 것도 방법이 된다.
---
- hosts: localhost tasks:
- name: Print all facts
ansible.builtin.debug:
var: ansible_facts
Ansible Vault
앤서블에서 데이터 파일을 암호화하거나 해독할 수 있는 도구이다. 새로운 암호화된 파일을 만들 수도 있고 이미 만들어진 파일에 암호화를 적용하는 것도 가능하다. ansible-playbook을 이용할 때 암호화된 파일을 복호화 하거나 역으로 암호화하는 것도 가능하다.
ansible-vault create mysecret.yml
> ✘ Sigrid 🌙 ~ ansible-vault create mysecret.yml
New Vault password:
Confirm New Vault password:
ansible-vault view mysecret.yml
을 통해 암호화한 파일을 볼 수도 있다.
- 기존에 주어진 파일을 암호화하는 것도 가능하고, 기존 파일의 암호를 변경하는 것도 가능하다.
✘ Sigrid 🌙 ~ ansible-vault encrypt test-secret.yml
New Vault password:
Confirm New Vault password:
Encryption successful
Sigrid 🌙 ~ ansible-vault rekey mysecret.ymlVault password:
New Vault password:
Confirm New Vault password: