Ansible 플레이북에서 셸 명령 출력 표시 방법

AnsibleIntermediate
지금 연습하기

소개

Ansible 은 시스템 관리자 및 DevOps 전문가들이 널리 사용하는 강력한 오픈 소스 자동화 도구입니다. Ansible 의 주요 기능 중 하나는 원격 호스트에서 셸 명령을 실행하고 해당 출력을 처리하는 것입니다. 이 실습 튜토리얼에서는 Ansible 플레이북에서 셸 명령의 출력을 효과적으로 캡처, 표시 및 처리하는 방법을 배우게 됩니다. 이 기술은 다양한 시스템 조건에 적응하고 유용한 피드백을 제공할 수 있는 강력한 자동화 워크플로우를 만드는 데 필수적입니다.

이것은 가이드 실험입니다. 학습과 실습을 돕기 위한 단계별 지침을 제공합니다.각 단계를 완료하고 실무 경험을 쌓기 위해 지침을 주의 깊게 따르세요. 과거 데이터에 따르면, 이것은 중급 레벨의 실험이며 완료율은 53%입니다.학습자들로부터 100%의 긍정적인 리뷰율을 받았습니다.

셸 명령을 사용한 첫 번째 Ansible 플레이북 설정

이 단계에서는 셸 명령을 실행하고 해당 출력을 캡처하는 기본적인 Ansible 플레이북을 설정합니다. 이는 이후 단계에서 더 고급 기술을 위한 기반을 제공합니다.

Ansible 설치

먼저, 시스템에 Ansible 을 설치해 보겠습니다.

sudo apt update
sudo apt install -y ansible

이제 Ansible 이 올바르게 설치되었는지 확인합니다.

ansible --version

다음과 유사한 출력이 표시되어야 합니다.

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 15 2022, 12:22:08) [GCC 11.2.0]
  jinja version = 3.0.3
  libyaml = True

인벤토리 파일 생성

Ansible 은 관리할 호스트를 알기 위해 인벤토리 파일을 사용합니다. 이 랩에서는 로컬 머신만 포함하는 간단한 인벤토리를 생성합니다.

  1. WebIDE 를 열고 /home/labex/project 디렉토리에 inventory.ini라는 새 파일을 만듭니다.
  2. 파일에 다음 내용을 추가합니다.
[local]
localhost ansible_connection=local

이 인벤토리는 local이라는 그룹을 정의하며, 이 그룹에는 localhost 만 포함되어 있고 Ansible 에 SSH 없이 직접 연결하도록 지시합니다.

첫 번째 플레이북 생성

이제 셸 명령을 실행하는 간단한 플레이북을 만들어 보겠습니다.

  1. /home/labex/project 디렉토리에 first_playbook.yml이라는 새 파일을 만듭니다.
  2. 파일에 다음 YAML 내용을 추가합니다.
---
- name: Shell Command Example
  hosts: local
  gather_facts: no

  tasks:
    - name: Run a simple shell command
      shell: echo "Hello from Ansible shell command"
      register: hello_output

    - name: Display the output
      debug:
        msg: "{{ hello_output.stdout }}"

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

  • 인벤토리에서 정의한 local 그룹을 대상으로 합니다.
  • 팩트 (시스템 정보) 수집을 건너뛰어 간단하게 유지합니다.
  • 인사 메시지를 에코하는 셸 명령을 실행합니다.
  • register 키워드를 사용하여 출력을 변수에 저장합니다.
  • debug 모듈을 사용하여 출력을 표시합니다.

플레이북 실행

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

ansible-playbook -i inventory.ini first_playbook.yml

다음과 유사한 출력이 표시되어야 합니다.

PLAY [Shell Command Example] **************************************************

TASK [Run a simple shell command] *********************************************
changed: [localhost]

TASK [Display the output] *****************************************************
ok: [localhost] => {
    "msg": "Hello from Ansible shell command"
}

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

출력은 플레이북이 성공적으로 실행되어 셸 명령을 실행하고 해당 출력을 표시했음을 보여줍니다.

