11 min to read
[Ansible for Kubespray] 3. Playbooks, Variables and Facts
Cloudnet@ K8S Deploy — Week2
Introduction
지난 글에서는 Inventory 구조와 Behavioral Inventory Parameters를 다루었습니다. group_vars와 host_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를 가지고 있는 구조입니다.
- Create user
- Display created user info
하나의 Playbook에 여러 Play를 포함할 수 있으며, 각 Play는 서로 다른 호스트 그룹을 대상으로 할 수 있습니다. Play는 정의된 순서대로 실행됩니다.
각 필드의 역할은 다음과 같습니다.
name: Play에 대한 설명hosts: 대상 호스트 그룹become: 권한 상승 여부vars: Play 범위에서 사용할 변수 정의tasks: 순차적으로 실행할 작업 목록
Tasks
각 Task는 name과 module로 구성됩니다. 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
각 모듈은 자체적인 기준으로 변경 여부를 판단합니다. 대표적인 모듈들의 동작 방식은 다음과 같습니다.
이에 따른 변경을 감지하는 방법은 다음과 같습니다.
- ansible.builtin.apt/yum module:
- 패키지가 없으면 설치 →
changed - 패키지가 이미 설치되어 있으면 →
ok
- 패키지가 없으면 설치 →
- ansible.builtin.service module:
- 서비스가 중지 상태인데
state: started를 실행 →changed - 서비스가 이미 실행 중이면 →
ok
- 서비스가 중지 상태인데
- ansible.builtin.copy module:
- 파일이 없거나 내용이 다르면 복사 →
changed - 파일이 이미 존재하고 내용이 같으면 →
ok
- 파일이 없거나 내용이 다르면 복사 →
- ansible.builtin.command/shell module:
- 항상
changed반환 (실제 변경 여부를 판단하지 않음) - 멱등성을 보장하지 않습니다.
- 이 모듈들은 임의의 명령어를 실행하므로, Ansible 입장에서 명령어가 시스템을 변경했는지 알 수 없습니다. 예를 들어
uptime명령은 단순히 정보를 출력하지만,useradd명령은 실제로 사용자를 생성합니다. Ansible은 이 두 명령의 차이를 구별할 방법이 없으므로, 항상changed로 처리하여 안전하게 동작하도록 설계되었습니다.
- 항상
command와 shell 모듈의 변경 여부를 제어하려면 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단계로 세분화되어 있습니다. 하지만 아래의 순서만 이해해도 대부분의 상황을 다룰 수 있습니다.
- Extra variables (명령줄
-e옵션) - Play variables (특정 Play의
vars:) - Playbook variables (
vars:,vars_files:) - Role defaults (
roles/role_name/defaults/main.yml) - 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
rc는 명령의 종료 상태를 나타내며, 0은 성공을 의미합니다. 상태에 기반하여 stdout 또는 stderr를 출력합니다.
Magic Variables
Magic Variables는 Ansible에서 자동으로 생성되는 변수입니다. 이 변수들은 Playbook의 모든 Task에서 사용할 수 있습니다.
inventory_hostname: Inventory에 정의된 호스트 이름inventory_hostname_short: 호스트 이름의 첫 번째 부분 (FQDN의 경우)groups: 모든 그룹과 그 멤버 정보group_names: 현재 호스트가 속한 그룹 목록hostvars: 모든 호스트의 변수 정보ansible_play_hosts: 현재 Play에서 대상이 되는 호스트 목록ansible_version: Ansible 버전 정보
아래와 같이 사용될 수 있습니다.
---
- 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
Facts
Facts는 Ansible이 관리 대상 호스트에서 자동으로 수집하는 시스템 정보입니다. 운영체제, IP 주소, CPU, 메모리, 디스크 등 다양한 정보를 포함합니다.
Gathering Facts
Playbook을 실행하면 기본적으로 아래와 같이 첫 번째 Task로 “Gathering Facts”가 자동 실행됩니다.
Gathering Facts
이 단계에서 Ansible은 각 호스트에 접속하여 setup 모듈을 실행하고 시스템 정보를 수집합니다. 수집된 Facts는 ansible_facts 변수에 저장되며, Playbook의 모든 Task에서 사용할 수 있습니다.
Facts 수집을 비활성화하려면 gather_facts: no를 설정합니다. Facts가 필요 없는 간단한 작업에서는 비활성화하여 실행 시간을 단축할 수 있습니다.
Facts Usage
위에서 언급한것처럼 Facts는 Playbook의 모든 Task에서 사용할 수 있기 때문에
자주 사용되는 Facts는 다음과 같습니다.
System Information
ansible_facts['distribution']: 운영체제 이름ansible_facts['distribution_version']: 운영체제 버전ansible_facts['kernel_version']: 커널 버전ansible_facts['architecture']: CPU 아키텍처 정보
Network Information
ansible_facts['default_ipv4']['address']: 기본 IPv4 주소ansible_facts['hostname']: 호스트 정보ansible_facts['fqdn']: FQDN (Fully Qualified Domain Name)
Hardware Information
ansible_facts['processor_vcpus']: CPU 코어 수(가상)ansible_facts['processor_cores']: CPU 코어 수(물리)ansible_facts['memtotal_mb']: 총 메모리(MB)
이외에도 다양한 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
Challenges
이번 실습에서는 3가지 도전과제를 해결합니다.
- 생성된 user를 ansible.builtin.user 모듈을 통해서 제거
- 관리 대상에 uptime을 ansible.builtin.debug 모듈을 통해서 확인
- 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'] }}"
Comments