Ansible ile iş yapmaya başladığınızda ilk karşılaştığınız kavram genellikle inventory dosyasıdır. “Hangi sunuculara bağlanacağım? Bunları nasıl gruplayacağım? Her ortam için ayrı dosya mı tutmalıyım?” gibi sorular kafanızı karıştırabilir. Bu yazıda hem statik hem de dinamik inventory yapılarını gerçek dünya senaryolarıyla ele alacağız. Sonunda elinizde gerçekten kullanılabilir, bakımı kolay bir inventory yapısı olacak.
Statik Inventory Nedir ve Ne Zaman Kullanılır?
Statik inventory, sunucu listesini elle yazdığınız, dosya sisteminde saklanan bir yapıdır. Küçük ve değişmeyen altyapılarda son derece pratiktir. On sunucunuz varsa ve bu sunucular pek değişmiyorsa dinamik bir çözüme ihtiyacınız yok demektir. Ansible varsayılan olarak /etc/ansible/hosts dosyasını inventory olarak kabul eder, ama bunu -i parametresiyle istediğiniz dosyaya yönlendirebilirsiniz.
Statik inventory iki formatta yazılabilir: INI ve YAML. Ben genellikle büyük projelerde YAML, küçük projelerde INI tercih ederim. Neden mi? INI daha hızlı yazılır, YAML daha okunabilir ve karmaşık değişken yapılarını daha iyi destekler.
INI Formatında Basit Bir Inventory
En temel haliyle bir INI inventory dosyası şuna benzer:
# /etc/ansible/hosts veya proje_dizini/inventory/hosts
[webservers]
web01.example.com
web02.example.com
web03.example.com
[dbservers]
db01.example.com ansible_port=5522
db02.example.com ansible_port=5522
[loadbalancers]
lb01.example.com
[monitoring]
grafana.example.com
prometheus.example.com
Bu yapıda her köşeli parantez bir grup tanımlar. Gruplar olmadan da çalışır ama gruplar hayatınızı inanılmaz kolaylaştırır. Bir playbook yazarken hosts: webservers diyerek o gruptaki tüm sunuculara ulaşırsınız.
YAML Formatında Inventory
Aynı yapıyı YAML formatında yazdığımızda daha düzenli bir görünüm elde ederiz:
# inventory/hosts.yml
all:
children:
webservers:
hosts:
web01.example.com:
ansible_port: 22
ansible_user: deploy
web02.example.com:
ansible_port: 22
ansible_user: deploy
web03.example.com:
ansible_port: 22
ansible_user: deploy
dbservers:
hosts:
db01.example.com:
ansible_port: 5522
ansible_user: postgres
db02.example.com:
ansible_port: 5522
ansible_user: postgres
loadbalancers:
hosts:
lb01.example.com:
YAML formatında her host’a özel değişkenleri doğrudan tanımlayabiliyorsunuz. Bu çok güçlü bir özellik.
Grup Değişkenleri ve Host Değişkenleri
Inventory dosyasına her şeyi doldurmak yerine, group_vars ve host_vars dizin yapısını kullanmak çok daha temiz bir yaklaşım sunar. Bu yapı, değişkenleri ayrı dosyalarda tutmanızı sağlar.
# Dizin yapısı:
# inventory/
# ├── hosts
# ├── group_vars/
# │ ├── all.yml
# │ ├── webservers.yml
# │ └── dbservers.yml
# └── host_vars/
# ├── web01.example.com.yml
# └── db01.example.com.yml
group_vars/all.yml dosyası tüm hostlara uygulanır. Buraya genel ayarları koyabilirsiniz:
# inventory/group_vars/all.yml
ansible_user: ansible
ansible_ssh_private_key_file: ~/.ssh/ansible_key
ntp_server: ntp.example.com
timezone: Europe/Istanbul
log_retention_days: 30
Webserver grubuna özel değişkenler için:
# inventory/group_vars/webservers.yml
http_port: 80
https_port: 443
max_connections: 1000
nginx_worker_processes: auto
app_deploy_dir: /var/www/html
Belirli bir host için özel ayar gerektiğinde host_vars kullanırsınız:
# inventory/host_vars/web01.example.com.yml
# Bu sunucu production'da daha fazla yük alıyor
nginx_worker_processes: 8
max_connections: 2000
backup_enabled: true
Çoklu Ortam için Inventory Yapısı
Gerçek dünyada genellikle development, staging ve production ortamlarına sahip olursunuz. Bu ortamları ayrı inventory dosyalarında tutmak en sağlıklı yaklaşımdır.
# Önce dizin yapısını oluşturalım
mkdir -p inventories/{production,staging,development}/{group_vars,host_vars}
touch inventories/production/hosts
touch inventories/staging/hosts
touch inventories/development/hosts
Production inventory örneği:
# inventories/production/hosts
[webservers]
web01.prod.example.com
web02.prod.example.com
web03.prod.example.com
[dbservers]
db01.prod.example.com
db02.prod.example.com
[webservers:vars]
env=production
deployment_branch=main
[dbservers:vars]
env=production
db_replica_count=2
[all:vars]
ansible_user=ansible
ansible_ssh_private_key_file=~/.ssh/prod_key
Staging için farklı bir inventory:
# inventories/staging/hosts
[webservers]
web01.staging.example.com
[dbservers]
db01.staging.example.com
[webservers:vars]
env=staging
deployment_branch=develop
[dbservers:vars]
env=staging
db_replica_count=0
[all:vars]
ansible_user=ansible
ansible_ssh_private_key_file=~/.ssh/staging_key
Artık playbook’larınızı ortama göre çalıştırabilirsiniz:
# Production'da çalıştır
ansible-playbook -i inventories/production/hosts deploy.yml
# Staging'de çalıştır
ansible-playbook -i inventories/staging/hosts deploy.yml
# Development'da sadece webserver'lara çalıştır
ansible-playbook -i inventories/development/hosts -l webservers deploy.yml
İç İçe Gruplar: children Kullanımı
Büyük altyapılarda grupları hiyerarşik olarak organize etmek çok değerlidir. Örneğin tüm web ve DB sunucularını kapsayan bir “datacenter” grubu oluşturabilirsiniz:
# inventory/hosts
[webservers]
web01.example.com
web02.example.com
[dbservers]
db01.example.com
[appservers]
app01.example.com
app02.example.com
# Datacenter Istanbul'daki tüm sunucular
[datacenter_ist:children]
webservers
dbservers
appservers
# Tüm uygulama katmanı sunucuları
[app_tier:children]
webservers
appservers
[datacenter_ist:vars]
datacenter=istanbul
ntp_server=ntp.ist.example.com
Bu yapıyla ansible datacenter_ist -m ping diyerek Istanbul datacenter’ındaki tüm sunuculara ping atabilirsiniz.
Dinamik Inventory: Neden İhtiyaç Duyarız?
Cloud ortamlarında sunucular gelir gider. AWS’de otomatik ölçekleme yapıyorsanız, bir sabah 5 sunucuyla uyanıp öğleden sonra 50 sunucuyla çalışıyor olabilirsiniz. Bu sunucuların IP adreslerini elle takip etmek hem imkansız hem de anlamsızdır. İşte burada dinamik inventory devreye girer.
Dinamik inventory, bir script veya plugin aracılığıyla sunucu listesini harici bir kaynaktan (AWS, Azure, GCP, VMware, Terraform state, vb.) çekerek Ansible’a iletir.
AWS EC2 Dynamic Inventory
AWS kullanıyorsanız amazon.aws collection’ı içindeki aws_ec2 plugin’i hayat kurtarır. Önce gerekli kurulumları yapalım:
# AWS collection kurulumu
ansible-galaxy collection install amazon.aws
# Gerekli Python kütüphanesi
pip3 install boto3 botocore
# AWS kimlik bilgilerini ayarla (ya credentials dosyası ya environment variable)
export AWS_ACCESS_KEY_ID="your_access_key"
export AWS_SECRET_ACCESS_KEY="your_secret_key"
export AWS_DEFAULT_REGION="eu-west-1"
Şimdi AWS EC2 için bir dynamic inventory YAML dosyası oluşturalım:
# inventory/aws_ec2.yml
# Dosya adının _ec2.yml ile bitmesi zorunlu!
plugin: amazon.aws.aws_ec2
regions:
- eu-west-1
- eu-central-1
filters:
instance-state-name: running
tag:Environment:
- production
keyed_groups:
- key: tags.Role
prefix: role
- key: tags.Environment
prefix: env
- key: placement.region
prefix: region
- key: instance_type
prefix: type
hostnames:
- private-ip-address
- dns-name
compose:
ansible_host: private_ip_address
ansible_user: "'ec2-user'"
Bu yapıyla env_production grubuna, role_webserver grubuna veya region_eu_west_1 grubuna göre sunuculara ulaşabilirsiniz. Tagler üzerinden otomatik gruplama harika bir özellik.
Inventory’yi test etmek için:
# Dynamic inventory listesini gör
ansible-inventory -i inventory/aws_ec2.yml --list
# Grafik görünüm
ansible-inventory -i inventory/aws_ec2.yml --graph
# Sadece belirli bir gruba ping at
ansible -i inventory/aws_ec2.yml role_webserver -m ping
Özel Dinamik Inventory Script Yazmak
Bazen hazır plugin’ler işinizi görmez. Kendi CMDB sisteminiz, özel bir kayıt sistemi veya Terraform state dosyasından inventory üretmeniz gerekebilir. Bu durumda Python ile basit bir script yazabilirsiniz.
Şöyle bir senaryo düşünelim: Bir PostgreSQL veritabanında sunucu bilgileri tutuluyor ve buradan dinamik olarak inventory üretmek istiyorsunuz:
#!/usr/bin/env python3
# scripts/dynamic_inventory.py
import json
import sys
import psycopg2
import argparse
def get_inventory():
# Veritabanından sunucu bilgilerini çek
conn = psycopg2.connect(
host="cmdb.example.com",
database="infrastructure",
user="ansible_reader",
password="secret"
)
cursor = conn.cursor()
cursor.execute("""
SELECT hostname, ip_address, role, environment, datacenter
FROM servers
WHERE status = 'active'
""")
servers = cursor.fetchall()
inventory = {
"_meta": {
"hostvars": {}
}
}
for hostname, ip, role, environment, datacenter in servers:
# Gruplara ekle
for group in [role, f"env_{environment}", f"dc_{datacenter}"]:
if group not in inventory:
inventory[group] = {"hosts": [], "vars": {}}
inventory[group]["hosts"].append(hostname)
# Host değişkenlerini ekle
inventory["_meta"]["hostvars"][hostname] = {
"ansible_host": ip,
"server_role": role,
"environment": environment,
"datacenter": datacenter
}
conn.close()
return inventory
def get_host(hostname):
# Belirli bir host için değişkenleri döndür
inventory = get_inventory()
return inventory["_meta"]["hostvars"].get(hostname, {})
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("--list", action="store_true")
parser.add_argument("--host", type=str)
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({}))
Script’i çalıştırılabilir yapın ve test edin:
chmod +x scripts/dynamic_inventory.py
# Test et
./scripts/dynamic_inventory.py --list
./scripts/dynamic_inventory.py --host web01.example.com
# Ansible ile kullan
ansible-playbook -i scripts/dynamic_inventory.py deploy.yml
Statik ve Dinamik Inventory’yi Bir Arada Kullanmak
Gerçek projelerde çoğu zaman her ikisini de kullanmak istersiniz. Ansible buna izin veriyor: Bir dizini inventory olarak belirttiğinizde, o dizindeki tüm geçerli inventory dosyaları ve scriptler birleştirilir.
# Karma inventory dizin yapısı
mkdir -p inventory/
# Statik dosya - network ekipmanları gibi değişmeyen şeyler
cat > inventory/static_hosts.ini << 'EOF'
[network_devices]
switch01.example.com ansible_connection=network_cli
switch02.example.com ansible_connection=network_cli
firewall01.example.com ansible_connection=network_cli
[monitoring]
grafana.example.com
prometheus.example.com
alertmanager.example.com
EOF
# Bu dizinde aws_ec2.yml de bulunuyor
# Ansible her ikisini otomatik birleştirir
# Tüm inventory'yi tek seferde kullan
ansible-playbook -i inventory/ deploy.yml
# Hangi hostların mevcut olduğunu kontrol et
ansible-inventory -i inventory/ --graph
Bu yaklaşımda network cihazlarınız hep statik kalırken, cloud sunucularınız dinamik olarak güncellenir. İkisi bir arada sorunsuz çalışır.
ansible.cfg ile Inventory Ayarları
Her seferinde -i parametresi vermek yerine, proje dizinindeki ansible.cfg dosyasında inventory konumunu belirtebilirsiniz:
# ansible.cfg
[defaults]
inventory = ./inventory
roles_path = ./roles
collections_path = ./collections
remote_user = ansible
private_key_file = ~/.ssh/ansible_key
host_key_checking = False
retry_files_enabled = False
forks = 20
timeout = 30
[inventory]
enable_plugins = host_list, script, auto, yaml, ini, toml, aws_ec2
[ssh_connection]
ssh_args = -o ControlMaster=auto -o ControlPersist=60s
pipelining = True
enable_plugins satırı önemli: Kullanmak istediğiniz inventory plugin’lerini buraya eklemeniz gerekir.
Inventory’yi Doğrulama ve Hata Ayıklama
Yazdığınız inventory’nin doğru çalışıp çalışmadığını kontrol etmek için birkaç pratik yöntem:
# Tüm hostları listele
ansible-inventory -i inventory/ --list
# Grafik görünüm - grupları ve alt grupları göster
ansible-inventory -i inventory/ --graph
# Belirli bir hostin tüm değişkenlerini gör
ansible-inventory -i inventory/ --host web01.example.com
# Belirli bir gruba ping at
ansible -i inventory/ webservers -m ping
# Fact toplama ile bağlantı ve değişkenleri doğrula
ansible -i inventory/ webservers -m setup | grep -i ansible_distribution
# Hangi sunuculara erişilebileceğini kontrol et (gerçekten bağlanmadan)
ansible -i inventory/ all --list-hosts
# Dry run ile playbook öncesi kontrol
ansible-playbook -i inventory/ --list-hosts -l webservers deploy.yml
Gerçek Dünya Senaryosu: E-ticaret Platformu Inventory Yapısı
Bir e-ticaret platformu yönettiğinizi düşünün. Frontend, API, veritabanı, cache, CDN ve monitoring katmanlarından oluşan bir yapı var. Hem on-premise hem de AWS’de sunucularınız mevcut:
# inventories/production/hosts
# On-premise sunucular
[frontend_onprem]
fe01.dc.example.com
fe02.dc.example.com
[api_onprem]
api01.dc.example.com
api02.dc.example.com
api03.dc.example.com
[database_onprem]
db-master.dc.example.com
db-replica01.dc.example.com
db-replica02.dc.example.com
[cache_onprem]
redis01.dc.example.com
redis02.dc.example.com
redis03.dc.example.com
[monitoring_onprem]
grafana.dc.example.com
prometheus.dc.example.com
# Grup hiyerarşisi
[onpremise:children]
frontend_onprem
api_onprem
database_onprem
cache_onprem
monitoring_onprem
[webservers:children]
frontend_onprem
[appservers:children]
api_onprem
[databases:children]
database_onprem
# Tüm ortam
[production:children]
onpremise
[production:vars]
env=production
slack_channel=#prod-alerts
deploy_timeout=300
health_check_retries=5
AWS EC2 kısmı ayrı bir dynamic inventory dosyasında:
# inventories/production/aws_ec2.yml
plugin: amazon.aws.aws_ec2
regions:
- eu-west-1
filters:
instance-state-name: running
tag:Environment: production
tag:Project: ecommerce
keyed_groups:
- key: tags.Tier
prefix: tier
- key: tags.Role
prefix: role
compose:
ansible_host: private_ip_address
ansible_user: "'ec2-user'"
env: "'production'"
Tüm bu yapıyla tek bir komutla tüm production ortamını yönetebilirsiniz.
Inventory Cache: Dinamik Inventory Performansı
Dinamik inventory her çalıştırmada API çağrısı yapar. Büyük AWS hesaplarında bu yavaş olabilir. Cache kullanarak bunu hızlandırabilirsiniz:
# ansible.cfg'e ekleyin
[inventory]
cache = yes
cache_plugin = jsonfile
cache_connection = /tmp/ansible_inventory_cache
cache_timeout = 300
Ya da plugin konfigürasyonunda:
# inventory/aws_ec2.yml
plugin: amazon.aws.aws_ec2
regions:
- eu-west-1
filters:
instance-state-name: running
cache: true
cache_plugin: jsonfile
cache_connection: /tmp/aws_inventory_cache
cache_timeout: 300
Cache’i manuel olarak temizlemek için:
# Cache'i temizle ve yeniden oluştur
ansible-inventory -i inventory/ --list --flush-cache
Sonuç
Inventory yönetimi Ansible’ın kalbi sayılabilir. Doğru kurgulanmış bir inventory yapısı; bakımı kolaylaştırır, hataları azaltır ve ekip içi iletişimi güçlendirir. Şu ilkeleri aklınızda tutun:
- Küçük, değişmeyen altyapı için statik INI veya YAML yeterlidir
- Cloud ortamları ve dinamik ölçekleme için mutlaka dynamic inventory kullanın
- group_vars ve host_vars dizin yapısını tercih edin, değişkenleri inventory dosyasına doldurmayın
- Ortam başına ayrı inventory tutun, production ve staging’i asla aynı dosyaya koymayın
- Statik ve dinamik inventory’yi bir dizinde birleştirerek karma yapılar oluşturabilirsiniz
- Cache kullanımı büyük dynamic inventory senaryolarında performansı ciddi artırır
ansible-inventory --graphve--listkomutlarını sık kullanın, yapınızı düzenli doğrulayın
Bu yazıda anlattığım yapıları kendi altyapınıza uyarlamak için küçük başlayın. Önce basit bir statik inventory yazın, çalıştırın, alışın. Sonra group_vars ekleyin. Cloud kullanıyorsanız dynamic inventory’ye geçin. Adım adım ilerlemek, her şeyi sıfırdan karmaşık yazmaktan çok daha sağlıklı sonuçlar verir.