이해해야 할 주요 개념

이 연습에서 다음 중요한 개념에 유의하십시오.

  1. shell 모듈을 사용하면 셸 명령을 실행할 수 있습니다.
  2. register 지시문은 작업의 출력을 변수에 캡처합니다.
  3. debug 모듈은 변수 값을 표시하는 데 도움이 됩니다.
  4. 셸 명령 출력에는 stdout (표준 출력) 과 stderr (오류 출력) 이 모두 포함됩니다.

다음 단계에서는 셸 명령 출력을 보다 효과적으로 처리하고 형식화하는 방법을 살펴보겠습니다.

구조화된 셸 명령 출력 작업

이제 Ansible 에서 셸 명령을 실행하는 기본 사항을 이해했으므로 구조화된 명령 출력으로 작업하고 이를 다양한 형식으로 표시하는 방법을 살펴보겠습니다.

시스템 정보 처리

시스템 정보를 수집하고 구조화된 방식으로 표시하는 더 실용적인 플레이북을 만들어 보겠습니다.

  1. /home/labex/project 디렉토리에 system_info.yml이라는 새 파일을 만듭니다.
  2. 다음 내용을 추가합니다.
---
- name: Gather and Display System Information
  hosts: local
  gather_facts: no

  tasks:
    - name: Gather system information
      shell: |
        echo "OS Information: $(cat /etc/os-release | grep PRETTY_NAME | cut -d= -f2)"
        echo "Kernel Version: $(uname -r)"
        echo "CPU Information: $(grep "model name" /proc/cpuinfo | head -1 | cut -d: -f2 | xargs)"
        echo "Memory Information: $(free -h | grep Mem | awk '{print $2}')"
      register: system_info

    - name: Display raw system information
      debug:
        msg: "{{ system_info.stdout }}"

    - name: Display information as a list
      debug:
        msg: "{{ system_info.stdout_lines }}"

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

  • 다양한 시스템 세부 정보를 수집하는 여러 줄의 셸 스크립트를 실행합니다.
  • 출력을 system_info 변수에 저장합니다.
  • 출력을 먼저 원시 문자열로 표시한 다음 줄 목록으로 표시합니다.

플레이북을 실행합니다.

ansible-playbook -i inventory.ini system_info.yml

다음과 같은 출력이 표시되어야 합니다.

PLAY [Gather and Display System Information] **********************************

TASK [Gather system information] **********************************************
changed: [localhost]

TASK [Display raw system information] *****************************************
ok: [localhost] => {
    "msg": "OS Information: \"Ubuntu 22.04.1 LTS\"\nKernel Version: 5.15.0-1023-azure\nCPU Information: Intel(R) Xeon(R) Platinum 8171M CPU @ 2.60GHz\nMemory Information: 4.0Gi"
}

TASK [Display information as a list] *****************************************
ok: [localhost] => {
    "msg": [
        "OS Information: \"Ubuntu 22.04.1 LTS\"",
        "Kernel Version: 5.15.0-1023-azure",
        "CPU Information: Intel(R) Xeon(R) Platinum 8171M CPU @ 2.60GHz",
        "Memory Information: 4.0Gi"
    ]
}

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

두 번째 표시 작업이 출력을 줄 바꿈이 있는 문자열 대신 목록으로 표시하는 방식을 확인하십시오. 이 목록 형식은 여러 줄의 출력을 더 쉽게 처리할 수 있도록 합니다.

명령 결과 및 반환 코드 작업

Linux 의 셸 명령은 성공 (0) 또는 실패 (0 이 아닌 값) 를 나타내기 위해 종료 코드를 반환합니다. Ansible 은 이러한 코드를 등록된 변수의 rc (반환 코드) 속성으로 캡처합니다.

반환 코드로 작업하는 방법을 보여주는 플레이북을 만들어 보겠습니다.

  1. /home/labex/project 디렉토리에 command_results.yml이라는 새 파일을 만듭니다.
  2. 다음 내용을 추가합니다.
