PYY0715's Tech Blog v3.1.0

Search the Post!

[Ansible for Kubespray] 3. Playbooks, Variables and Facts

Cloudnet@ K8S Deploy — Week2

Introduction

지난 글에서는 Inventory 구조와 Behavioral Inventory Parameters를 다루었습니다. group_varshost_vars를 사용하여 변수를 계층적으로 관리하는 방법과 Inventory 범위 내 변수 우선순위를 확인했습니다.

이번 글에서는 Playbook과 변수의 활용 방법을 다룹니다. Playbook 구조를 이해하고, Playbook 변수, Extra Variables, Registered Variables를 사용하여 동적인 자동화를 구현합니다. 또한 Ansible이 자동으로 수집하는 시스템 정보인 Facts를 활용하는 방법과 전체 변수 우선순위 체계를 실습으로 확인합니다.

Playbooks

Playbook은 YAML 형식으로 작성된 자동화 스크립트입니다. 하나 이상의 Play로 구성되며, 각 Play는 특정 호스트 그룹에서 실행할 Task 목록을 정의합니다.

Playbook Structure

기본 Playbook 구조를 살펴보겠습니다.

---
- name: Manage system users
  hosts: all
  become: true
  vars:
    user: ansible

  tasks:
    - name: Create user 
      ansible.builtin.user:
        name: ""
        state: present
      register: user_result

    - name: Display created user info
      ansible.builtin.debug:
        msg: "User  created with UID "

이는 Manage system users Play 아래, 2개의 Tasks를 가지고 있는 구조입니다.

  1. Create user
  2. Display created user info

하나의 Playbook에 여러 Play를 포함할 수 있으며, 각 Play는 서로 다른 호스트 그룹을 대상으로 할 수 있습니다. Play는 정의된 순서대로 실행됩니다.

각 필드의 역할은 다음과 같습니다.

Tasks

각 Task는 namemodule로 구성됩니다. name은 Task의 설명이고, module은 Task가 실행할 동작입니다.

각 Play 내에서 Task는 정의된 순서대로 실행되지만, 여러 호스트에 대해서는 병렬로 실행됩니다. 단, 호스트 실행 순서는 보장되지 않습니다.

Task Execution States

Playbook을 실행하면 각 Task는 다음 중 하나의 상태를 반환합니다.

State Description
ok Task가 성공적으로 실행되었고 변경 사항 없음
changed Task가 성공적으로 실행되었고 시스템이 변경됨
failed Task 실행 실패
skipped 조건에 의해 Task가 건너뜀
unreachable 호스트 연결 불가
rescued 실패 후 복구 블록에 의해 성공
ignored 실패했지만 ignore_errors로 무시됨

이러한 상태에 기반해서 멱등성을 준수하도록 동작합니다.

Module-Specific Change Detection

각 모듈은 자체적인 기준으로 변경 여부를 판단합니다. 대표적인 모듈들의 동작 방식은 다음과 같습니다.

이에 따른 변경을 감지하는 방법은 다음과 같습니다.

  1. ansible.builtin.apt/yum module:
    • 패키지가 없으면 설치 → changed
    • 패키지가 이미 설치되어 있으면 → ok
  2. ansible.builtin.service module:
    • 서비스가 중지 상태인데 state: started를 실행 → changed
    • 서비스가 이미 실행 중이면 → ok
  3. ansible.builtin.copy module:
    • 파일이 없거나 내용이 다르면 복사 → changed
    • 파일이 이미 존재하고 내용이 같으면 → ok
  4. ansible.builtin.command/shell module:
    • 항상 changed 반환 (실제 변경 여부를 판단하지 않음)
    • 멱등성을 보장하지 않습니다.
    • 이 모듈들은 임의의 명령어를 실행하므로, Ansible 입장에서 명령어가 시스템을 변경했는지 알 수 없습니다. 예를 들어 uptime 명령은 단순히 정보를 출력하지만, useradd 명령은 실제로 사용자를 생성합니다. Ansible은 이 두 명령의 차이를 구별할 방법이 없으므로, 항상 changed로 처리하여 안전하게 동작하도록 설계되었습니다.

commandshell 모듈의 변경 여부를 제어하려면 changed_when을 사용합니다. 즉 이는 시스템을 변경하지 않았다고 처리하는 것입니다.

