Static inventory file เหมาะสำหรับโครงสร้างที่ไม่เปลี่ยนแปลง แต่เมื่อใช้ Cloud Provider ที่ server สามารถสร้างและลบได้ตลอดเวลา การ maintain ไฟล์ inventory ด้วยมือจะกลายเป็นภาระและเกิดข้อผิดพลาดได้ง่าย Dynamic Inventory แก้ปัญหานี้โดย pull รายชื่อ host จาก Cloud API โดยตรงทุกครั้งที่รัน
บทความนี้อธิบายหลักการทำงานของ Dynamic Inventory, การใช้ inventory plugins สำหรับ AWS EC2 และ DigitalOcean พร้อมแนวทางที่ใช้ได้กับ Vultr และ Cloud Provider อื่น ๆ ในรูปแบบเดียวกัน
Dynamic Inventory ทำงานอย่างไร
แทนที่จะอ่าน inventory จากไฟล์ text ระบบจะ execute script หรือ plugin ที่ติดต่อกับ Cloud API แล้ว return JSON ที่มีโครงสร้างตามรูปแบบที่กำหนด โดย host จะถูก group ตาม tag, region, หรือ attribute อื่น ๆ ที่กำหนดไว้บน Cloud Platform
ติดตั้ง Collections สำหรับ Cloud Plugins
Inventory plugins สำหรับ Cloud Provider ต่าง ๆ มาพร้อมกับ Ansible Collections ซึ่งต้องติดตั้งแยก
# ติดตั้ง Amazon AWS collection
ansible-galaxy collection install amazon.aws
# ติดตั้ง DigitalOcean collection
ansible-galaxy collection install community.digitalocean
# ติดตั้ง community.general สำหรับ Vultr และ provider อื่น ๆ
ansible-galaxy collection install community.general
Dynamic Inventory สำหรับ AWS EC2
สร้างไฟล์ aws_ec2.yml เพื่อกำหนด inventory plugin สำหรับดึง EC2 instances
# aws_ec2.yml
plugin: amazon.aws.aws_ec2
regions:
- ap-southeast-1
- us-east-1
# กรอง instance ที่ running เท่านั้น
filters:
instance-state-name: running
# จัดกลุ่มตาม tag
keyed_groups:
- key: tags.Environment
prefix: env
- key: tags.Role
prefix: role
# เพิ่ม variable จาก instance metadata
hostnames:
- ip-address
- dns-name
ต้องตั้งค่า AWS credentials ก่อน ไม่ว่าจะเป็น environment variables AWS_ACCESS_KEY_ID และ AWS_SECRET_ACCESS_KEY หรือใช้ AWS IAM role บน EC2 instance ที่รัน control node
Dynamic Inventory สำหรับ DigitalOcean
DigitalOcean inventory plugin ใช้ Personal Access Token สำหรับ authentication
# digitalocean.yml
plugin: community.digitalocean.digitalocean
api_token: "{{ lookup('env', 'DO_API_TOKEN') }}"
# จัดกลุ่มตาม tag
keyed_groups:
- key: do_tags
prefix: tag
# จัดกลุ่มตาม region
- key: do_region.slug
prefix: region
ทดสอบ Dynamic Inventory
ก่อนรัน playbook ควรตรวจสอบว่า inventory plugin ดึงข้อมูลได้ถูกต้องด้วย ansible-inventory
# ดู hosts ทั้งหมดที่ดึงมาจาก AWS
ansible-inventory -i aws_ec2.yml --list
# ดูโครงสร้าง groups
ansible-inventory -i aws_ec2.yml --graph
# ping ทุก host ที่อยู่ใน group env_production
ansible -i aws_ec2.yml env_production -m ping
Script-based Dynamic Inventory (สำหรับ Cloud ที่ไม่มี Plugin)
สำหรับ Cloud Provider ที่ยังไม่มี inventory plugin อย่างเป็นทางการ เช่น Vultr หรือ Private Cloud สามารถเขียน script ที่รับ --list argument และ return JSON ในรูปแบบที่กำหนดได้
#!/usr/bin/env python3
# vultr_inventory.py
import sys, json, os, urllib.request
def get_instances():
token = os.environ.get('VULTR_API_KEY', '')
req = urllib.request.Request(
'https://api.vultr.com/v2/instances',
headers={'Authorization': f'Bearer {token}'}
)
with urllib.request.urlopen(req) as resp:
return json.loads(resp.read())['instances']
def build_inventory():
instances = get_instances()
inventory = {'_meta': {'hostvars': {}}}
for inst in instances:
ip = inst.get('main_ip', '')
label = inst.get('label', ip)
tag_group = inst.get('tag', 'ungrouped')
inventory.setdefault(tag_group, {'hosts': []})['hosts'].append(label)
inventory['_meta']['hostvars'][label] = {'ansible_host': ip}
return inventory
if '--list' in sys.argv:
print(json.dumps(build_inventory(), indent=2))
elif '--host' in sys.argv:
print(json.dumps({}))
ตั้ง permission เป็น executable ก่อนใช้งาน: chmod +x vultr_inventory.py แล้วใช้เป็น -i vultr_inventory.py
สรุป
Dynamic Inventory เหมาะสำหรับ environment ที่ server เปลี่ยนแปลงบ่อย ช่วยให้ไม่ต้องอัพเดต inventory ด้วยมือทุกครั้ง Cloud Provider หลักมี inventory plugin พร้อมใช้ผ่าน Ansible Collections สำหรับ provider ที่ไม่มี plugin ก็เขียน script ที่ return JSON ตามมาตรฐานได้ไม่ยาก