---
- name: Working with Command Results
  hosts: local
  gather_facts: no

  tasks:
    - name: Check if a file exists
      shell: test -f /etc/hosts
      register: file_check
      ignore_errors: yes

    - name: Show command result details
      debug:
        msg: |
          Return code: {{ file_check.rc }}
          Succeeded: {{ file_check.rc == 0 }}
          Failed: {{ file_check.rc != 0 }}

    - name: Check if a non-existent file exists
      shell: test -f /file/does/not/exist
      register: missing_file
      ignore_errors: yes

    - name: Show command result for missing file
      debug:
        msg: |
          Return code: {{ missing_file.rc }}
          Succeeded: {{ missing_file.rc == 0 }}
          Failed: {{ missing_file.rc != 0 }}

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

  • 파일이 있는지 확인하기 위해 두 개의 테스트 명령을 실행합니다.
  • 명령이 실패할 경우 플레이북이 중지되지 않도록 ignore_errors: yes를 사용합니다.
  • 반환 코드 및 성공/실패 상태를 포함한 자세한 명령 결과 정보를 표시합니다.

플레이북을 실행합니다.

ansible-playbook -i inventory.ini command_results.yml

다음과 유사한 출력이 표시되어야 합니다.

PLAY [Working with Command Results] *******************************************

TASK [Check if a file exists] *************************************************
changed: [localhost]

TASK [Show command result details] ********************************************
ok: [localhost] => {
    "msg": "Return code: 0\nSucceeded: True\nFailed: False\n"
}

TASK [Check if a non-existent file exists] ************************************
fatal: [localhost]: FAILED! => {"changed": true, "cmd": "test -f /file/does/not/exist", "delta": "0:00:00.003183", "end": "2023-07-14 15:24:33.931406", "msg": "non-zero return code", "rc": 1, "start": "2023-07-14 15:24:33.928223", "stderr": "", "stderr_lines": [], "stdout": "", "stdout_lines": []}
...ignoring

TASK [Show command result for missing file] ***********************************
ok: [localhost] => {
    "msg": "Return code: 1\nSucceeded: False\nFailed: True\n"
}

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

기존 파일의 반환 코드는 0 이고 존재하지 않는 파일의 반환 코드는 1 임을 확인하십시오. 이는 플레이북에서 반환 코드를 사용하여 결정을 내리는 방법을 보여줍니다.

등록된 변수 구조 이해

셸 명령에서 등록된 변수에는 몇 가지 유용한 속성이 포함되어 있습니다.

  • stdout: 단일 문자열로 된 표준 출력
  • stdout_lines: 줄 목록으로 분할된 표준 출력
  • stderr: 단일 문자열로 된 표준 오류 출력
  • stderr_lines: 줄 목록으로 분할된 표준 오류 출력
  • rc: 반환 코드 (성공 시 0, 실패 시 0 이 아닌 값)
  • cmd: 실행된 명령
  • startend: 명령이 시작 및 종료된 타임스탬프
  • delta: 명령 실행 기간

Ansible 에서 셸 명령 출력을 효과적으로 처리하려면 이 구조를 이해하는 것이 중요합니다.

셸 출력 기반 조건부 실행

Ansible 의 가장 강력한 기능 중 하나는 셸 명령의 출력을 기반으로 결정을 내리는 기능입니다. 이 단계에서는 조건과 필터를 사용하여 셸 명령 출력을 처리하고 플레이북을 더 동적으로 만드는 방법을 배웁니다.

셸 출력과 함께 조건 사용

셸 명령 출력을 기반으로 결정을 내리는 플레이북을 만들어 보겠습니다.

  1. /home/labex/project 디렉토리에 conditional_playbook.yml이라는 새 파일을 만듭니다.
  2. 다음 내용을 추가합니다.