- name: Check disk space
  ansible.builtin.command: df -h
  register: disk_info
  changed_when: false  # 확인만 하고 변경 없음으로 처리

또는 creates 파라미터로 멱등성을 구현할 수도 있습니다.

- name: Download file if not exists
  ansible.builtin.command: wget http://example.com/file.tar.gz
  args:
    creates: /tmp/file.tar.gz  # 파일이 있으면 실행 건너뜀

Variables

Ansible의 변수 시스템은 매우 유연하지만, 그만큼 복잡할 수 있습니다. 변수를 정의할 수 있는 위치가 많고, 같은 이름의 변수가 여러 곳에 정의될 수 있기 때문입니다. Ansible은 명확한 우선순위 규칙을 통해 이를 해결합니다.

Variable Precedence

Ansible 공식 문서에 따르면 변수 우선순위는 22단계로 세분화되어 있습니다. 하지만 아래의 순서만 이해해도 대부분의 상황을 다룰 수 있습니다.

  1. Extra variables (명령줄 -e 옵션)
  2. Play variables (특정 Play의 vars:)
  3. Playbook variables (vars:, vars_files:)
  4. Role defaults (roles/role_name/defaults/main.yml)
  5. Inventory variables (group_vars/all, group_vars/group_name, host_vars/host_name)

숫자가 낮을수록 우선순위가 높아 다른 변수를 오버라이드합니다. Extra Variables는 가장 높은 우선순위를 가져 어떤 변수도 덮어쓸 수 있습니다.

Extra Variables

Extra Variables는 명령줄에서 -e 또는 --extra-vars 옵션으로 전달하는 변수입니다. 가장 높은 우선순위를 가지므로 모든 다른 변수를 덮어씁니다.

ansible-playbook site.yml -e "http_port=8080"

공백을 기준으로 여러 변수를 전달할 수 있습니다.

ansible-playbook site.yml -e "http_port=8080 max_connections=200"

JSON 형식으로도 전달할 수 있습니다.

ansible-playbook site.yml -e '{"http_port": 8080, "max_connections": 200}'

파일에서 변수를 로드할 수도 있습니다.

ansible-playbook site.yml -e "@extra_vars.yml"

Playbook Variables

Playbook 내에서 변수를 정의하는 방법은 두 가지입니다.

1. vars 섹션에서 직접 정의

---
- name: Deploy application
  hosts: webservers
  vars:
    app_version: "2.1.0"
    app_port: 8080
    app_user: webapp
  tasks:
    - name: Display app version
      ansible.builtin.debug:
        msg: "Deploying version "

2. vars_files로 파일 로드

---
- name: Deploy application
  hosts: webservers
  vars_files:
    - vars/common.yml
    - vars/app_config.yml
  tasks:
    - name: Display app version
      ansible.builtin.debug:
        msg: "Deploying version "

vars_files를 사용하면 변수를 논리적으로 그룹화하여 관리할 수 있습니다. 또한 같은 변수 파일을 여러 Playbook에서 재사용할 수 있습니다.

Registered Variables

Registered Variables는 Task의 실행 결과를 변수에 저장하는 기능입니다. 이전 Task의 결과를 다음 Task에서 재사용 할 수 있습니다.

---
- name: Check system information
  hosts: all
  tasks:
    - name: Get uptime
      ansible.builtin.command: uptime
      register: uptime_result

    - name: Display uptime
      ansible.builtin.debug:
        var: uptime_result

Registered Variable의 JSON 구조는 다음과 같습니다.

Registered Variables Registered Variables

rc는 명령의 종료 상태를 나타내며, 0은 성공을 의미합니다. 상태에 기반하여 stdout 또는 stderr를 출력합니다.

Magic Variables

Magic Variables는 Ansible에서 자동으로 생성되는 변수입니다. 이 변수들은 Playbook의 모든 Task에서 사용할 수 있습니다.

아래와 같이 사용될 수 있습니다.

---
- name: Display magic variables
  hosts: all
  tasks:
      - name: Show inventory hostname
        ansible.builtin.debug:
            msg: "Current host: "

      - name: Show group membership
        ansible.builtin.debug:
            msg: "This host belongs to: "

