Introduction to Ansible
특징
- Provisioning
- Configuration Management
- Continuous Delivery
- Application Deployment
- Security Compliance
Redhat 에서 Python 으로 개발한 Provisioning 자동화 도구로 YAML 로 작성된 파일을 통해 Docker, EC2 등에 대한 설정을 관리할 수 있다. 머신 설정을 자동화하기 위해 shell script 를 많이 사용하지만 Ansible 이 이런 과정을 쉽게 만들어준다.
Ansible 은 여러대의 VM 의 집합을 Inventory 라고 부르고 각 VM 들을 host 라고 부른다. 가령 3대의 VM 의 집합을 Inventory 라고 했을 때, 2대의 VM 은 Web 을 호스팅하는 host 로 구분짓고 나머지 1대를 DB 를 호스팅하는 host 로 구분 지을 수 있다.
Ansible 은 주어진 Inventory 내 host 들을 provisioning 하고 config 을 관리하기 위해 Playbook 이라는 일종의 설정 파일을 사용하여 VM 을 선언적으로 관리한다. Playbook 은 Play 의 집합으로 Play 에는 해당 설정이 적용될 host 그룹과 그 그룹에 적용될 작업들을 나열하는 Tasks 와 Roles 가 존재한다.
Ansible 은 VM 에 필요한 설정과 커맨드를 실행하기 위해 VM 에 agent 를 설치하는 대신 ssh 연결을 통해 원격으로 VM 을 설정할 수 있다. 또한 설정 작업이 여러번 반복되도 동일한 결과를 도출하도록 Idempotency 를 보장한다.
Configuration and Basic Concepts
Introduction to Ansible Configuration Files
[defaults]
inventory = /etc/ansible/hosts
log_path = /var/log/ansible.log
...
[inventory]
enable_plugins = host_list, virtualbox, yaml, constructed
[privilege_escalation]
...Ansible 을 설치하면 기본적으로 /etc/ansible/ansible.cfg 이라는 구성 파일이 생성된다. 이 파일은 Ansible 의 기본적인 동작을 설정하는 파일이다.
여러 Playbook 이 존재해서 각 Playbook 마다 다른 설정값을 주고 싶을 때엔 여러가지 방법으로 줄 수 있는데, 우선순위는 아래와 같다. 아래 순서대로 주어진 설정값들이 우선 적용되고 모두 다 작성하지 않아도 다음 우선순위 파일에 작성된 설정값이 적용된다.
$ANSIBLE_CONFIG=/opt/ansible-web.cfg환경변수에 지정된 config 파일/opt/web-playbooks/ansible.cfgPlaybook 이 실행되는 디렉터리에 있는 config 파일.ansible.cfg유저의 홈 디렉터리에 있는 config 파일/etc/ansible/ansible.cfg기본 config 파일
Ansible Inventory
server1.company.com
server2.company.com
[mail]
server3.company.com
server4.company.com
[db]
server5.company.com
server6.company.com
[web]
server7.company.com
server8.company.comAnsible 은 1대 또는 여러대의 머신을 동시에 설정할 수 있다. Linux 의 경우엔 SSH, Windows 의 경우엔 Powershell Remoting 을 통해 통신하여 머신들을 설정한다. Ansible 은 이런 target systems 를 Inventory 를 통해 관리하는데 기본적으로 /etc/ansible/hosts 에 위치한다. Inventory 파일은 ini 또는 yaml 형태의 파일로 작성할 수 있다.
web ansible_host=server1.company.com ansible_connection=ssh ansible_user=root
db ansible_host=server2.company.com ansible_connection=winrm ansible_user=admin
mail ansible_host=server3.company.com ansible_connection=ssh ansible_ssh_pass=P
localhost ansible_connection=localhostInventory 파일에서 target host 를 그룹으로 분류하는 것 외에도 alias 를 통해 target system 에 대한 설정을 세분화 할 수도 있다. 이런 설정값들은 기본적으로 linux 를 기준으로 기본값이 설정된다.
Ansible Variables
name: Add DNS server to resolv.conf
hosts: localhost
vars:
dns_server: 10.1.250.10
tasks:
- lineinfile:
path: /etc/resolv.conf
line: 'nameserver {{ dns_server }}'Ansible 에선 변수를 선언할 때 Playbook vars 딕셔너리에 선언하거나 variables 파일에 따로 선언할 수 있다. 변수를 사용할 때엔 Jinja2 템플릿 형식으로 적용할 수 있다.
Ansible Playbooks
# playbook.yml
-
name: Play 1
hosts: localhost
tasks:
- name: Execute command 'date'
command: date
- name: Execute script
script: test_script.sh
-
name: Play 2
hosts: localhost
tasks:
- name: Install web service
yum:
name: httpd
state: present
- name: Start web server
service:
name: httpd
state: startedAnsible Playbook 은 Ansible 이 target systems 에 적용할 Play 들을 모아두는 YAML 파일이다. 각 Play 는 target host 에 순차적으로 적용할 tasks 를 포함한다. Task 는 name 과 module 로 이루어지는데 여기서 module 은 command, script, yum, service 을 의미한다.
ansible-playbook playbook.yml
위 커맨드로 Playbook 을 실행할 수 있다.
ansible-playbook install_nginx.yml --check
check mode 로 실행 시 어떤 호스트에 변경이 일어날 지 확인할 수 있다. 모든 module 이 check mode 를 지원하진 않는다.
ansible-playbook configure_nginx.yml --check --diff
diff mode 를 함께 사용하면 어떤 변경점이 있는지 역시 확인할 수 있다.
ansible-playbook configure_nginx.yml --syntax-check
syntax-check mode 로 Playbook 의 오타를 찾아낼 수도 있다.
Ansible Conditionals
---
- name: Install NGINX
hosts: all
tasks:
- name: Install NGINX on Debian
apt:
name: nginx
state: present
when: ansible_os_family == "Debian" and
ansible_distribution_version == "16.04"
- name: Install NGINX on Redhat
yum:
name: nginx
state: present
when: ansible_os_family == "RedHat" or
ansible_os_family == "SUSE"Ansible 에선 Play 내 when 필드를 통해 적용될 task 를 조건부로 실행할 수 있다.
---
- name: Install Softwares
hosts: all
vars:
packages:
- name: nginx
required: True
- name: mysql
required: True
- name: apache
required: False
tasks:
- name: Install "{{ item.name }}" on Debian
apt:
name: "{{ item.name }}"
state: present
when: item.required == True
loop: "{{ packages }}"또한 loop 와 vars 를 조합하여 필요한 task 만 실행되게끔 작성도 가능하다.
Ansible Loops
- name: Create users
hosts: localhost
tasks:
- user: name='{{ item.name }}' state=present uid='{{ item.uid }}'
loop:
- name: joe
uid: 1010
- name: george
uid: 1011Ansible 에선 task 내에서 loop 를 돌릴 수 있고 각 요소를 item 을 통해 참조할 수 있다.
- name: Check multiple mongodbs
hosts: localhost
tasks:
- debug: msg="DB={{ item.database }} PID={{ item.pid }}"
with_mongodb:
- database: dev
connection_string: "mongodb://dev.mongo/"
- database: prod
connection_string: "mongodb://prod.mongo/"비슷하게 with_ 로 시작하는 필드들이 있는데 이는 loop 와 같은 방식으로 작동한다.
Ansible Modules
Ansible 은 target node 에 실행할 명령들을 module 을 통해 작성한다. User, Group, Iptable 등 System 수준의 설정에서 부터 Shell Script 등을 실행할 수 있는 Command 수준, Copy, Lineinfile 등 File 수준, Database, Cloud 수준 등 다양한 module 이 존재한다.
Command
- name: Play 1
hosts: localhost
tasks:
- name: Execute command 'date'
command: date
- name: Display resolv.conf contents
command: cat resolv.conf chdir=/etc이런 module 들은 다양한 parameter 를 제공하는데, command module 을 예로 chdir, creates 등 명령어를 실행하기 전에 필요한 옵션들이 존재한다.
Service
- name: Start Postgresql
hosts: localhost
tasks:
- name: Start the database service
service:
name: postgresql
state: startedService module 의 state 의 경우 started 를 통해 서비스가 실행중이지 않을 때만 실행하여 idempotency 를 보장한다.
Fileinline
- name: Add DNS server to resolv.conf
hosts: localhost
tasks:
- lineinfile:
path: /etc/resolv.conf
line: 'nameserver 10.1.250.10'lineinfile module 의 경우 echo script 를 사용하는 것과 다르게 한 번의 라인 추가만 작동한다는 것 역시 idempotency 를 보장한다.
Ansible Roles
Ansible 에서 Role 은 사람이 직업을 가지듯 target system node 가 mysql 을 호스팅할 지 nginx 를 호스팅할 지 역할을 부여하는 개념이다.
- name: Install and Configure MySQL
hosts: db-server
tasks:
- name: Install Pre-Requisites
yum:
name: pre-req-packages
state: present
- name: Install MySQL Packages
yum:
name: mysql
state: present
- name: Start MySQL Service
service:
name: mysql
state: present
- name: Configure Database
mysql_db:
name: db1
state: present가령 MySQL 을 호스팅하기 위해선 위와같은 tasks 가 필요하다고 하자.
- name: Install and Configure MySQL
hosts: db-server1 ... db-server100
roles:
- mysqlMySQL-Role 을 위한 tasks 만 따로 모아서 다른 파일에 저장한 뒤 Playbook 에서 참조해서 사용하도록 구성할 수 있다.
my-playbook/
- playbook.yml
- roles/
- mysql/
- templates/
- tasks/
- handlers/
- vars/
- defaults/
- meta/
Role 을 사용할 경우 위와 같은 file structure 로 사용하거나 /etc/ansible/roles directory 에 저장하여 전역에서 사용할 수도 있다.