---
- name: Conditional Tasks Based on Command Output
  hosts: local
  gather_facts: no

  tasks:
    - name: Check disk space
      shell: df -h / | grep -v Filesystem | awk '{print $5}' | sed 's/%//'
      register: disk_usage

    - name: Display disk usage
      debug:
        msg: "Current disk usage: {{ disk_usage.stdout }}%"

    - name: Disk usage warning
      debug:
        msg: "WARNING: Disk usage is high"
      when: disk_usage.stdout|int > 50

    - name: Disk usage normal
      debug:
        msg: "Disk usage is normal"
      when: disk_usage.stdout|int <= 50

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

  • 루트 파일 시스템의 디스크 사용량 백분율을 확인하기 위해 셸 명령을 실행합니다.
  • 명령 출력을 기반으로 when 조건을 사용합니다.
  • 비교를 위해 문자열 출력을 정수로 변환하기 위해 int 필터를 사용합니다.

플레이북을 실행합니다.

ansible-playbook -i inventory.ini conditional_playbook.yml

출력은 실제 디스크 사용량에 따라 다르지만 다음과 유사하게 표시됩니다.

PLAY [Conditional Tasks Based on Command Output] ******************************

TASK [Check disk space] *******************************************************
changed: [localhost]

TASK [Display disk usage] *****************************************************
ok: [localhost] => {
    "msg": "Current disk usage: 38%"
}

TASK [Disk usage warning] *****************************************************
skipped: [localhost]

TASK [Disk usage normal] ******************************************************
ok: [localhost] => {
    "msg": "Disk usage is normal"
}

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

Ansible 이 실제 디스크 사용량 값을 기반으로 조건부 작업 중 하나만 실행하는 방식을 확인하십시오.

명령에서 JSON 출력 처리

많은 최신 CLI 도구는 JSON 형식으로 데이터를 반환합니다. Ansible 에는 JSON 출력을 처리하는 기능이 내장되어 있습니다.

  1. /home/labex/project 디렉토리에 json_output.yml이라는 새 파일을 만듭니다.
  2. 다음 내용을 추가합니다.
---
- name: Handling JSON Output
  hosts: local
  gather_facts: no

  tasks:
    - name: Create a JSON file for testing
      copy:
        dest: /tmp/services.json
        content: |
          {
            "services": [
              {
                "name": "web",
                "status": "running",
                "port": 80
              },
              {
                "name": "database",
                "status": "stopped",
                "port": 5432
              },
              {
                "name": "cache",
                "status": "running",
                "port": 6379
              }
            ]
          }

    - name: Read JSON file with shell
      shell: cat /tmp/services.json
      register: json_output

    - name: Parse and display JSON content
      debug:
        msg: "{{ json_output.stdout | from_json }}"

    - name: Extract and display service information
      debug:
        msg: "Service: {{ item.name }}, Status: {{ item.status }}, Port: {{ item.port }}"
      loop: "{{ (json_output.stdout | from_json).services }}"

    - name: Show only running services
      debug:
        msg: "Running service: {{ item.name }} on port {{ item.port }}"
      loop: "{{ (json_output.stdout | from_json).services }}"
      when: item.status == "running"

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

  • 데모용 샘플 JSON 파일을 만듭니다.
  • 셸 명령으로 JSON 파일을 읽습니다.
  • from_json 필터를 사용하여 JSON 문자열을 데이터 구조로 구문 분석합니다.
  • 데이터 구조를 반복하여 정보를 표시합니다.
  • 조건부 로직을 사용하여 실행 중인 서비스만 필터링합니다.

플레이북을 실행합니다.

ansible-playbook -i inventory.ini json_output.yml

다음과 유사한 출력이 표시되어야 합니다.

PLAY [Handling JSON Output] ***************************************************

TASK [Create a JSON file for testing] *****************************************
changed: [localhost]

TASK [Read JSON file with shell] **********************************************
changed: [localhost]

TASK [Parse and display JSON content] *****************************************
ok: [localhost] => {
    "msg": {
        "services": [
            {
                "name": "web",
                "port": 80,
                "status": "running"
            },
            {
                "name": "database",
                "port": 5432,
                "status": "stopped"
            },
            {
                "name": "cache",
                "port": 6379,
                "status": "running"
            }
        ]
    }
}

