Ansible 플레이북에서 스크립트 출력 표시 방법

AnsibleBeginner
지금 연습하기

소개

Ansible 은 시스템 관리자와 개발자가 인프라를 효율적으로 관리할 수 있도록 돕는 강력한 자동화 도구입니다. Ansible 플레이북을 통해 스크립트나 명령을 실행할 때, 모니터링 및 문제 해결을 위해 해당 출력값을 캡처하고 표시하는 것이 매우 중요합니다.

이 실습에서는 Ansible 플레이북에서 스크립트 출력을 효과적으로 표시하는 방법을 배우게 됩니다. Ansible 플레이북의 기본 구조부터 시작하여, 명령 출력값을 캡처하고 표시하는 다양한 기술을 살펴보고, 마지막으로 출력 데이터를 형식화하고 필터링하는 몇 가지 고급 방법을 다룰 것입니다.

이 실습을 마치면 Ansible 에서 스크립트 출력을 처리하는 다양한 접근 방식에 대한 실질적인 경험을 얻게 되어, 더 많은 정보를 제공하고 디버깅이 용이한 자동화 워크플로우를 만들 수 있게 됩니다.

첫 번째 Ansible 플레이북 설정

스크립트 출력을 표시하는 방법을 살펴보기 전에, 기본적인 Ansible 환경을 설정하고 첫 번째 플레이북을 만들어야 합니다.

Ansible 설치

먼저 Ansible 이 시스템에 설치되어 있는지 확인해 보겠습니다.

sudo apt update
sudo apt install -y ansible

이 명령은 Ubuntu 시스템에 Ansible 을 설치합니다. 설치가 완료되면 Ansible 버전을 확인하여 설치를 확인합니다.

ansible --version

다음과 유사한 출력이 표시되어 Ansible 이 올바르게 설치되었음을 확인할 수 있습니다.

