Dynamic Inventory #
Static inventory bekerja baik saat infrastruktur stabil dan berubah jarang. Tapi di cloud atau lingkungan yang dinamis — server di-provision dan di-terminate setiap hari, container scale up dan down — memelihara file hosts.ini secara manual adalah pekerjaan yang tidak mungkin. Dynamic inventory menyelesaikan ini: Ansible mengambil daftar host secara real-time dari sumber yang otoritatif seperti AWS EC2, GCP, Azure, VMware, atau CMDB internal, setiap kali playbook dijalankan.
Menggunakan Inventory Plugin Bawaan (AWS EC2) #
Collection amazon.aws menyediakan inventory plugin aws_ec2 yang mengambil instance secara langsung dari AWS API:
ansible-galaxy collection install amazon.aws
pip install boto3
# inventory/aws_ec2.yml
# Nama file HARUS diakhiri dengan aws_ec2.yml atau aws_ec2.yaml
plugin: amazon.aws.aws_ec2
regions:
- ap-southeast-1 # Singapura
- ap-southeast-3 # Jakarta
# Filter: hanya ambil instance yang running
filters:
instance-state-name: running
"tag:Environment": production
# Gunakan private IP untuk koneksi internal
hostnames:
- private-ip-address
# Kelompokkan instance berdasarkan tag
keyed_groups:
- prefix: role
key: tags.Role # Group: role_webserver, role_database, dll.
- prefix: env
key: tags.Environment # Group: env_production, env_staging
# Buat grup berdasarkan region
groups:
singapore: "'ap-southeast-1' in placement.region"
jakarta: "'ap-southeast-3' in placement.region"
# Tambahkan variabel dari tag EC2
compose:
ansible_host: private_ip_address
instance_type: instance_type
availability_zone: placement.availability_zone
# Test inventory sebelum digunakan di playbook
ansible-inventory -i inventory/aws_ec2.yml --list
ansible-inventory -i inventory/aws_ec2.yml --graph
# Gunakan dalam playbook
ansible-playbook -i inventory/aws_ec2.yml site.yml
Inventory Plugin untuk GCP #
# inventory/gcp_compute.yml
plugin: google.cloud.gcp_compute
projects:
- my-production-project
zones:
- asia-southeast2-a # Jakarta
- asia-southeast2-b
filters:
- status = RUNNING
- labels.environment = production
keyed_groups:
- prefix: role
key: labels.role
- prefix: zone
key: zone
compose:
ansible_host: networkInterfaces[0].networkIP
Menulis Inventory Script Sendiri #
Untuk sumber inventory yang tidak punya plugin bawaan (CMDB internal, database legacy), buat inventory script Python:
#!/usr/bin/env python3
# inventory/cmdb_inventory.py
import json
import sys
import argparse
try:
import requests
except ImportError:
print(json.dumps({"_meta": {"hostvars": {}}}))
sys.exit(0)
CMDB_URL = "https://cmdb.company.internal/api"
CMDB_TOKEN = "your-token-here" # Gunakan env variable di production
def get_inventory():
"""Ambil semua server dari CMDB dan kelompokkan."""
headers = {"Authorization": f"Bearer {CMDB_TOKEN}"}
try:
response = requests.get(
f"{CMDB_URL}/servers",
params={"status": "active"},
headers=headers,
timeout=15
)
response.raise_for_status()
servers = response.json()
except Exception as e:
sys.stderr.write(f"Error mengambil inventory dari CMDB: {e}\n")
return {"_meta": {"hostvars": {}}}
inventory = {
"_meta": {"hostvars": {}},
"all": {"children": []},
}
for server in servers:
hostname = server["hostname"]
env = server.get("environment", "unknown")
role = server.get("role", "unknown")
# Tambahkan host variables
inventory["_meta"]["hostvars"][hostname] = {
"ansible_host": server.get("ip_address", hostname),
"server_id": server.get("id"),
"datacenter": server.get("datacenter"),
"os": server.get("os"),
}
# Buat grup berdasarkan environment
env_group = f"env_{env}"
if env_group not in inventory:
inventory[env_group] = {"hosts": [], "vars": {"env": env}}
inventory["all"]["children"].append(env_group)
inventory[env_group]["hosts"].append(hostname)
# Buat grup berdasarkan role
role_group = f"role_{role}"
if role_group not in inventory:
inventory[role_group] = {"hosts": []}
inventory["all"]["children"].append(role_group)
inventory[role_group]["hosts"].append(hostname)
return inventory
def get_host(hostname):
"""Ambil variabel untuk host tertentu."""
headers = {"Authorization": f"Bearer {CMDB_TOKEN}"}
try:
response = requests.get(
f"{CMDB_URL}/servers/{hostname}",
headers=headers,
timeout=10
)
response.raise_for_status()
server = response.json()
return {
"ansible_host": server.get("ip_address", hostname),
"server_id": server.get("id"),
}
except Exception:
return {}
def main():
parser = argparse.ArgumentParser()
parser.add_argument('--list', action='store_true',
help='Tampilkan semua inventory')
parser.add_argument('--host', type=str,
help='Tampilkan variabel untuk host tertentu')
args = parser.parse_args()
if args.list:
print(json.dumps(get_inventory(), indent=2))
elif args.host:
print(json.dumps(get_host(args.host), indent=2))
else:
print(json.dumps({}))
if __name__ == '__main__':
main()
# Beri permission executable
chmod +x inventory/cmdb_inventory.py
# Test
./inventory/cmdb_inventory.py --list
./inventory/cmdb_inventory.py --host web-01.company.com
# Gunakan dalam playbook
ansible-playbook -i inventory/cmdb_inventory.py site.yml
Menggabungkan Beberapa Sumber Inventory #
Ansible bisa menggabungkan beberapa sumber inventory sekaligus — cukup arahkan ke direktori:
inventory/
├── aws_ec2.yml # Server di AWS
├── cmdb_inventory.py # Server on-premise dari CMDB
├── static_hosts.ini # Server khusus yang tidak ada di dua sumber di atas
└── group_vars/
├── all.yml
├── role_webserver.yml
└── env_production.yml
# Ansible otomatis menggabungkan semua sumber
ansible-playbook -i inventory/ site.yml
Caching Inventory #
Untuk infrastruktur besar, memanggil API cloud setiap kali playbook dijalankan lambat dan mungkin kena rate limit. Aktifkan caching:
# ansible.cfg
[inventory]
cache = true
cache_plugin = jsonfile
cache_connection = /tmp/ansible_inventory_cache
cache_timeout = 300 # Cache berlaku 5 menit
# Refresh cache manual saat diperlukan
ansible-inventory -i inventory/ --list --flush-cache
Ringkasan #
- Inventory plugin (seperti
aws_ec2,gcp_compute) lebih direkomendasikan dari inventory script — lebih terintegrasi dengan ekosistem Ansible dan mendukung caching bawaan.- Gunakan
keyed_groupsuntuk otomatis membuat grup dari tag/label cloud — semua server dengan tagRole: webserverlangsung masuk ke gruprole_webserver.composeuntuk memetakan field API ke variabel Ansible — misalnya,ansible_host: private_ip_addressmemastikan Ansible menggunakan IP private, bukan public.- Inventory script Python harus mendukung flag
--listdan--host— ini adalah interface yang diharapkan Ansible.- Gabungkan beberapa sumber dengan mengarahkan
-ike direktori — Ansible otomatis memuat semua file inventory di direktori tersebut.- Aktifkan caching inventory untuk menghindari API call berulang — sangat penting untuk infrastruktur cloud besar dengan ribuan instance.