TASK [Extract and display service information] ********************************
ok: [localhost] => (item={'name': 'web', 'status': 'running', 'port': 80}) => {
    "msg": "Service: web, Status: running, Port: 80"
}
ok: [localhost] => (item={'name': 'database', 'status': 'stopped', 'port': 5432}) => {
    "msg": "Service: database, Status: stopped, Port: 5432"
}
ok: [localhost] => (item={'name': 'cache', 'status': 'running', 'port': 6379}) => {
    "msg": "Service: cache, Status: running, Port: 6379"
}

TASK [Show only running services] *********************************************
ok: [localhost] => (item={'name': 'web', 'status': 'running', 'port': 80}) => {
    "msg": "Running service: web on port 80"
}
skipped: [localhost] => (item={'name': 'database', 'status': 'stopped', 'port': 5432})
ok: [localhost] => (item={'name': 'cache', 'status': 'running', 'port': 6379}) => {
    "msg": "Running service: cache on port 6379"
}

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

플레이북이 JSON 을 구문 분석하고, 특정 정보를 추출하고, 조건을 기반으로 데이터를 필터링하는 방식을 확인하십시오.

셸 명령을 사용한 오류 처리

셸 명령을 실행할 때는 잠재적인 오류를 적절하게 처리하는 것이 중요합니다.

  1. /home/labex/project 디렉토리에 error_handling.yml이라는 새 파일을 만듭니다.
  2. 다음 내용을 추가합니다.
---
- name: Error Handling with Shell Commands
  hosts: local
  gather_facts: no

  tasks:
    - name: Run a potentially failing command
      shell: grep "nonexistent_pattern" /etc/passwd
      register: command_result
      ignore_errors: yes

    - name: Display success or failure
      debug:
        msg: "Command {{ 'succeeded' if command_result.rc == 0 else 'failed with return code ' + command_result.rc|string }}"

    - name: Run a custom failing command
      shell: exit 3
      register: exit_command
      ignore_errors: yes

    - name: Display detailed error information
      debug:
        msg: |
          Return code: {{ exit_command.rc }}
          Error message: {{ exit_command.stderr if exit_command.stderr else 'No error message' }}

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

  • 실패할 것으로 예상되는 명령을 실행합니다.
  • 명령이 실패하더라도 플레이북 실행을 계속하기 위해 ignore_errors: yes를 사용합니다.
  • 오류 정보를 처리하고 표시하는 다양한 방법을 보여줍니다.

플레이북을 실행합니다.

ansible-playbook -i inventory.ini error_handling.yml

다음과 유사한 출력이 표시되어야 합니다.

PLAY [Error Handling with Shell Commands] *************************************

TASK [Run a potentially failing command] **************************************
fatal: [localhost]: FAILED! => {"changed": true, "cmd": "grep \"nonexistent_pattern\" /etc/passwd", "delta": "0:00:00.002916", "end": "2023-07-14 16:10:23.671519", "msg": "non-zero return code", "rc": 1, "start": "2023-07-14 16:10:23.668603", "stderr": "", "stderr_lines": [], "stdout": "", "stdout_lines": []}
...ignoring

TASK [Display success or failure] *********************************************
ok: [localhost] => {
    "msg": "Command failed with return code 1"
}

TASK [Run a custom failing command] *******************************************
fatal: [localhost]: FAILED! => {"changed": true, "cmd": "exit 3", "delta": "0:00:00.002447", "end": "2023-07-14 16:10:23.906121", "msg": "non-zero return code", "rc": 3, "start": "2023-07-14 16:10:23.903674", "stderr": "", "stderr_lines": [], "stdout": "", "stdout_lines": []}
...ignoring

TASK [Display detailed error information] *************************************
ok: [localhost] => {
    "msg": "Return code: 3\nError message: No error message\n"
}

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

이는 셸 명령을 실행할 때 다양한 오류 조건을 캡처하고 이에 대응하는 방법을 보여줍니다.

실용적인 셸 출력 처리 도구 만들기

