Ansible Inventory Best Practices: จัดระเบียบ Hosts ในโปรเจกต์ขนาดใหญ่

เมื่อโปรเจกต์ขยายจาก server ไม่กี่เครื่องเป็นหลายสิบหรือหลายร้อยเครื่อง inventory file ที่เคยเขียนง่าย ๆ ในไฟล์เดียวจะกลายเป็นปัญหา การจัดระเบียบ inventory ตั้งแต่เริ่มต้นด้วย best practices ที่ถูกต้องช่วยให้ทีมทำงานร่วมกันได้ง่าย เพิ่มหรือลด server ได้คล่องตัว และลดโอกาสผิดพลาดในระหว่าง deployment

บทความนี้รวบรวมแนวทางที่ใช้ได้จริงในโปรเจกต์ขนาดใหญ่ ตั้งแต่การแยกไฟล์ inventory ตามสภาพแวดล้อม การใช้โครงสร้างโฟลเดอร์มาตรฐาน ไปจนถึงการ validate ก่อนนำไปใช้งาน

แยก Inventory ตาม Environment

ข้อผิดพลาดที่พบบ่อยที่สุดคือใส่ทุก environment ไว้ในไฟล์เดียวกัน ทำให้เสี่ยงต่อการรัน playbook ผิด environment แนวทางที่ดีกว่าคือแยก inventory ออกเป็นไฟล์หรือโฟลเดอร์ตาม environment

project/
├── inventories/
│   ├── production/
│   │   ├── hosts.ini         # รายชื่อ hosts
│   │   ├── group_vars/
│   │   │   ├── all.yml
│   │   │   └── webservers.yml
│   │   └── host_vars/
│   ├── staging/
│   │   ├── hosts.ini
│   │   ├── group_vars/
│   │   └── host_vars/
│   └── development/
│       ├── hosts.ini
│       └── group_vars/
├── roles/
└── site.yml

การรัน playbook จะระบุ environment ผ่าน -i flag ทำให้ชัดเจนว่ากำลังทำงานกับ environment ไหน

# รัน playbook กับ production เท่านั้น
ansible-playbook -i inventories/production site.yml

# รัน playbook กับ staging
ansible-playbook -i inventories/staging site.yml

ใช้ Group Naming Convention ที่สม่ำเสมอ

ชื่อ group ที่ดีต้องสื่อความหมายชัดเจนและสม่ำเสมอตลอดทั้งโปรเจกต์ แนะนำรูปแบบ [role]_[environment] หรือแยก role กับ environment เป็น group คนละชั้น

# รูปแบบที่แนะนำ: แยก role และ environment เป็น group ต่างหาก
[webservers]
web1.example.com
web2.example.com

[dbservers]
db1.example.com

[production]
web1.example.com
db1.example.com

[staging]
web2.example.com

# ใช้ children เพื่อจัดกลุ่มย่อย
[production:children]
webservers

[all:vars]
ansible_user=ubuntu

กำหนด ansible_host สำหรับทุก Host

ควรกำหนด ansible_host เป็น IP address ตรง ๆ แทนการใช้ hostname ที่ต้องพึ่ง DNS resolution เพราะช่วยให้ playbook ทำงานได้แม้ DNS มีปัญหา และยังทำให้ตรวจสอบได้ง่ายว่า playbook กำลังเชื่อมต่อไปยัง IP ใด

# inventories/production/hosts.ini
[webservers]
web-prod-1  ansible_host=203.0.113.10
web-prod-2  ansible_host=203.0.113.11

[dbservers]
db-primary  ansible_host=10.0.1.20
db-replica  ansible_host=10.0.1.21

เก็บ Sensitive Data ใน Vault

ข้อมูลสำคัญเช่น password, API key, หรือ private key ไม่ควรอยู่ใน inventory หรือ group_vars แบบ plaintext ใช้ Ansible Vault encrypt ก่อนเก็บไว้

# สร้างไฟล์ที่ encrypt ด้วย vault
ansible-vault create inventories/production/group_vars/all/vault.yml

# เนื้อหาใน vault.yml (จะถูก encrypt)
vault_db_password: "s3cur3P@ssw0rd"
vault_api_key: "abc123xyz"

# ในไฟล์ group_vars/all/main.yml อ้างถึง vault variable
db_password: "{{ vault_db_password }}"
api_key: "{{ vault_api_key }}"

ใช้ inventory Directory แทนไฟล์เดียว

เมื่อส่งโฟลเดอร์เป็น inventory (-i inventories/production/) ระบบจะอ่านทุกไฟล์ inventory ในโฟลเดอร์นั้นอัตโนมัติ ทำให้แบ่งกลุ่ม host ออกเป็นหลายไฟล์ได้โดยไม่ต้อง merge ทุกอย่างไว้ที่เดียว

inventories/production/
├── webservers.ini     # hosts สำหรับ web tier
├── dbservers.ini      # hosts สำหรับ database tier
├── monitoring.ini     # hosts สำหรับ monitoring
└── group_vars/
    ├── all.yml
    ├── webservers.yml
    └── dbservers.yml

Documentation ใน Inventory

comment ใน inventory ช่วยให้สมาชิกทีมคนอื่นเข้าใจได้ทันทีว่า server แต่ละเครื่องทำหน้าที่อะไร ควรระบุข้อมูลสำคัญเช่น role, location, หรือเหตุผลที่ config พิเศษ

[webservers]
# Primary web server — Bangkok DC, 8 vCPU / 16GB RAM
web-prod-1  ansible_host=203.0.113.10

# Secondary web server — Singapore DC (DR)
web-prod-2  ansible_host=203.0.113.11  ansible_port=2222

[dbservers]
# PostgreSQL primary — DO NOT run destructive tasks directly
db-primary  ansible_host=10.0.1.20

Test Inventory ก่อน Deploy เสมอ

ก่อนรัน playbook จริงในทุก environment โดยเฉพาะ production ควร dry-run ด้วย --check และตรวจสอบ inventory ให้แน่ใจก่อน

# ตรวจสอบโครงสร้าง inventory ก่อน deploy
ansible-inventory -i inventories/production --list
ansible-inventory -i inventories/production --graph

# Dry-run ดูว่า playbook จะทำอะไรบ้าง
ansible-playbook -i inventories/production site.yml --check

# Limit เฉพาะ host เดียวก่อน แล้วค่อยขยาย
ansible-playbook -i inventories/production site.yml --limit web-prod-1

Version Control และ Code Review

inventory ทุกไฟล์ต้องอยู่ใน Git เสมอ ยกเว้นไฟล์ที่มีข้อมูลลับ (vault ที่ encrypt แล้วเก็บได้ในบาง workflow) การ review inventory change ผ่าน Pull Request ช่วยให้ทีมมั่นใจว่าไม่มีการเพิ่มหรือลบ host โดยไม่ตั้งใจ การแก้ไข inventory ควรผ่าน process เดียวกับการแก้โค้ด เพื่อให้มี audit trail และสามารถ rollback ได้หากเกิดความผิดพลาด

สรุป

การจัดระเบียบ inventory ในโปรเจกต์ขนาดใหญ่เริ่มจากการแยก environment ออกจากกัน ใช้ชื่อ group ที่สื่อความหมาย กำหนด ansible_host เป็น IP ตรง และเก็บข้อมูลลับด้วย Vault ขั้นตอนเหล่านี้ลงทุนน้อยแต่ช่วยลดปัญหาในระยะยาวได้มาก โดยเฉพาะเมื่อทีมขยายใหญ่ขึ้น