이 글은 CloudNet@ 팀 gasida님의 스터디 A101 1기 내용 및 실습으로 작성된 글입니다.
반복문
1. 단순 반복문
- loop 키워드를 작업에 추가하면 반복해야 하는 작업을 항목의 목록을 값으로 사용한다.
sshd와 rsyslog 서비스가 시작되어 있지 않다면, 시작하는 명령의 yml 파일을 생성한다.
---
- hosts: all
tasks:
- name: Check sshd and rsyslog state
ansible.builtin.service:
name: "{{ item }}"
state: started
loop:
- sshd
- rsyslog
사용하는 아이템을 변수에 저장하면 loop 키워드에서 변수 목록을 변수로 사용할 수 있다.
---
- hosts: all
vars:
services:
- sshd
- rsyslog
tasks:
- name: Check sshd and rsyslog state
ansible.builtin.service:
name: "{{ item }}"
state: started
loop: "{{ services }}"
2. 사전 목록에 의한 반복문
- 하나의 아이템을 사용할 수도 있지만, 동시에 다른 여러 개의 아이템이 필요할 때, loop문에서 사전 목록으로 사용할 수 있다.
log 파일을 생성하면서, mode로 권한을 바꾸는 파일을 생성하여 실행한다.
실행할 때 실제 로그 파일이 잘 생성되는지 watch를 걸어서 모니터링하고, 실제 ansible-playbook이 돌 때 log 파일이 생기면서 권한이 바뀌는 것을 확인할 수 있었다.
---
- hosts: all
tasks:
- name: Create files
ansible.builtin.file:
path: "{{ item['log-path'] }}"
mode: "{{ item['log-mode'] }}"
state: touch
loop:
- log-path: /var/log/test1.log
log-mode: '0644'
- log-path: /var/log/test2.log
log-mode: '0600'
3. 반복문과 Register 변수 사용
- 반복실행되는 작업들이 모두 정상적으로 잘 수행되었는지 확인할 수 있고, 이 값을 이용해서 다음 작업을 수행할수도 있다.
shell 모듈을 이용하여 "I can speak ~" 라는 메시지를 출력하게 하고, loop 키워드를 사용해 Korean과 English가 사용되도록 아이템을 나열한다.
그리고 결과를 result 변수로 저장하여 debuh 모듈을 통해 내용을 확인한다.
---
- hosts: localhost
tasks:
- name: Loop echo test
ansible.builtin.shell: "echo 'I can speak {{ item }}'"
loop:
- Korean
- English
register: result
- name: Show result
ansible.builtin.debug:
var: result
register 키워드에 저장된 result 내용에는 대괄호 사이에 Key-Value 쌍으로 구성된 결과 값이 모두 저장되며, 배열 형식으로 출력된 것을 확인할 수 있다.
출력 결과를 보면 Korean과 English가 각각 2개의 Item으로 출력된 것을 확인할 수 있다.
---
- hosts: localhost
tasks:
- name: Loop echo test
ansible.builtin.shell: "echo 'I can speak {{ item }}'"
loop:
- Korean
- English
register: result
- name: Show result
ansible.builtin.debug:
msg: "Stdout: {{ item.stdout }}"
loop: "{{ result.results }}"
위와 같이 출력 값을 stdout을 사용하여 한 줄(표준 출력)로 출력할 수 있는데, 확실히 위에서 편하게 볼 수 있던 것과 달리 이번에는 조금 보기 불편하게 출력되었다.
조건문
1. 조건 작업 구문
- when 문은 조건부로 작업을 실행할 때 테스트할 조건을 값으로 사용하며, 조건이 충족되면 작업을 실행하고 조건을 충족하지 않는다면 작업을 건너뛴다.
- when 문을 테스트하는 가장 쉬운 조건 중 하나는 Boolean 변수가 True, False 여부이다.
run_my_task 변수가 true로 값을 주고, when문에서 run_my_task를 사용하면 true일 때만 작업을 실행한다.
---
- hosts: localhost
vars:
run_my_task: true
tasks:
- name: echo message
ansible.builtin.shell: "echo test"
when: run_my_task
register: result
- name: Show result
ansible.builtin.debug:
var: result
run_my_task 값을 false 수정 후 playbook을 실행하니, skipped 된 것을 확인할 수 있다.
2. 조건 연산자
- when문에 bool 변수 외에도 조건 연산자를 사용할 수 있다.
- != : 값이 같지 않을 때 참 (true)
- >, >=, <=, < : 초과, 이상, 미만, 이하 일 때 참 (true)
- not : 조건의 부정
- and, or : 그리고, 또는 의 의미로 여러 조건으로 조합 가능
- in : 값이 포함된 경우에 true
- in defined: 변수가 정의된 경우 true
var 키워드로 supported_distro라는 변수를 주어, ansible_facts의 값이 Ubuntu 나 Centos이면 true (출력)
---
- hosts: all
vars:
supported_distros:
- Ubuntu
- CentOS
tasks:
- name: Print supported os
ansible.builtin.debug:
msg: "This {{ ansible_facts['distribution'] }} need to use apt"
when: ansible_facts['distribution'] in supported_distros
2. 복수 조건문
- when 문은 단일 조건문 뿐만 아니라 복수 조건문도 사용할 수 있다.
1. 운영체제가 CentOS이거나 Ubuntu일 경우에 작업이 수행되도록 yml 파일을 생성하여 실행해본다. (해당 when 문에는 or (또는) 조건을 사용)
---
- hosts: all
tasks:
- name: Print os type
ansible.builtin.debug:
msg: "OS Type {{ ansible_facts['distribution'] }}"
when: ansible_facts['distribution'] == "CentOS" or ansible_facts['distribution'] == "Ubuntu"
2. 운영체제가 Ubuntu이고, 해당 OS의 버전이 22.04인 경우에만 작업이 수행되도록 yml 파일을 생성하여 실행해본다. (해당 when 문에는 and(그리고) 조건을 사용, 두 개의 조건이 일치해야 실행됨.)
---
- hosts: all
tasks:
- name: Print os type
ansible.builtin.debug:
msg: >-
OS Type: {{ ansible_facts['distribution'] }}
OS Version: {{ ansible_facts['distribution_version'] }}
when: ansible_facts['distribution'] == "Ubuntu" and ansible_facts['distribution_version'] == "22.04"
ubuntu@server:~/my-ansible$ hostnamectl
Static hostname: server
Icon name: computer-vm
Chassis: vm
Machine ID: ec29acc53df305fd06148dbcea6601ca
Boot ID: ad28e87c32bb4c6ebb5f6e10455cad21
Virtualization: amazon
Operating System: Ubuntu 22.04.3 LTS
Kernel: Linux 6.2.0-1017-aws
Architecture: x86-64
Hardware Vendor: Amazon EC2
Hardware Model: t3.medium
os의 버전이 ubuntu 22.04.3 버전인 것을 확인할 수 있고, 위에서 기재한 조건문 운영체제가 Ubuntu이고, OS의 버전이 22.04인 조건이 맞았기 때문에 실행된 것이다.
만약에 조건이 하나라도 틀어지면 어떻게 되나 보려고 조건문에 OS 버전을 22.02로 바꾸어서 다시 실행했더니 조건이 맞지 않아 모두 skipped 된 것을 볼 수 있다.
3. 반복문과 조건문을 함께 사용
ansible facts에서 mounts라는 타입의 변수 값을 반복(현재 mount된 것들을 확인)하면서, mount가 "/"이고, size_available의 값이 "300000000"보다 큰 경우에만 메시지를 출력하고, 그렇지 않을 경우에는 작업을 건너뛰는 조건문 파일을 만들어서 실행해본다.
기존 cache가 아닌 새로운 cache로 수집을 하기위해 기존 cache를 삭제하고, ansible을 사용할 때 다시 cache 하도록 명령어를 추가하여 어떤 변화가 있을 지 watch 명령어로 모니터링을 걸어둔 상태로 yml을 실행했다.
---
- hosts: db
tasks:
- name: Print Root Directory Size
ansible.builtin.debug:
msg: "Directory {{ item.mount }} size is {{ item.size_available }}"
loop: "{{ ansible_facts['mounts'] }}"
when: item['mount'] == "/" and item['size_available'] > 300000000
수집된 mount 파일은 많지만 조건에 많지 않아 skpping 된 것을 볼 수 있고, 한개의 mount 파일만 조건에 만족한 것을 확인할 수 있다.
핸들러 및 작업 실패 처리
1. 앤서블 핸들러
- 앤서블에서 핸들러를 사용하려면, notify 문을 사용해서 명시적으로 호출된 경우에만 사용할 수 있고, 핸들러를 정의할 때 같은 이름으로 여러 개의 핸들러를 정의하기 보다 각각의 고유한 이름으로 정의하는 것이 좋다.
rsyslog 재시작 작업이 실행되면 notify(핸들러) 키워드를 통해 print msg라는 핸들러를 호출하도록 플레이북을 생성하였으며, 핸들러는 handlers 라는 키워드로 시작한다.
---
- hosts: tnode2
tasks:
- name: restart rsyslog
ansible.builtin.service:
name: "rsyslog"
state: restarted
notify:
- print msg
handlers:
- name: print msg
ansible.builtin.debug:
msg: "rsyslog is restarted"
2. 작업 실패 무시
- 앤서블은 작동 시 각 작업의 반환 코드를 평가하여 작업의 성공 여부를 판단하고, 일반적으로 작업을 실패하면 앤서블은 그 이후의 모든 작업을 건너뛴다. 하지만 작업이 실해되어도 계속 실행할 수 있도록 ignore_erros 라는 키워드로 구현할 수 있다.
apache3라는 apt는 없기 때문에 (2는 있음) 실패되었을 때 다음 작업을 어떻게 처리하나 보기 위해 각각 yml 파일을 생성하였다.
---
- hosts : tnode1
tasks:
- name: Install apache3
ansible.builtin.apt:
name: apache3
state: latest
- name: Print msg
ansible.builtin.debug:
msg: "Before task is ignored"
---
- hosts : tnode1
tasks:
- name: Install apache3
ansible.builtin.apt:
name: apache3
state: latest
ignore_errors: yes
- name: Print msg
ansible.builtin.debug:
msg: "Before task is ignored"
1번 파일은 실패가 되자마자 바로 failed가 되어버려 결과 값에서도 failed=1이 된 것을 확인할 수 있었고, ignore_errors가 들어간 2번 파일을 실패하니까 ignoring 이라고 뜨면서 다음 작업 (메시지를 프린트)을 실행하여 결과 값에도 ignored=1 이 뜬 것을 볼 수 있다.
2. 작업 실패 후 핸들러 실행
- 앤서블은 일반적으로 작업이 실패하고 해당 호스트에서 실행이 중단되면 이전 작업에서 받은 알림을 모든 핸들러가 실행하지 않는다. 하지만, 플레이북에 force_handlers 라는 키워드를 추가하게 되면, 이후 작업이 실패하여 실행이 중단되어도 알람을 받은 핸들러가 호출된다.
force_handlers=yes를 추가하지 않은 파일과, force_handlers=yes를 추가한 파일을 생성하여 playbook을 실행해보았다.
---
- hosts: tnode2
tasks:
- name: restart rsyslog
ansible.builtin.service:
name: "rsyslog"
state: restarted
notify:
- print msg
- name: install apache3
ansible.builtin.apt:
name: "apache3"
state: latest
handlers:
- name: print msg
ansible.builtin.debug:
msg: "rsyslog is restarted"
---
- hosts: tnode2
force_handlers: yes
tasks:
- name: restart rsyslog
ansible.builtin.service:
name: "rsyslog"
state: restarted
notify:
- print msg
- name: install apache3
ansible.builtin.apt:
name: "apache3"
state: latest
handlers:
- name: print msg
ansible.builtin.debug:
msg: "rsyslog is restarted"
1번 파일은 실패가 되자마자 바로 failed가 되어버려 핸들러가 실행되지 않은 것을 확인할 수 있었고, force_handlers=yes가 들어간 2번 파일은 실패해도 이전에 정상적으로 수행되었던 부분에 대해서 핸들러 작업 (메시지를 프린트)이 실행된 것을 확인할 수 있다.
3. 작업 실패 조건 지정
- command 계열 모듈을 사용 시, 앤서블에서 셸 스크립트를 실행한 후에 결과로 실패나 에러 메시지를 출력해도 앤서블은 해당 작업이 성공했다고 인지한다. 어떤 명령이라도 실행된 경우에는 task 실행 상태를 항상 changed 로 한다. 이런 경우 failed_when을 사용하여 작업이 실패했을 때를 나타내는 조건을 지정할 수 있다.
책 저자분께서 만들어주신 스크립트를 사용하여 실습을 진행해보았다.
사용자를 추가하는 스크립트 파일을 tnode1에 복사 후 확인하고, shell 모듈 사용하는 태스트를 사용하여 플레이북을 생성한다. 1개는 failed_when 조건식이 없는 yml, 1개는 failed_when 조건식이 들어간 yml 파일을 만들어 실행한다.
---
- hosts: tnode1
tasks:
- name: Run user add script
ansible.builtin.shell: /home/ubuntu/adduser-script.sh
register: command_result
- name: Print msg
ansible.builtin.debug:
msg: "{{ command_result.stdout }}"
---
- hosts: tnode1
tasks:
- name: Run user add script
ansible.builtin.shell: /home/ubuntu/adduser-script.sh
register: command_result
failed_when: "'Please input user id and password' in command_result.stdout"
- name: Print msg
ansible.builtin.debug:
msg: "{{ command_result.stdout }}"
1번의 경우 계정 정보를 넣어주지 않아 계정 생성을 실패했음에도 ok라는 결과를 보여주고, 2번의 경우 failed 이라는 결과 값을 보여준다.
만약 잡아내고 싶은(?) 문구가 많다면, 그걸 다 넣어줘야해서 엄청 편한 거라고 말하기는 어려울 것 같다는 생각이 들었다.
4. 앤서블 블록 및 오류처리
- 앤서블은 block이라는 오류를 제어하는 문법을 제공하고, 이것은 작업을 논리적으로 그룹화하는 문법절이며 작업 실행 방법을 제어하는데 사용할 수 있다. 그리고 블록문을 통해 rescue과 always를 함께 사용해서 오류를 처리할 수 있다.
- block : 실행할 기본 작업을 정의
- rescure : block에 정의된 작업이 실패했을 때 실행할 작업을 정의
- always : block 및 rescue 절에 정의된 작업의 성공, 실패 여부와 관계 없이 항상 실행되는 작업을 정의
---
- hosts: tnode2
vars:
logdir: /var/log/daily_log
logfile: todays.log
tasks:
- name: Configure Log Env
block:
- name: Find Directory
ansible.builtin.find:
paths: "{{ logdir }}"
register: result
failed_when: "'Not all paths' in result.msg"
rescue:
- name: Make Directory when Not found Directory
ansible.builtin.file:
path: "{{ logdir }}"
state: directory
mode: '0755'
always:
- name: Create File
ansible.builtin.file:
path: "{{ logdir }}/{{ logfile }}"
state: touch
mode: '0644'
Find Directory를 실패하여 rescue 구문을 통해 디렉터리가 없기 때문에 디렉터리를 생성했고, always 구문을 통해 로그 파일을 생성한 것을 볼 수 있다.
tnode2에 해당 경로를 보면 위와 같이 log 파일이 있는 것을 확인할 수 있다.
'CloudNetaStudy > [Study] Ansible' 카테고리의 다른 글
[4주차] 보안설정 / 모니터링 자동화 (0) | 2024.02.09 |
---|---|
[3주차] 시스템 구축 및 환경 설정 자동화 (0) | 2024.02.02 |
[1주차] Ansible 개념과 설치 (0) | 2024.01.11 |