이 마지막 단계에서는 지금까지 배운 모든 내용을 결합하여 시스템 정보를 수집하고, 처리하고, 보고서를 생성하는 실용적인 Ansible 플레이북을 만들 것입니다. 이는 Ansible 의 셸 명령 처리 기능이 매우 유용할 수 있는 실제 시나리오를 나타냅니다.

시스템 정보 보고서 도구 구축

포괄적인 시스템 정보 수집 도구를 만들어 보겠습니다.

  1. /home/labex/project 디렉토리에 system_report.yml이라는 새 파일을 만듭니다.
  2. 다음 내용을 추가합니다.
---
- name: Comprehensive System Report
  hosts: local
  gather_facts: no

  vars:
    report_file: /tmp/system_report.txt

  tasks:
    - name: Collect basic system information
      shell: |
        echo "SYSTEM REPORT" > {{ report_file }}
        echo "=============" >> {{ report_file }}
        echo "" >> {{ report_file }}

        echo "HOSTNAME: $(hostname)" >> {{ report_file }}
        echo "TIMESTAMP: $(date)" >> {{ report_file }}
        echo "" >> {{ report_file }}

        echo "SYSTEM INFORMATION" >> {{ report_file }}
        echo "------------------" >> {{ report_file }}
        echo "OS: $(cat /etc/os-release | grep PRETTY_NAME | cut -d= -f2)" >> {{ report_file }}
        echo "KERNEL: $(uname -r)" >> {{ report_file }}
        echo "UPTIME: $(uptime -p)" >> {{ report_file }}
        echo "" >> {{ report_file }}

        echo "RESOURCE UTILIZATION" >> {{ report_file }}
        echo "-------------------" >> {{ report_file }}
        echo "CPU LOAD: $(uptime | awk -F'load average:' '{print $2}')" >> {{ report_file }}
        echo "MEMORY USAGE:" >> {{ report_file }}
        free -h >> {{ report_file }}
        echo "" >> {{ report_file }}
        echo "DISK USAGE:" >> {{ report_file }}
        df -h >> {{ report_file }}
        echo "" >> {{ report_file }}

        echo "NETWORK INFORMATION" >> {{ report_file }}
        echo "-------------------" >> {{ report_file }}
        echo "IP ADDRESSES:" >> {{ report_file }}
        ip addr | grep "inet " | awk '{print $2}' >> {{ report_file }}
        echo "" >> {{ report_file }}

        echo "PROCESS INFORMATION" >> {{ report_file }}
        echo "-------------------" >> {{ report_file }}
        echo "TOP 5 CPU CONSUMING PROCESSES:" >> {{ report_file }}
        ps aux --sort=-%cpu | head -6 >> {{ report_file }}
        echo "" >> {{ report_file }}
        echo "TOP 5 MEMORY CONSUMING PROCESSES:" >> {{ report_file }}
        ps aux --sort=-%mem | head -6 >> {{ report_file }}
      register: report_generation

    - name: Check if report was generated successfully
      stat:
        path: "{{ report_file }}"
      register: report_stat

    - name: Display report generation status
      debug:
        msg: "Report generated successfully at {{ report_file }}"
      when: report_stat.stat.exists

    - name: Display report content
      shell: cat {{ report_file }}
      register: report_content
      when: report_stat.stat.exists

    - name: Show report content
      debug:
        msg: "{{ report_content.stdout_lines }}"
      when: report_stat.stat.exists

    - name: Analyze disk usage
      shell: df -h / | grep -v Filesystem | awk '{print $5}' | sed 's/%//'
      register: disk_usage
      when: report_stat.stat.exists

    - name: Generate disk usage alert if needed
      debug:
        msg: "ALERT: Disk usage on / is {{ disk_usage.stdout }}% which exceeds the 80% threshold!"
      when:
        - report_stat.stat.exists
        - disk_usage.stdout|int > 80

    - name: Generate disk usage warning if needed
      debug:
        msg: "WARNING: Disk usage on / is {{ disk_usage.stdout }}% which exceeds the 60% threshold."
      when:
        - report_stat.stat.exists
        - disk_usage.stdout|int > 60
        - disk_usage.stdout|int <= 80

    - name: Confirm normal disk usage
      debug:
        msg: "Disk usage on / is normal at {{ disk_usage.stdout }}%."
      when:
        - report_stat.stat.exists
        - disk_usage.stdout|int <= 60

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

  • 일련의 셸 명령을 사용하여 포괄적인 시스템 정보를 수집합니다.
  • 정보를 보고서 파일에 씁니다.
  • 보고서가 성공적으로 생성되었는지 확인합니다.
  • 보고서의 내용을 표시합니다.
  • 디스크 사용량 데이터를 분석합니다.
  • 분석을 기반으로 적절한 경고를 생성합니다.

