Ansible

Ansible Facts: รวบรวม System Information อัตโนมัติ

เผยแพร่ · แก้ไขล่าสุด

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 หรือรอรอบถัดไปจึงจะใช้งานได้