Magic Variables Magic Variables

Facts

Facts는 Ansible이 관리 대상 호스트에서 자동으로 수집하는 시스템 정보입니다. 운영체제, IP 주소, CPU, 메모리, 디스크 등 다양한 정보를 포함합니다.

Gathering Facts

Playbook을 실행하면 기본적으로 아래와 같이 첫 번째 Task로 “Gathering Facts”가 자동 실행됩니다.

Gathering Facts Gathering Facts

이 단계에서 Ansible은 각 호스트에 접속하여 setup 모듈을 실행하고 시스템 정보를 수집합니다. 수집된 Facts는 ansible_facts 변수에 저장되며, Playbook의 모든 Task에서 사용할 수 있습니다.

Facts 수집을 비활성화하려면 gather_facts: no를 설정합니다. Facts가 필요 없는 간단한 작업에서는 비활성화하여 실행 시간을 단축할 수 있습니다.

Facts Usage

위에서 언급한것처럼 Facts는 Playbook의 모든 Task에서 사용할 수 있기 때문에

자주 사용되는 Facts는 다음과 같습니다.

System Information

Network Information

Hardware Information

이외에도 다양한 Facts가 존재합니다. 필요한 Facts를 확인하려면 ansible_facts 변수를 출력하거나 ansible all -m setup 모듈을 실행하여 확인할 수 있습니다.

Conditional Tasks on Facts

위에서 확인한 Facts를 조건문과 함께 사용하여 OS별로 다른 작업을 수행할 수 있습니다.

---
- name: Install packages based on OS
  hosts: all
  become: yes
  tasks:
    - name: Install nginx on Debian/Ubuntu
      ansible.builtin.apt:
        name: nginx
        state: present
      when: ansible_facts['os_family'] == "Debian"

    - name: Install nginx on RedHat/CentOS
      ansible.builtin.yum:
        name: nginx
        state: present
      when: ansible_facts['os_family'] == "RedHat"

이전 글에서 구성된 환경은 tnode3의 경우 Rocky Linux9으로 구성되었기 때문에 조건문에 따라 1번째 Task는 Skip되고 2번째 Task는 실행됩니다.

Result Result

Challenges

이번 실습에서는 3가지 도전과제를 해결합니다.

  1. 생성된 user를 ansible.builtin.user 모듈을 통해서 제거
  2. 관리 대상에 uptime을 ansible.builtin.debug 모듈을 통해서 확인
  3. Facts를 사용하여 3개의 서버(노드)의 커널 버전과 운영체제 종류를 출력

Mission 1

이전 실습에서 생성한 ansible 사용자를 제거합니다. ansible.builtin.user 모듈을 사용하면 state: absent로 설정하여 사용자를 삭제할 수 있습니다.

---
- name: Remove ansible user
  hosts: all
  become: true
  vars:
      user: ansible

  tasks:
      - name: Remove user 
        ansible.builtin.user:
            name: "{{ user }}"
            state: absent

      - name: Display removal result
        ansible.builtin.debug:
            msg: "User {{ user }} has been removed"

Mission 2

ansible.builtin.debug 모듈을 사용하여 각 서버의 uptime을 확인합니다. command 모듈로 uptime을 실행하고 결과를 register로 저장한 후 debug 모듈로 출력합니다.

---
- name: Check system uptime
  hosts: all
  tasks:
      - name: Get uptime
        ansible.builtin.command: uptime
        register: uptime_result
        changed_when: false

      - name: Display uptime
        ansible.builtin.debug:
            msg: "{{ uptime_result.stdout }}"

Mission 3

Facts를 사용하여 3개 서버의 커널 버전과 운영체제 종류를 출력합니다.

---
- name: Display system information
  hosts: all
  tasks:
      - name: Display kernel and OS info
        ansible.builtin.debug:
            msg:
                - "Host: {{ inventory_hostname }}"
                - "OS: {{ ansible_facts['distribution'] }} {{ ansible_facts['distribution_version'] }}"
                - "Kernel: {{ ansible_facts['kernel_version'] }}"
Why don't you read something next?
[Ansible for Kubespray] 4. Loop, Conditions

[Ansible for Kubespray] 4. Loop, Conditions

Share

Comments