플레이북을 실행합니다.

ansible-playbook -i inventory.ini system_report.yml

플레이북 실행 및 전체 시스템 보고서를 보여주는 포괄적인 출력을 볼 수 있습니다. 출력은 매우 길기 때문에 다음은 볼 수 있는 내용의 샘플입니다.

PLAY [Comprehensive System Report] ********************************************

TASK [Collect basic system information] ***************************************
changed: [localhost]

TASK [Check if report was generated successfully] *****************************
ok: [localhost]

TASK [Display report generation status] ***************************************
ok: [localhost] => {
    "msg": "Report generated successfully at /tmp/system_report.txt"
}

TASK [Display report content] *************************************************
changed: [localhost]

TASK [Show report content] ****************************************************
ok: [localhost] => {
    "msg": [
        "SYSTEM REPORT",
        "=============",
        "",
        "HOSTNAME: ubuntu-vm",
        "TIMESTAMP: Fri Jul 14 16:35:42 UTC 2023",
        "",
        "SYSTEM INFORMATION",
        "------------------",
        "OS: \"Ubuntu 22.04.1 LTS\"",
        "KERNEL: 5.15.0-1023-azure",
        "UPTIME: up 3 hours, 25 minutes",
        ...

보고서 검토

생성된 시스템 보고서를 검토해 보겠습니다.

cat /tmp/system_report.txt

이렇게 하면 플레이북에서 생성된 전체 보고서가 표시됩니다.

사용자 지정 셸 스크립트 생성 및 Ansible 에서 호출

더 복잡한 작업의 경우 전용 셸 스크립트를 만들고 Ansible 에서 호출하는 것이 더 쉬울 수 있습니다.

  1. /home/labex/project 디렉토리에 disk_analyzer.sh라는 새 파일을 만듭니다.
  2. 다음 내용을 추가합니다.
#!/bin/bash

## disk_analyzer.sh - A simple script to analyze disk usage

echo "DISK USAGE ANALYSIS"
echo "------------------"

## Get overall disk usage
ROOT_USAGE=$(df -h / | grep -v Filesystem | awk '{print $5}' | sed 's/%//')
echo "Root filesystem usage: ${ROOT_USAGE}%"

## Categorize the usage
if [ $ROOT_USAGE -gt 80 ]; then
  echo "STATUS: CRITICAL - Immediate action required"
elif [ $ROOT_USAGE -gt 60 ]; then
  echo "STATUS: WARNING - Consider cleaning up disk space"
else
  echo "STATUS: OK - Disk usage is within normal parameters"
fi

echo ""

## Find largest directories
echo "Top 5 largest directories in /var:"
du -h /var --max-depth=1 2> /dev/null | sort -hr | head -5

echo ""

## Find largest files
echo "Top 5 largest files in /var/log:"
find /var/log -type f -exec du -h {} \; 2> /dev/null | sort -hr | head -5

exit 0
  1. 스크립트를 실행 가능하게 만듭니다.
chmod +x /home/labex/project/disk_analyzer.sh
  1. 이 스크립트를 호출하는 새 플레이북을 만듭니다.
touch /home/labex/project/call_script.yml
  1. 플레이북에 다음 내용을 추가합니다.
---
- name: Call Custom Shell Script
  hosts: local
  gather_facts: no

  tasks:
    - name: Run disk analyzer script
      shell: /home/labex/project/disk_analyzer.sh
      register: script_output

    - name: Display script output
      debug:
        msg: "{{ script_output.stdout_lines }}"

    - name: Check for critical status
      debug:
        msg: "CRITICAL DISK USAGE DETECTED! Immediate action required."
      when: script_output.stdout is search("STATUS: CRITICAL")
  1. 플레이북을 실행합니다.
ansible-playbook -i inventory.ini call_script.yml

다음과 유사한 출력이 표시되어야 합니다.

PLAY [Call Custom Shell Script] ***********************************************

TASK [Run disk analyzer script] ***********************************************
changed: [localhost]

TASK [Display script output] **************************************************
ok: [localhost] => {
    "msg": [
        "DISK USAGE ANALYSIS",
        "------------------",
        "Root filesystem usage: 38%",
        "STATUS: OK - Disk usage is within normal parameters",
        "",
        "Top 5 largest directories in /var:",
        "60M\t/var/lib",
        "60M\t/var/cache",
        "12M\t/var/log",
        "4.0K\t/var/tmp",
        "4.0K\t/var/mail",
        "",
        "Top 5 largest files in /var/log:",
        "4.0M\t/var/log/journal/c75af53674ce472fb9654a1d5cf8cc37/system.journal",
        "2.3M\t/var/log/auth.log",
        "1.3M\t/var/log/syslog",
        "724K\t/var/log/kern.log",
        "428K\t/var/log/cloud-init.log"
    ]
}

TASK [Check for critical status] **********************************************
skipped: [localhost]

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

이 접근 방식은 셸 스크립트의 강력함과 Ansible 의 자동화 기능을 결합합니다. 셸 스크립트는 디스크 분석에 대한 복잡한 로직을 처리하는 반면, Ansible 은 결과의 실행 및 추가 처리를 관리합니다.

주요 내용

이 랩을 통해 Ansible 에서 셸 명령 출력을 처리하기 위한 몇 가지 중요한 기술을 배웠습니다.

  1. 셸 명령을 실행하고 출력을 캡처하는 방법
  2. 표시를 위해 명령 출력을 처리하고 형식화하는 방법
  3. 명령 결과를 기반으로 조건부 실행을 사용하는 방법
  4. JSON 출력 및 오류 조건을 처리하는 방법
  5. 셸 명령과 Ansible 의 자동화 기능을 결합하는 실용적인 도구를 만드는 방법

이러한 기술은 Ansible 로 더 복잡한 자동화 솔루션을 구축할 때 매우 유용할 것입니다.

요약

이 랩에서는 Ansible 플레이북에서 셸 명령 출력을 효과적으로 사용하는 방법을 배웠습니다. 셸 명령을 실행하고 출력을 캡처하는 기본 사항부터 시작하여 조건부 실행, 오류 처리, JSON 과 같은 구조화된 데이터 형식 처리와 같은 고급 기술로 발전했습니다.

다음과 같은 몇 가지 주요 기술을 습득했습니다.

  • shell 모듈을 사용하여 Ansible 플레이북에서 셸 명령 실행
  • register 지시문을 사용하여 명령 출력 캡처
  • debug 모듈을 사용하여 출력 표시
  • Jinja2 필터 및 조건으로 출력 처리
  • Ansible 과 셸 스크립트를 결합하는 실용적인 자동화 도구 만들기

이러한 기술을 통해 다양한 시스템 조건에 적응하고 수행되는 작업에 대한 유용한 피드백을 제공할 수 있는 보다 동적이고 반응적인 자동화 워크플로우를 만들 수 있습니다.

Ansible 여정을 계속 진행하면서 셸 명령이 훌륭한 유연성을 제공하지만 Ansible 의 내장 모듈은 일반적인 작업에 대해 더 강력하고 이식 가능한 솔루션인 경우가 많다는 점을 기억하십시오. 기존 셸 스크립트를 활용하거나 Ansible 모듈로 쉽게 처리할 수 없는 복잡한 작업을 수행해야 할 때 셸 명령을 사용하십시오.