배포 자동화 툴
Good Point
- 사용하기 쉬움(스크립트 방식이 아닌 설정기반)
- 멀티플랫폼지원
- Agent 기반이 아닌 SSH 기반으로 스크립트 배포 없이 관리 서버에서 실행 가능
- 멱등성(여러 번 적용하더라도 결과동일) 보장하는 모듈지원
- 순차 실행뿐 아니라 병렬 실행 지원
- 내부에서 JSON으로 통신 파이썬이 아닌 다른 언어로도 모듈 개발 가능
Link
Book
Word
- 컨트롤러장비
- ansible이나 playbook을 실행 시키는 장비
- 관리장비
- ansible로 원격으로 관리하는 장비
- 인벤토리
- 관리장비 그룹이나 리스트를 갖고있는 것
- 플레이
Install
OSX
brew install ansible
도움말
ansible-doc -l
ansible-doc file
Playbook
- ansible script 모음 하나 이상의 플레이로 구성
ansible-playbook example-play.yml
target
- 플레이가 실행될 장비와 어떻게 플레이가 실행될 것인지 정의
- SSH 사용자 이름과 다른 SSH와 관계된 설정을 지정
- hosts: webservers
users: root
sudo: yes // root 권한 획득을 위해 사용
user: flynn // sudo 실행 전에 장비에 연결한 사용자 이름 정의
sudo_user: root // sudo 사용을 시도하여 되려는 사용자 정의
connection: ssh // 원격장비 연결하기 위해 사용할 수 있는 전송 방법 정의(ssh, paramiko, local)
gather_facts: yes // setup 모듈 결과 사용여부 태스크 수행시간을 줄일 수 있음
vars
- 기본값 유지가 되지 않음, 장비 팩트나 인벤토리에서 설정한 변수로 인해 오버라이드 됨
- 플레이에서 실행할 때 쓰일 사용 가능한 변수를 정의
vars:
nginx_version: 1.9.1
motd_warning: 'WARNING: Use by Flynn Only'
testservers: yes
변수 파일을 통해 로드
vars_files:
/conf/test.yml
사용자 프롬프트를 통해서 받음
vars_prompt:
- name:'https_passpharase'
prompt: 'Key Passphrase'
private: yes
task
- 앤시블을 이용하여 실행하고 싶은 모든 모듈을 순서대로 열거
- name은 필수 값은 아니다. 하지만 유지보수를 위해서 작성하는 것을 추천
- 콘솔에 name이 있으면 함께 출력됨 없으면 action 내용 출력
tasks:
// action: 모듈명령
- name: install nginx
action: yum name=nginx state=installed
// ansible이 추천 하는 방식
// module이름: 필요한 인수나열
- name: configure nginx
copy: src=files/nginx.conf dest=/etc/nginx/nginx.conf
// 인수 여러줄로 나열
- name: restart nginx
service:
name:nginx
state: restarted
handler
- 태스크와 동일한 형식 단 태스크나 핸들러에 의해서만 호출됨
- 태스크 리스트가 종료 된 다음 호출됨
- 핸들러가 여러번 호출 되어도 한번만 수행됨
- 태스크의 변경이 발생할때만 호출됨
- 각 핸들러는 하나의 모듈만 수행됨
- 태스크에서 여러 핸들러를 호출 할수 있음
handlers:
- name: restart nginx
action: service name=nginx state=restarted
Modules
- ping
- ansible 동작이 잘되는지 확인
ansible machine-name -m ping
- setup
- 관리 장비 정보 반환
ansible machine-name -m setup
- file
- file관련 모듈 읽기/쓰기/삭제/변경 가능
ansible machine-name -m file -a 'path=/etc/fstab'
ansible machine-name -m file -a 'path=/tmp/test state=directory mode=0700 owner=root'
ansible machine-name -m file -a 'path=/tmp/test state=absent'
- copy
- 컨트롤러 장비에서 관리 장비로 파일 복사
ansible machinename -m copy -a 'src=/etc/fstab dest=/tmp/fstab'
- command
- 관리 장비에서 임의의 커맨드를 실행 할 수 있음
- 멱등성 보장이 어려움(제한적으로 지원 ex> creates, removes)
ansible machinename -m command -a 'rm -rf /tmp/testing removes=/tmp/testing'
- shell
- 리다이렉션, 파이프 또는 백그라운드 작업을 사용가능
- 멱등성을 제한적으로 지원(ex > creates 인수만 지원)
ansible machinename -m shell -a '/opt/testapp/install.sh > /var/log/testapp.log creates=/var/log/testapp.log'
- service
- 서비스 관련 모듈
- template
- 템플릿을 설정할 수 있는 모듈
- jinja2 템플릿을 지원
template: src=templates/named.conf.j2 dest=/etc/named.conf owner=root group=named mode=0640
- set_fact
- fact 추가
set_fact: innodb_buffer_pool_size_mb="{{ ansible_memtotal_mb / 2 }}
- pause
- 플레이북 실행동안 일시정지를 할수 있는 모듈
- 사용자 입력으로 진행여부 확인
pause: prompt="Wanring! Enter to continue CTRL-C a to quit"
- 특정 시간만 대기
pause: seconds=30
- wait_for
- 특정 TCP 포트를 폴링, 원격 연결 수락될때까지 대기
- 폴링은 원격 장비에서 이루어짐
wait_for: port=8080 state=started
- assemble
- 관리 장비에서 여러 개의 파일을 합치고 관리 장비의 다른 파일로 저장한다.
assemble: src=/opt/sshkeys dest=/root/.ssh/authorized_keys owner=root group=root mode=0700
- add_host
- 동적으로 플레이에 새로운 장비를 추가
add_host:
group_by
- 동적으로 그룹 생성
---
- name: Create operating system group
hosts: all
tasks:
- group_by: key=os_{{ ansible_distribution }}
- name: Run on CentOS hosts only
hosts: os_CentOS
tasks:
- name: Install Nginx
yum: name=nginx state=latest
- name: Run on Ubuntu hosts only
hosts: os_Ubunutu
tasks:
- name: Install Nginx
apt: pkg=nginx state=latest
병렬로 작업 실행
- task에 async와 poll 을 추가한다.
tasks:
- name: Install mlocate
yum: name=mlocate state=installed
- name: Run updatedb
command: /usr/bin/updatedb
async: 300 // 커맨드가 완료될 때까지 앤시블이 기다려 줄 수 있는 최대 값
poll: 10 // 커맨드가 완료될 때를 점검하기 위해 얼마나 자주 폴링
poll 0 // 앤시블이 완료를 기다리지 않음
async 0 // 작업을 완료할 때까지 기다림
Looping
- 반복적인 태스크를 처리 할 때 사용 with_items, with_fileglob을 활용
- 비슷한 설정으로 모듈을 많이 반복
- 하나의 목록인 팩트의 모든 값을 반복
- 하나의 큰 파일로 결합할 assemble 모듈과 함께 나중에 사용할 수 있는 많은 파일을 생성하기 위해 사용
- glob 패턴 매칭을 사용 중인 디렉토리를 복사하기 위해 with_fileglob를 사용
tasks:
- name: Secure config files
file: path=/etc/{{ item }} mode=0600 owner=root group=root
with_items:
- my.cnf
- shadow
- fstab
// lookup 플러그인
tasks:
- name: Upload public keys
copy: src={{ item }} dest=/root/.sshkeys mode=0600 owner=root group=root
with_fileglob:
- keys/*.pub
조건절
- 특정 조건에서만 동작하도록 한다.
- 운영체제의 차이를 극복하며 작업
- 사용자에게 프롬프트를 보여 요청한 액션만 수행
- 뭔가를 변경하지 않고 실행하기에 오랜 시간이 소요될 수 있는 모듈을 피해 성능을 개선
- 특정한 파일이 존재하는 시스템의 변경을 거절
- 사용자가 작성한 스크립트가 이미 실행 중인지 체크
tasks:
- name: Install VIM via yum
yum: name=vim-enhanced state=installed
when: ansible_os_family == "RedHat"
- name: Install VIM via apt
apt: name=vim state=installed
when: ansible_os_family == "Debian"
- name: Unexpected OS family
debug: msg="OS Family {{ ansible_os_family }} is not supported" fail=yes
when: not ansible_os_family == "RedHat" or ansible_os_family == "Debian"
태스크 위임
- 다른 장비에서 액션 수행이 필요한 경우 사용
- 배포 전에 로드 밸런서로부터 장비를 제거하기
- 변경하려는 서버에서 트래픽을 빼는 DNS를 변경하기
- 저장 장치의 iSCI 볼륨을 생성하기
- 네트워크 작업 바깥에 접근을 점검할 수 있게 외부 서버를 사용하기
tasks:
- name: Get config
get_url: dest=configs/{{ ansible_hostname }} force=yes url=http://{{ ansible_hostname }}/diagnostic/config
delegate_to: localhost
// localhost에 위임하는 경우는 local_action
이 있음
tasks:
- name: Get config
local_action: get_url dest=configs/{{ ansible_hostname }} force=yes url=http://{{ ansible_hostname }}/diagnostic/config
추가변수
hostvars
- 현재 플레이가 다뤘던 모든 장비에 대한 변수를 얻을수 있음
{{ hostvars.[hostname].ansible_default_ipv4.address }}
groups
- 인벤토리 그룹에 의해 구분짓는 인벤토리의 모든 장비의 목록을 포함, 모든 장비와 모든 그룹에 반복할 수 있음
- name: Create a user for all app servers
with_items: groups.appservers
mysql_user: name=flynn password=test host={{ hostvars.[item].ansible_eth0.ipv4.address }} state present
group_names
- 현재 장비가 포함된 모든 그룹의 이름으로 문자열 목록을 포함
tasks:
- name: For secure machines
set_fact: sshconfig=files/ssh/sshd_config_secure
when: "'secure' in group_names"
- name: For non-secure machines
set_fact: sshconfig=files/ssh/sshd_config_default
when: "'secure' not in group_names"
- name: Copy over the config
copy: src={{ sshconfig }} dest=/tmp/sshd_config
inventory_hostname
- 인벤토리에서 저장된 서버의 장비 이름을 저장
inventory_hostname_short
- 인벤토리에서 저장된 서버의 장비 이름을 저장 중 첫 번째 점(.)까지의 캐릭터만 포함
inventory_dir
- 인벤토리 파일을 포함하는 디렉토리의 경로 이름
inventory_file
- inventory_dir에서 인벤토리 파일명이 추가된 이름
변수로 파일 찾기
copy: src=files/nrpe.{{ ansible_architecture }}.conf dest=/etc/nagios/nrpe.cfg
name: Get the best match for the machine
copy: dest=/etc/nginx.conf src={{ item }}
first_available_file:
- files/nginx/{{ ansible_os_family }}-{{ ansible_architecture }}.conf
- files/nginx/default-{{ ansible_architecture }}.conf
- files/nginx/default.conf
Environment
- environment로 환경 변수를 추가 할수 있음
- 애플리케이션 인스톨러 실행하기
- shell 모듈을 이용할 때 경로에 추가적인 요소를 추가하기
- 시스템 라이브러리 검색 경로에 포함되지 않은 장소로부터 라이브러리를 로딩하기
- 모듈을 실행하는 동안 LD_PRELOAD 해킹을 이용하기
name: Upload the file
shell: aws s3 put-object --bucket=my-test-bucket --key={{ ansible_hostname }}/fstab --body=/etc/fstab --region=eu-west-1
environment:
AWS_ACCESS_KEY_ID: XXXXXXXX
AWS_SECRET_ACCESS_KEY: XXXXXXXX
외부 데이터 검색
- conf.d 방식의 디렉토리에 모든 아파치 설정 디렉토리를 복사하기
- 플레이북이 무엇을 하는지 조정하기 위한 환경 변수 얻기
- DNS TXT 레코드에서 설정 얻기
- 커맨드 결과를 얻어 변수로 저장
직접 호출 방식
name: Download file
get_url: dest=/var/tmp/file.tar.gz url=http://server/file.tar.gz
environment:
http_proxy: "{{ lookup('env', 'http_proxy') }}"
with_* 사용하는 방식
name: Register the webapp farm
local_action: add_host name={{ item }} groupname=webapp
with_sequence: start=1 end=10 format=webapp%02x
결과 저장
- register 를 사용해서 결과를 저장한다.
- fetch 모듈로 원격 디렉토리에서 파일 목록을 얻고 모두 다운로드하기
- 핸들러가 실행하기 전, 앞 태스크가 변경할 때 태스크를 실행하기
- 원격 장비의 SSH키 내용을 얻어 known_hosts 파일을 만들기
- name: Get /tmp info
file: dest=/tmp state=directory
register: tmp
- name: Set mode on /var/tmp
file: dest=/tmp/subtmp mode={{ tmp.mode }} state=directory
Debug
debug
- 변수의 현재값 보기 좋음, msg는 출력 내용, fail은 진행여부 yes인 경우 멈춤
debug: msg="{{ item }}"
with_items: ansible_interfaces
verbose
- verbose모드일 경우 앤시블이 실행 이후 각 모듈에서 리턴된 모든 값을 출력
- register 키워드를 사용하고 있다면 유용
ansible-playbook --verbose playbook.yml
check / diff
- 실제 관리장비에 어떠한 변화를 주지 않고 실행 참고로 diff는 template 모듈이 생성한 변화만 출력
pause
- 잠시 멈출때 사용
Include
- 중복을 없애기 위해 사용
var include
task include
# usersetup.yml
# Requires a user variable to specify user to setup
- name: Create user account
user: name={{ user }} state=present
- name: Make user SSH config dir
file: path=/home/{{ user }}/.ssh owner={{ user }} group={{ user }} mode=0600 state=directory
- name: Copy in public key
copy: src=keys/{{ user }}.pub dest=/home/{{ user }}/.ssh/authorized_keys mode=0600 owner={{ user }} group={{ user }}
tasks:
- include: usersetup.yml user={{ item }}
with_items:
- niceilm
- flynn
handler include
handlers:
- include: sendmailhandlers.yml
playbook include
---
- include "drfailover.yml"
- include "upgradeapp.yml"
- include "drfailback.yml"
- name: Notify management
host: local
tasks:
- local_action: mail to="niceilm@naver.com" msg='The application has been upgraded and is now live'
- include "drupgrade.yml"
Role
Tag
ansible-pull
Error Handling In Playbooks
- name: cache
apt: purge=yes name=lxc-docker
ignore_errors: yes