ansible에서 log 파일 기록하기
ansible을 사용하면서 문제가 발생할 때 가장 먼저 확인할 수 있는 것은 ansible log이다. 이러한 log는 아래 방법으로 로그 파일을 기록할 수 있다. 이러한 log를 통해 ansible, ansible-playbook 명령의 출력을 저장하고 문제 발생시 이것을 확인하여 troubleshooting을 할 수 있다.
vi ansible.cfg
[defaults]
log_path = /home/student/troubleshoot-playbook/ansible.log
# 참고 : log 저장 위치
log 파일이 저장될 위치를 /var/log로 하려면, playbook을 root로 실행하거나, /var/log에 대한 권한 설정을 변경해야 한다. 또한 로그파일 관리를 위해 logrotate도 구성하도록 권고된다.
debug 모듈의 msg로 변수 확인하기
debug 모듈은 playbook이 실행되면서 특정 변수들에 대한 값을 직접 확인할 수 있다. 변수를 사용하는 playbook에서 디버깅을 할 때 사용할 수 있다. 예를 들어 작업 출력을 다음 작업의 입력으로 쓰는데, 그 값이 제대로 들어갔는지 확인할 때 사용한다.
debug 모듈은 2가지 방법으로 사용한다.
1. 메시지+변수를 출력 (msg 사용)
2. 변수를 출력 (var 사용)
---
- name: debug test
hosts: workstation.lab.example.com
tasks:
- name: debug test task
debug:
msg: "the free memory for this system is {{ ansible_facts['memfree_mb'] }}"
- name: display the "output" variable
debug:
var: ansible_facts['memfree_mb']
task 전체를 실행하지 않고, 일부만 실행하기
--start-at-task 옵션을 사용하면, 해당 플레이북의 task중 특정 task부터 끝까지 실행하게 할 수 있다. 즉 시작하는 task를 처음부터가 아닌 명시한 task부터 하게 하는 것이다. 예를들어 아래 예시를 보자.
---
- name: debug test
hosts: workstation.lab.example.com
tasks:
- name: debug test task
debug:
msg: "the free memory for this system is {{ ansible_facts['memfree_mb'] }}"
- name: display the output variable
debug:
var: ansible_facts['memfree_mb']
- name: third output
debug:
msg: "third task"
이 예시 파일에서 다음과 같이 실행하면, display the output variable 태스크부터 시작한다. (이 --start-at-task 옵션은 인수로 name을 받는다.)
ansible-playbook debugtest.yml --start-at-task="display the output variable"
원래 task가 3개여야 하는데, 중간에 display the output variable 태스크부터 시작해서 끝까지 수행하는 것을 알 수 있다.
디버깅 옵션
playbook을 실행할 때, -v 옵션을 사용하여 디버그 정보를 확인할 수 있다. 아래 예시처럼 사용할 수 있다.
ansible-playbook debugtest.yml -vv
-v |
출력 데이터가 표시된다. |
-vv |
출력 및 입력 데이터가 모두 표시된다. |
-vvv |
관리 호스트 연결에 대한 정보를 포함한다. |
-vvvv |
각 원격 호스트에서 실행되는 스크립트와 각 스크립트를 실행하는 사용자와 같은 추가 정보가 포함된다. |
플레이북을 관리할 때 권장사항
1. 플레이와 작업의 이름을 정하기 위해 플레이나 작업 목적에 대한 간결한 설명을 사용한다. 플레이 name, 작업 name은 플레이북이 실행되면 표시된다.
2. 작업에 대한 추가 인라인 설명서를 추가할 정의를 포함한다.
3. 세로 공백을 효율적으로 사용한다. 일반적으로 작업 속성을 세로로 구성하여 읽기 쉽게 만든다.
4. 일관된 수평 들여쓰기가 중요하다. 탭이 아닌 공백을 사용하여 들여쓰기 오류를 방지한다. 이를 쉽게 하기 위해 tab를 누르면 공백을 쓰도록 텍스트 편집기를 설정한다.
5. 가능한 간단하게 플레이북을 유지한다. 필요한 기능만.
문제 검증 예시
위 예시처럼 Failed to connect to the host via ssh: ssh: Could not resolve hostname servera.lab.example.com: Name or service not known 이런식으로 뜬다면, 여러가지를 해볼 수 있지만 먼저 해볼 것은 아래 4가지이다.
1.해당 관리 호스트 servera.lab.example.com 이 살아있는지 핑으로 확인
2. ssh 접속이 잘 되는지 확인, ssh 키가 있는지 확인
3. 더 자세한 정보를 얻기위해 -vvvv 옵션으로 실행.
4. inventory 파일의 철자 확인
테스트 도구로 검사 모드 사용하기
- 테스트를 위해 두가지 옵션을 사용할 수 있다.
* --check 옵션
ansible-playbook --check playbook.yml
이 옵션은 검사모드로, 즉 관리 호스트의 구성을 변경하지 않고 (즉 효력이 없고) 플레이북을 실행한다. 플레이북 내에서 사용된 모듈이 검사 모드를 지원하는 경우 관리 호스트에서 변경한 사항이 표시되지만 수행되지 않는다. 검사 모드가 모듈에서 지원되지 않으면 변경 사항은 표시되지 않지만, 모듈은 여전히 조치를 취하지 않는다. 참고로, 작업에서 조건문을 사용하는 경우, --chcek 명령이 제대로 작동하지 않을 수 있다. 유의할 것.
* --diff 옵션
클라이언트의 템플릿 파일에 변경이 가해졌다면, 그 변경 사항을 보고한다. 이 옵션을 사용할 수 있는 모듈이 따로 정해져 있다. 아래 예시는 template 모듈을 사용했고, 다른 모듈도 사용할 수 있는지는 확인해보아야 한다.
* --check, --diff 옵션 사용 예시
test.j2
{% if users is defined and users %}
{% for user in users %}{{ user }}
{% endfor %}
{% endif %}
jinja2test.yml
---
- hosts: 127.0.0.1
tasks:
- name: Test jinja2template
template:
src=test.j2
dest=test.conf
vars:
users:
- mike
- smith
- clare
- alex
아무 파일도 없으므로, 붉은색 --- before 부분에는 아무것도 나오지 않는다. 그리고 mike, smith, klare, alex가 추가되었다는 것을 알 수 있다.
이제 jinja2test.yml 을 다음과 같이 변수를 수정해보자.
---
- hosts: 127.0.0.1
tasks:
- name: Test jinja2template
template:
src=test.j2
dest=test.conf
vars:
users:
- 1234
- 112
- 4038
- 0327
그리고 다시 실행하면, 아래와 같이 붉은색은 before, 이전 값이고, 녹색은 이번에 적용된 값을 확인할 수 있다. 그런데 --check 옵션을 썼으므로 결과만 확인이 가능하고 실제로 적용되지는 않는다.
디버깅이나 상태에 대한 추가정보를 제공하는 모듈들
* uri 모듈
-RESTful API가 필요한 콘텐츠를 반환하는지 확인하는 방법을 제공한다.
- name: test
hosts: web1.example.com
tasks:
- uri:
url: http://api.myapp.com
return_content: yes
register: apiresponse
- fail:
msg: 'version was not provided'
when: "'version' not in apiresponse.content"
* script 모듈
script 모듈은 관리 호스트에서 스크립트 실행을 지원하고 해당 스크립트의 반환 코드가 0이 아닌 경우 실패한다. 스크립트는 제어 노드에 있어야 하며 관리 호스트로 전송되어 실행된다.
- name: test
hosts: web1.example.com
tasks:
- script: check_free_memory
* fail 모듈
- fail 모듈 task가 실행되면, 그 시점에서 fail이 발생하고 플레이북은 중단된다. 따라서 조건문을 넣어서 자주 사용한다.
- name: show failed system requirements message
fail:
msg: "the {{ inventory_hostname }} did not meet minimum reqs."
when: >
ansible_memtotal_mb*1024*1024 < min_ram_megabytes*1000000 or
ansible_distribution != "redhat"
- 위 예시는 2개의 조건 중 하나라도 만족하면 fail을 발생시키고 메시지를 뿌리는 것이다.
* stat 모듈
stat 모듈은 stat 명령과 유사하게 파일에 대한 사실을 수집한다. 이를 사용해 번수를 등록하고 테스트하여 파일이 존재하는지 또는 파일에 대한 다른 정보를 얻을 수 있는지 테스트할 수 있다.
즉, 특정 파일에 대해 stat 모듈을 사용하며, 그 파일이 존재하면 stat 결과에 포함되는 값인 [register변수.stat.exists]에 true를 보고하고, ok가 된다. (changed가 아님) 만약 그 파일이 존재하지 않는다면, stat 결과에 포함되는 값인 [register변수.stat.exists]에 false를 보고한다. 따라서 이 false, true를 가지고 뭔가 작업을 수행할 수 있다.
아래 예제는 특정 파일이 존재하면 playbook을 fail시켜서 중단시키는 예제이다. fail 모듈은 조건이 true이면 해당 playbook을 fail시키고 중단시킨다.
---
- hosts: 127.0.0.1
tasks:
- name: check if /var/run/app.lock exists
stat:
path: /var/run/app.lock1
register: lock
- name: fail if the application is running
fail:
when: not lock.stat.exists
파일이 존재하는 경우 이렇게 레지스터 변수의 stat의 exists가 true가 나온다. 그리고 true이므로 조건문에 따라 fail 부분은 skip 하게 된다. 서비스가 살아있으면, 즉 파일이 존재하면 not true이므로 false가 된다. 그러면 fail을 실행하지 않는다.
만약 파일 이름을 바꿔서 파일이 없는것처럼 되었다면, 아래처럼 레지스터 변수의 stat의 exists가 false가 나온다. 그리고 false 이므로 조건문에 따라 fail이 진행되고 플레이가 중단된다. 서비스가 죽어있으면, 즉 파일이 없으면 not false이므로 true가 된다. 그러면 fail을 실행한다.
* assert 모듈
assert 모듈은 fail 모듈에 대한 대안이다. 이 모듈은 조건문 "목록"을 취하는 that 옵션을 지원한다. 여러 조건이 있을 때 이러한 조건문 중 하나가 false이면 작업이 실패한다.
---
- hosts: 127.0.0.1
tasks:
- name: check if /var/run/app.lock exists
stat:
path: /var/run/app.lock1
register: lock
- name: fail if the application is running
assert:
that:
- lock.stat.exists
stat 모듈 예시와 동일하지만 that 이하에 조건이 not이 빠졌다. 여기서는 해당 조건이 false가 나면 fail이 되어 playbook이 중단되기 때문이다. 따라서 위 구문은 파일이 존재해서 true를 받으면, 그대로 assert에서도 true를 받아 아무일도 일어나지 않는다.
만약 파일이 없다면, 파일이 없으므로 false가 나오고, 그대로 assert에서도 false를 받아 playbook이 중단된다.
연결 문제를 진단하기
일반적으로 연결 자체에 대한 문제는 호스트 연결 및 원격 사용자와의 권한 에스컬레이션 관련하여 문제가 많이 발생한다. 이러한 문제가 발새하는 경우 아래 내용을 검토한다.
- 클라이언트에 인증하는데 문제가 있다면, 구성 파일이나 플레이에서 remote_user를 올바르게 썼는지 확인
- 올바른 ssh 키를 설정했는지, 올바른 암호를 제공했는지 확인
- become이 올바르게 설정되어있고 올바른 become_user를 사용하는지 확인 (default는 root이다)
- 올바른 sudo 암호를 입력하며 관리 호스트에 sudo 설정이 잘 되어있는지 확인
ansible-playbook을 실행하다 중간에 에러가 났다면?
- ansible은 플레이북에 포함되고 해당 모듈에서 수행한 구성이 올바른지 확인하도록 설계되었다.
- 모든 모듈에서 보고된 오류를 모니터링하고 오류가 발생하면 플레이북을 바로 중지한다.
- 이렇게 하면 오류 이전에 수행된 작업에는 오류가 없다.
- 그러므로 앤서블에서 관리한 작업의 결과가 관리 호스트에서 올바르게 적용되었는지 일반적으로 확인하지 않아도 된다.
- 직접 문제를 해결해야 하는 경우 플레이북에 몇 가지 상태 검사를 추가하거나, 애드혹 명령으로 그러한 상태 검사를 실행하는 것이 좋다.
- 하지만 모듈 자체에서 수행하는 테스트를 다시 확인하기 위해 작업 및 플레이를 너무 복잡하게 만드는건 조심해야 한다.
예제 - 문제가 발생하는 것 확인하고 해결하기
* inventory 파일 내용
* ansible.cfg 파일 내용
* 템플릿 파일 내용 (postfix-relay-main.conf.j2)
* 사용할 yml 파일
* 결과
ansible-playbook mailrelay.yml --check 로 실행
task들을 쭉 보면, 설치 및 서비스 시작 등이 잘 시작되었는데도, 에러가 난다. 이 이유는 알고보니 그냥 --check로 실행했기 때문에 실제로 설치가 되지 않아 실제 작업 구문이 fail이 난 것이다. 아래처럼 애드혹 명령으로 확인해보니, /etc/postfix/main.cf 파일이 없다고 한다.
--check를 빼고 실행하면, 아래와 같이 잘 실행된다.
결과 부분에 Ansible managed라고 뜨는것은 , 템플릿 파일에 {{ ansible_managed }} 라고 해 두었고 ansible.cfg에 설정했기 때문이다. 15장 참고
2021.02.26 - [Ansible] - 15장. ansible에서 jinja2 사용하기
참조링크
ansible 구성
https://docs.ansible.com/ansible/2.7/installation_guide/intro_configuration.html
debug
https://docs.ansible.com/ansible/2.7/modules/debug_module.html
모범 사례
https://docs.ansible.com/ansible/2.7/user_guide/playbooks_best_practices.html
검사 모드
https://docs.ansible.com/ansible/2.7/user_guide/playbooks_checkmode.html
테스트 전략
https://docs.ansible.com/ansible/2.7/reference_appendices/test_strategies.html
'Ansible' 카테고리의 다른 글
18장. ansible galaxy를 사용하여 role 관리, 배포하기 (0) | 2021.03.15 |
---|---|
17장. ansible role (0) | 2021.03.12 |
16장. playbook에 파일 포함하기 및 가져오기 (0) | 2021.02.27 |
15장. 병렬 구성 작업 (1) | 2021.02.27 |
14장. ansible에서 jinja2 사용하기 (0) | 2021.02.26 |