Facts คือข้อมูลระบบที่ Playbook รวบรวมจาก remote host โดยอัตโนมัติก่อน task แรกเสมอ ครอบคลุมตั้งแต่ OS version, IP address, จำนวน CPU ไปจนถึง disk layout ทำให้ Playbook ตัดสินใจตามสภาพแวดล้อมจริงได้โดยไม่ต้อง hardcode
บทความนี้อธิบาย facts ในเชิงลึก ตั้งแต่โครงสร้าง ansible_facts, การใช้ gather_subset เพื่อเลือกเฉพาะข้อมูลที่ต้องการ, การสร้าง custom facts ด้วยไฟล์ .fact, ไปจนถึง magic variables ที่ใช้บ่อยในทางปฏิบัติ
โครงสร้าง ansible_facts
เมื่อ Playbook รัน module setup จะทำงานก่อน task แรกเสมอ (เว้นแต่ปิดด้วย gather_facts: false) ข้อมูลทั้งหมดเก็บอยู่ใน dictionary ansible_facts และเข้าถึงได้โดยตรงด้วยตัวแปรที่ขึ้นต้น ansible_
---
- name: Display basic system facts
hosts: all
tasks:
- name: Show OS and hardware info
debug:
msg: |
Hostname: {{ ansible_hostname }}
Distro: {{ ansible_distribution }}
RAM (MB): {{ ansible_memtotal_mb }}
IP: {{ ansible_default_ipv4.address }}
ค่าที่เข้าถึงได้สองแบบ เช่น ansible_facts['os_family'] และ ansible_os_family ให้ผลเหมือนกัน แบบหลังใช้บ่อยกว่าเพราะกระชับกว่า
gather_subset: เลือกเฉพาะ Facts ที่ต้องการ
การรวบรวม facts ทั้งหมดใช้เวลาประมาณ 1-2 วินาทีต่อ host เมื่อรันกับเซิร์ฟเวอร์หลายร้อยเครื่องพร้อมกัน เวลาสะสมอาจเพิ่มขึ้นมากโดยไม่จำเป็น ถ้าต้องการเฉพาะบางหมวด ใช้ gather_subset เพื่อจำกัดขอบเขต
---
- name: Gather only network and hardware facts
hosts: all
gather_facts: true
gather_subset:
- network
- hardware
- "!virtual" # ยกเว้น virtualization facts
tasks:
- name: Show IP address
debug:
msg: "Network facts gathered successfully"
Subset ที่ใช้บ่อยมีดังนี้: all รวบรวมทุกอย่าง (default), min เฉพาะข้อมูลพื้นฐานเช่น hostname และวันที่, network สำหรับ IP และ network interface, hardware สำหรับ CPU RAM และ disk, และ virtual สำหรับ virtualization type การใช้ ! นำหน้าชื่อ subset หมายถึงยกเว้น subset นั้นออกจากการรวบรวม
Custom Facts: กำหนดข้อมูลเองบน Remote Host
นอกจาก built-in facts ยังสร้าง custom facts ได้โดยวางไฟล์ในไดเรกทอรี /etc/ansible/facts.d/ บน remote host รองรับสองรูปแบบ: INI และ JSON executable script
Custom Facts แบบ INI
# /etc/ansible/facts.d/app.fact บน remote host
[application]
name=myapp
version=2.5.1
environment=production
[database]
host=db01.internal
port=5432
เข้าถึงผ่าน ansible_local ในรูปแบบ ansible_local.<ชื่อไฟล์>.<section>.<key>:
- name: Use custom facts
debug:
msg: |
App: {{ ansible_local.app.application.name }} v{{ ansible_local.app.application.version }}
DB: {{ ansible_local.app.database.host }}:{{ ansible_local.app.database.port }}
Custom Facts แบบ Executable Script
ถ้าไฟล์ .fact เป็น executable script ระบบจะรันและอ่าน JSON output แทน ทำให้ facts คำนวณค่าแบบ dynamic ได้
#!/bin/bash
# /etc/ansible/facts.d/system_status.fact (chmod +x ก่อนใช้งาน)
DISK_FREE=$(df -BG / | tail -1 | awk '{print $4}' | tr -d 'G')
LOAD=$(uptime | awk -F'load average:' '{print $2}' | cut -d, -f1 | tr -d ' ')
echo "{\"disk_free_gb\": ${DISK_FREE}, \"load_1min\": \"${LOAD}\"}
- name: Alert if disk low
debug:
msg: "WARNING: Low disk space!"
when: ansible_local.system_status.disk_free_gb | int < 10
Deploy Custom Facts ด้วย Playbook
แทนที่จะวางไฟล์ manual สามารถ deploy custom fact files ด้วย Playbook ได้เลย
---
- name: Deploy custom facts
hosts: all
become: true
tasks:
- name: Create facts directory
file:
path: /etc/ansible/facts.d
state: directory
mode: '0755'
- name: Deploy app fact file
copy:
dest: /etc/ansible/facts.d/app.fact
content: |
[application]
name={{ app_name }}
version={{ app_version }}
environment={{ env }}
mode: '0644'
- name: Re-gather facts to load new custom facts
setup:
filter: ansible_local
- name: Verify custom fact loaded
debug:
msg: "Custom facts loaded successfully"
การเรียก setup หลัง deploy ทำให้โหลด custom facts ที่เพิ่งสร้างได้ทันทีโดยไม่ต้องรอ Playbook รอบถัดไป
Magic Variables
Magic variables คือตัวแปรพิเศษที่ระบบสร้างขึ้นโดยอัตโนมัติ ไม่ได้มาจาก fact gathering แต่มาจากโครงสร้าง inventory และ playbook เอง
# Magic variables ที่ใช้บ่อยที่สุด
hostvars # dict ของ facts และ variables จากทุก host ใน inventory
groups # dict ของ group → list of hosts
# เช่น groups['webservers'] = ['web01', 'web02']
group_names # list ของ group ที่ host ปัจจุบันอยู่
inventory_hostname # ชื่อ host ใน inventory
ตัวอย่างการใช้ hostvars เพื่ออ่าน IP ของ database server แล้วเขียนลง config ของ web server:
---
- name: Configure app servers with DB IP
hosts: webservers
tasks:
- name: Write DB connection config
template:
src: templates/db.conf.j2
dest: /etc/myapp/db.conf
# templates/db.conf.j2
# DB_HOST = {{ hostvars[groups['dbservers'][0]]['ansible_default_ipv4']['address'] }}
# DB_PORT = 5432
Facts ใน Conditional: ปรับ Playbook ตาม OS
Pattern ที่พบบ่อยที่สุดคือใช้ fact เพื่อเลือก task ตาม OS family ทำให้ Playbook เดียวรันได้ทั้งบน Ubuntu และ CentOS:
---
- name: Install web server across OS families
hosts: all
become: true
tasks:
- name: Install on Debian/Ubuntu
apt:
name: nginx
state: present
when: ansible_os_family == "Debian"
- name: Install on RHEL/CentOS/Rocky
dnf:
name: nginx
state: present
when: ansible_os_family != "Debian"
- name: Set worker_processes to match CPU count
lineinfile:
path: /etc/nginx/nginx.conf
regexp: '^worker_processes'
line: "worker_processes {{ ansible_processor_vcpus }};"
- name: Skip swap config if RAM > 8GB
debug:
msg: "Enough RAM, skipping swap setup"
when: ansible_memtotal_mb > 8192
สรุป
Facts ทำให้ Playbook ปรับตัวได้ตามสภาพแวดล้อมจริงโดยไม่ต้อง hardcode ค่าใด ๆ Pattern หลักที่ควรจำ: ใช้ gather_subset เพื่อเพิ่มความเร็วเมื่อต้องการเฉพาะบางหมวด, สร้าง custom facts ด้วยไฟล์ .fact เมื่อต้องการข้อมูลที่ built-in ไม่มี, และใช้ hostvars เมื่อต้องการข้อมูลของ host อื่นจาก play เดียวกัน
จุดสำคัญที่ต้องระวัง: custom facts ที่เพิ่งสร้างจะยังไม่โหลดโดยอัตโนมัติในรอบเดิม ต้องเรียก setup ซ้ำหลัง deploy หรือรอรอบถัดไปจึงจะใช้งานได้