ansible [core 2.12.x]
  config file = /etc/ansible/ansible.cfg
  configured module search path = ['/home/labex/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python3/dist-packages/ansible
  ansible collection location = /home/labex/.ansible/collections:/usr/share/ansible/collections
  executable location = /usr/bin/ansible
  python version = 3.10.x (default, Mar 14 2023, 14:50:41) [GCC 11.3.0]
  jinja version = 3.0.3
  libyaml = True

Ansible 인벤토리 이해

Ansible 은 연결할 호스트를 알아야 합니다. 이 실습에서는 로컬 머신만 포함하는 간단한 인벤토리 파일을 사용합니다.

Ansible 프로젝트를 위한 디렉토리를 만듭니다.

mkdir -p ~/project/ansible-lab
cd ~/project/ansible-lab

이제 inventory.ini라는 이름의 인벤토리 파일을 만듭니다.

echo "localhost ansible_connection=local" > inventory.ini

이 인벤토리 파일은 Ansible 에게 SSH 를 사용하지 않고 로컬 머신에서 명령을 실행하도록 지시합니다.

첫 번째 플레이북 만들기

이제 기본적인 Ansible 플레이북을 만들어 보겠습니다. WebIDE 에서 ~/project/ansible-lab 디렉토리에 다음 내용으로 first_playbook.yml이라는 새 파일을 만듭니다.

---
- name: My First Ansible Playbook
  hosts: localhost
  gather_facts: yes

  tasks:
    - name: Display a simple message
      debug:
        msg: "Hello from Ansible!"

    - name: Display system information
      debug:
        msg: "You are running {{ ansible_distribution }} {{ ansible_distribution_version }}"

이 간단한 플레이북에는 두 가지 작업이 있습니다.

  1. 간단한 인사말 메시지 표시
  2. 실행 중인 운영 체제에 대한 정보 표시

이 플레이북을 실행하여 작동 방식을 확인해 보겠습니다.

cd ~/project/ansible-lab
ansible-playbook -i inventory.ini first_playbook.yml

다음과 유사한 출력이 표시됩니다.

PLAY [My First Ansible Playbook] *********************************************************

TASK [Gathering Facts] *******************************************************************
ok: [localhost]

TASK [Display a simple message] **********************************************************
ok: [localhost] => {
    "msg": "Hello from Ansible!"
}

TASK [Display system information] ********************************************************
ok: [localhost] => {
    "msg": "You are running Ubuntu 22.04"
}

PLAY RECAP *******************************************************************************
localhost                  : ok=3    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

이 출력은 다음을 보여줍니다.

  • 플레이북이 성공적으로 실행되었습니다.
  • 모든 작업이 "ok" 상태로 완료되었습니다.
  • 각 디버그 작업의 출력이 표시됩니다.

이제 기본적인 플레이북이 작동하므로, 스크립트를 실행하고 해당 출력을 더 자세히 표시하는 방법을 살펴볼 수 있습니다.

스크립트 실행 및 출력 캡처

이제 기본적인 Ansible 환경이 설정되었으므로, commandshell 모듈을 사용하여 스크립트를 실행하고 출력을 캡처하는 방법을 살펴보겠습니다.

Command 와 Shell 모듈의 차이점

Ansible 은 명령을 실행하기 위한 두 가지 주요 모듈을 제공합니다.

  • command: 셸을 거치지 않고 원격 노드에서 명령을 실행합니다. 즉, |, >, <, &와 같은 셸 연산자는 작동하지 않습니다.
  • shell: 셸을 통해 명령을 실행하여 셸 연산자와 환경 변수를 사용할 수 있습니다.

실행할 간단한 스크립트 만들기

먼저 Ansible 로 실행할 수 있는 간단한 셸 스크립트를 만들어 보겠습니다. ~/project/ansible-lab 디렉토리에 system_info.sh라는 파일을 만듭니다.

cd ~/project/ansible-lab

WebIDE 에서 다음 내용으로 파일을 만듭니다.

#!/bin/bash

echo "=== System Information ==="
echo "Hostname: $(hostname)"
echo "Kernel Version: $(uname -r)"
echo "CPU Info: $(grep 'model name' /proc/cpuinfo | head -1 | cut -d':' -f2 | xargs)"
echo "Memory Info: $(free -h | grep Mem | awk '{print $2 " total, " $3 " used, " $4 " free"}')"
echo "Disk Usage: $(df -h / | grep / | awk '{print $5 " of " $2 " used"}')"

스크립트를 실행 가능하게 만듭니다.

chmod +x ~/project/ansible-lab/system_info.sh

이제 이 스크립트를 수동으로 실행하여 어떤 출력을 생성하는지 확인해 보겠습니다.

./system_info.sh

다음과 유사한 출력이 표시됩니다.

=== System Information ===
Hostname: labex-xxxxxxxx
Kernel Version: 5.15.0-xx-generic
CPU Info: Intel(R) Xeon(R) xxxxxx
Memory Info: 8.0G total, 1.2G used, 5.8G free
Disk Usage: 15% of 50G used

Ansible 로 스크립트 실행

이제 이 스크립트를 실행하고 출력을 캡처하는 새 플레이북을 만들어 보겠습니다. ~/project/ansible-lab 디렉토리에 script_output.yml이라는 파일을 만듭니다.

---
- name: Run Script and Capture Output
  hosts: localhost
  gather_facts: no

  tasks:
    - name: Run system info script
      command: ./system_info.sh
      register: script_result

    - name: Display script output
      debug:
        msg: "{{ script_result.stdout }}"

이 플레이북은 두 가지 작업을 수행합니다.

  1. command 모듈을 사용하여 system_info.sh 스크립트를 실행합니다.
  2. register 키워드를 사용하여 출력을 script_result라는 변수에 저장합니다.
  3. debug 모듈을 사용하여 캡처된 출력을 표시합니다.

이 플레이북을 실행해 보겠습니다.

cd ~/project/ansible-lab
ansible-playbook -i inventory.ini script_output.yml

다음과 유사한 출력이 표시됩니다.

PLAY [Run Script and Capture Output] ***************************************************

TASK [Run system info script] ***********************************************************
changed: [localhost]

TASK [Display script output] ************************************************************
ok: [localhost] => {
    "msg": "=== System Information ===\nHostname: labex-xxxxxxxx\nKernel Version: 5.15.0-xx-generic\nCPU Info: Intel(R) Xeon(R) xxxxxx\nMemory Info: 8.0G total, 1.2G used, 5.8G free\nDisk Usage: 15% of 50G used"
}

PLAY RECAP *****************************************************************************
localhost                  : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

출력이 줄 바꿈 문자 (\n) 가 있는 단일 문자열로 표시되는 것을 확인하세요. 다음 섹션에서 표시를 개선해 보겠습니다.

Register 변수 이해

register 키워드는 명령의 출력뿐만 아니라 여러 속성을 포함하는 변수를 생성합니다. 이러한 속성을 탐색하기 위해 새 플레이북을 만들어 보겠습니다.

~/project/ansible-lab 디렉토리에 register_details.yml이라는 파일을 만듭니다.

---
- name: Explore Register Variable
  hosts: localhost
  gather_facts: no

  tasks:
    - name: Run system info script
      command: ./system_info.sh
      register: script_result

    - name: Display all register properties
      debug:
        var: script_result

    - name: Display just stdout
      debug:
        var: script_result.stdout

    - name: Display stdout as a list of lines
      debug:
        var: script_result.stdout_lines

이 플레이북을 실행합니다.

ansible-playbook -i inventory.ini register_details.yml

script_result 변수의 모든 속성을 보여주는 더 자세한 출력을 볼 수 있습니다. 여기에는 다음이 포함됩니다.

  • stdout: 표준 출력을 단일 문자열로 표시
  • stderr: 표준 오류 (있는 경우)
  • rc: 반환 코드 (0 은 성공을 의미)
  • stdout_lines: 표준 출력을 줄 목록으로 분할

마지막 작업은 출력을 줄 목록으로 형식화하여 훨씬 더 읽기 쉽게 만듭니다.

고급 출력 처리 기술

이제 스크립트 출력을 캡처하는 기본 사항을 이해했으므로, Ansible 플레이북에서 출력을 처리하고 표시하는 몇 가지 더 고급 기술을 살펴보겠습니다.

스크립트 오류 처리

스크립트를 실행할 때 오류 조건을 적절하게 처리하는 것이 중요합니다. Ansible 은 명령이 0 이 아닌 종료 코드를 반환하면 작업을 실패로 표시합니다. 오류 처리를 보여주는 플레이북을 만들어 보겠습니다.

~/project/ansible-lab 디렉토리에 error_handling.yml이라는 파일을 만듭니다.

---
- name: Handling Script Errors
  hosts: localhost
  gather_facts: no

  tasks:
    - name: Run a command that might fail
      command: ls /nonexistent_directory
      register: cmd_result
      ignore_errors: yes

    - name: Show error message if command failed
      debug:
        msg: "Command failed with error: {{ cmd_result.stderr }}"
      when: cmd_result.rc != 0

    - name: Show success message if command succeeded
      debug:
        msg: "Command succeeded with output: {{ cmd_result.stdout }}"
      when: cmd_result.rc == 0

이 플레이북에서:

  1. 존재하지 않는 디렉토리를 나열하려고 시도합니다.
  2. 명령이 실패하더라도 플레이북이 중지되지 않도록 ignore_errors: yes를 사용합니다.
  3. 반환 코드 (cmd_result.rc) 를 확인하여 명령이 성공했는지 실패했는지 확인합니다.
  4. 결과에 따라 적절한 메시지를 표시합니다.

이 플레이북을 실행해 보겠습니다.

cd ~/project/ansible-lab
ansible-playbook -i inventory.ini error_handling.yml

다음과 유사한 출력이 표시됩니다.

PLAY [Handling Script Errors] ***********************************************************

TASK [Run a command that might fail] ***************************************************
fatal: [localhost]: FAILED! => {"changed": true, "cmd": ["ls", "/nonexistent_directory"], "delta": "0:00:00.003398", "end": "2023-09-15 12:34:56.789012", "msg": "non-zero return code", "rc": 2, "start": "2023-09-15 12:34:56.785614", "stderr": "ls: cannot access '/nonexistent_directory': No such file or directory", "stderr_lines": ["ls: cannot access '/nonexistent_directory': No such file or directory"], "stdout": "", "stdout_lines": []}
...ignoring

TASK [Show error message if command failed] *********************************************
ok: [localhost] => {
    "msg": "Command failed with error: ls: cannot access '/nonexistent_directory': No such file or directory"
}

TASK [Show success message if command succeeded] ****************************************
skipping: [localhost]

PLAY RECAP *******************************************************************************
localhost                  : ok=2    changed=0    unreachable=0    failed=0    skipped=1    rescued=0    ignored=1

명령이 실패했음에도 불구하고 플레이북이 계속 실행되고 오류 메시지가 표시되는 것을 확인하세요.

여러 줄 출력 형식 지정

여러 줄 출력을 생성하는 더 복잡한 스크립트를 만들고 플레이북에서 이를 깔끔하게 형식 지정해 보겠습니다.

~/project/ansible-lab 디렉토리에 package_info.sh라는 파일을 만듭니다.

#!/bin/bash

echo "TOP 5 LARGEST INSTALLED PACKAGES"
echo "================================"
dpkg-query -W -f='${Installed-Size}\t${Package}\n' | sort -n -r | head -5

실행 가능하게 만듭니다.

chmod +x ~/project/ansible-lab/package_info.sh

이제 이 스크립트를 실행하고 출력을 깔끔하게 형식 지정하는 플레이북을 만듭니다. formatted_output.yml이라는 파일을 만듭니다.

---
- name: Format Script Output
  hosts: localhost
  gather_facts: no

  tasks:
    - name: Run package info script
      shell: ./package_info.sh
      register: pkg_info

    - name: Display raw output
      debug:
        msg: "{{ pkg_info.stdout }}"

    - name: Display formatted output with a title
      debug:
        msg: |
          Below is the package information:
          --------------------------------
          {% for line in pkg_info.stdout_lines %}
          {{ line }}
          {% endfor %}
          --------------------------------
          Total lines: {{ pkg_info.stdout_lines | length }}

이 플레이북은 다음을 수행합니다.

  1. package_info.sh 스크립트를 실행합니다.
  2. 원시 출력을 표시합니다.
  3. Jinja2 템플릿을 사용하여 제목과 바닥글로 출력을 형식 지정합니다.

실행해 보겠습니다.

ansible-playbook -i inventory.ini formatted_output.yml

다음과 같이 깔끔하게 형식 지정된 출력이 표시됩니다.

PLAY [Format Script Output] ***********************************************************

TASK [Run package info script] ********************************************************
changed: [localhost]

TASK [Display raw output] *************************************************************
ok: [localhost] => {
    "msg": "TOP 5 LARGEST INSTALLED PACKAGES\n================================\n112233\tsome-large-package\n99887\tanother-package\n...\n"
}

TASK [Display formatted output with a title] ******************************************
ok: [localhost] => {
    "msg": "Below is the package information:\n--------------------------------\nTOP 5 LARGEST INSTALLED PACKAGES\n================================\n112233\tsome-large-package\n99887\tanother-package\n...\n--------------------------------\nTotal lines: 7"
}

PLAY RECAP ****************************************************************************
localhost                  : ok=3    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

조건부 출력 표시

때로는 상세 모드로 실행하는 경우와 같이 특정 조건에서만 출력을 표시하고 싶을 수 있습니다. 이를 수행하는 방법을 살펴보겠습니다.

~/project/ansible-lab 디렉토리에 conditional_output.yml이라는 파일을 만듭니다.

---
- name: Conditional Output Display
  hosts: localhost
  gather_facts: yes

  tasks:
    - name: Get disk usage information
      shell: df -h
      register: disk_info

    - name: Display disk usage (always shown)
      debug:
        msg: "{{ disk_info.stdout_lines[0:2] }}"

    - name: Display detailed disk usage (only in verbose mode)
      debug:
        msg: "{{ disk_info.stdout_lines }}"
        verbosity: 1

이 플레이북에서:

  1. 디스크 사용량 정보를 캡처합니다.
  2. 항상 요약 (처음 두 줄) 을 표시합니다.
  3. 상세 모드 (-v 플래그 사용) 로 실행할 때만 전체 세부 정보를 표시합니다.

먼저 일반 모드로 실행해 보겠습니다.

ansible-playbook -i inventory.ini conditional_output.yml

이제 상세 모드로 실행해 보겠습니다.

ansible-playbook -i inventory.ini conditional_output.yml -v

상세 모드에서는 전체 디스크 사용량 정보를 얻고, 일반 모드에서는 요약만 표시되는 것을 확인할 수 있습니다.

이 기술은 기본적으로 잠재적으로 민감하거나 압도적인 출력을 숨기는 데 유용하며, 디버깅에 필요한 경우에도 사용할 수 있습니다.

요약

이 랩에서는 Ansible 플레이북에서 스크립트 출력을 캡처하고 표시하는 다양한 기술을 배웠습니다.

  1. 기본적인 Ansible 환경을 설정하고 첫 번째 플레이북을 만들었습니다.
  2. commandshell 모듈을 사용하여 스크립트를 실행하는 방법을 배웠습니다.
  3. register 지시문을 사용하여 스크립트 출력을 캡처했습니다.
  4. debug 모듈을 사용하여 다양한 형식으로 출력을 표시했습니다.
  5. 오류 조건을 처리하고 조건부 출력 표시를 구현했습니다.
  6. 출력을 더 읽기 쉽게 만들기 위해 형식 지정 기술을 적용했습니다.

이러한 기술을 통해 실행 중에 명확한 피드백을 제공하는 더 많은 정보를 제공하는 Ansible 플레이북을 만들 수 있습니다. 이러한 가시성은 자동화된 프로세스를 모니터링하고 문제가 발생할 때 문제 해결하는 데 매우 중요합니다.

이러한 출력 처리 기술을 활용하여 작업을 수행할 뿐만 아니라 각 단계에서 무슨 일이 일어나고 있는지 명확하게 전달하는 더 강력한 자동화 워크플로우를 구축할 수 있습니다. 이렇게 하면 자동화가 더 투명해지고 특히 팀 환경이나 복잡한 인프라에서 작업할 때 유지 관리가 더 쉬워집니다.