Ansible Sunucu Konfigürasyon Yönetimi Rehberi

Ansible sunucu konfigürasyon yönetiminde kurulum, inventory, playbook ve vault kullanımını gerçek komut örnekleriyle adım adım anlatan pratik bir rehber.

Linux
Ansible Sunucu Konfigürasyon Yönetimi Rehberi

Elli sunucusu olan bir ortamda tek tek SSH ile bağlanıp paket güncellemek, er ya da geç bir sunucuda bir şeyi unutmanıza yol açar. Ansible bu sorunu ajansız çözer. Sunucularda hiçbir yazılım kurmaz, yalnızca SSH bağlantısı ve YAML dosyalarıyla tanımladığınız durumu tüm makinelere aynı şekilde uygular. Bu rehberde kurulumdan Ansible Vault'a kadar gerçek komutlarla ilerliyor, üretimde karşılaşacağınız tuzakları da ele alıyoruz.

Ansible Nedir ve Neden Agentsız Çalışır

Ansible, Red Hat'e ait açık kaynaklı bir otomasyon aracıdır. Puppet ve Chef gibi rakiplerinden farkı, yönetilen sunucuya herhangi bir ajan yazılımı kurmamasıdır; yalnızca Python ve SSH erişimi yeterlidir. Bu da kurulumu küçük ve orta ölçekli altyapılarda hızlı hale getirir, çünkü kurulum derdi control node adı verilen tek bir makinede kalır.

Control node, playbook'ları çalıştırdığınız makinedir; genelde kendi bilgisayarınız ya da bir CI sunucusudur. Yönetilen sunucular (managed nodes) ise sadece SSH anahtarınızı kabul eder, başka bir kurulum gerektirmez. Bu ayrımı netleştirmek önemlidir, çünkü Ansible'ı Puppet'ın ajan-master modeliyle karıştırmak kurulum aşamasında karışıklığa yol açar.

Ansible'ın modül kütüphanesi geniştir: apt, yum, copy, service, template, user gibi yüzlerce hazır modül gelir. Her modül belirli bir görevi yapar ve idempotent çalışacak şekilde tasarlanmıştır; aynı görevi on kez çalıştırsanız da sonuç değişmez. Resmi dokümantasyon (docs.ansible.com), yeni bir modülün parametrelerini kontrol ederken en güvenilir kaynaktır.

Ansible'ı Puppet ve Chef'ten ayıran bir başka özellik push tabanlı çalışma modelidir. Yönetilen sunucu sürekli bir ajanla merkezi sunucuyu yoklamaz; control node değişiklik göndermek istediğinde SSH üzerinden bağlanır, işini bitirir ve çıkar. Bu model ek bir arka plan servisi, ek bir açık port ya da ek bir güvenlik riski getirmez.

Kurulum ve Control Node Hazırlığı

Ansible'ı control node'a kurmak çoğu dağıtımda tek komutluk bir iştir. Debian ve Ubuntu tabanlı sistemlerde paket yöneticisinden, RHEL tabanlı sistemlerde ise EPEL deposu üzerinden kurulur. Kurulumdan sonra sürüm kontrolü yapmak, hangi Ansible ve Python sürümüyle çalıştığınızı doğrulamanızı sağlar.

Ansible control node ile yönetilen sunucular arasındaki SSH tabanlı agentsız mimariyi gösteren şema
# Debian/Ubuntu
sudo apt update && sudo apt install -y ansible

# RHEL/CentOS/Rocky (EPEL gerekli)
sudo dnf install -y epel-release
sudo dnf install -y ansible

# Kurulum ve sürüm doğrulama
ansible --version

Ansible Galaxy üzerinden topluluk rollerini de kurabilirsiniz; nginx kurulumu, Docker kurulumu veya PostgreSQL yapılandırması gibi yaygın görevler için hazır roller mevcuttur. ansible-galaxy install komutu bu rolleri ~/.ansible/roles dizinine indirir.

ansible-galaxy install geerlingguy.docker
ansible-galaxy install geerlingguy.postgresql

Yönetilen sunuculara SSH anahtarınızı önceden dağıtmanız gerekir; ssh-copy-id komutu bunu tek adımda halleder. Şifre ile SSH bağlantısı da mümkündür, ama anahtar tabanlı erişim hem daha hızlıdır hem de otomasyon sırasında parola istemi sorununu ortadan kaldırır.

Inventory Dosyası Nasıl Yazılır

Inventory, Ansible'ın hangi sunucuları yöneteceğini tanımlayan dosyadır; en basit hâliyle INI formatında yazılır, YAML formatı da desteklenir. Sunucuları gruplara ayırmak, görevleri yalnızca ilgili makinelere yönlendirmenizi sağlar. Aşağıdaki örnek web ve veritabanı sunucularını ayrı gruplarda tutuyor.

[webservers]
web1.example.com
web2.example.com ansible_host=10.0.1.12

[dbservers]
db1.example.com ansible_user=postgres

[webservers:vars]
http_port=80

[all:vars]
ansible_python_interpreter=/usr/bin/python3

Grup içinde grup tanımlamak da mümkündür; örneğin [production:children] altında webservers ve dbservers'ı toplayıp tek bir üst grup oluşturabilirsiniz. Büyük altyapılarda statik INI dosyası yerine dinamik inventory script'leri (AWS EC2 veya Azure gibi bulut sağlayıcılarından sunucu listesini otomatik çeken) tercih edilir. Inventory'nin doğruluğu tüm otomasyonun temelini oluşturur; yanlış gruba giden bir playbook, yanlış sunucuda servis yeniden başlatabilir.

Inventory dosyasını doğrulamak için ad-hoc komutlar kullanılır; tam bir playbook yazmadan tek bir modülü çalıştırmak istediğinizde bu yöntem işinizi görür.

# Tüm webservers grubuna ping at
ansible webservers -i inventory.ini -m ping

# dbservers grubunda disk kullanımını göster
ansible dbservers -i inventory.ini -a "df -h"

Playbook ve YAML Syntax'ı

Playbook, bir veya daha fazla "play" içeren YAML dosyasıdır; her play, belirli bir sunucu grubunda hangi görevlerin sırayla çalışacağını tanımlar. YAML girinti konusunda katıdır, tab karakteri yerine boşluk kullanmak zorunludur; aksi hâlde yaml.scanner.ScannerError hatasıyla karşılaşırsınız. Aşağıdaki örnek bir web sunucusuna nginx kurup servisi başlatıyor.

Bir Ansible playbook YAML dosyasının kod editöründe görüntülendiği stilize pencere
---
- name: Web sunucularini yapilandir
  hosts: webservers
  become: true
  vars:
    http_port: 80
  tasks:
    - name: Nginx paketini kur
      apt:
        name: nginx
        state: present
        update_cache: true

    - name: Konfigurasyon dosyasini kopyala
      copy:
        src: files/nginx.conf
        dest: /etc/nginx/nginx.conf
        owner: root
        mode: '0644'
      notify: nginx yeniden baslat

    - name: Nginx servisinin calistigini garanti et
      service:
        name: nginx
        state: started
        enabled: true

  handlers:
    - name: nginx yeniden baslat
      service:
        name: nginx
        state: restarted

RHEL tabanlı sunucularda apt yerine yum ya da dnf modülünü kullanmanız gerekir; paket adları da dağıtıma göre değişebilir. notify ve handlers çifti önemli bir detaydır: konfigürasyon dosyası değişmediyse servis yeniden başlamaz, yalnızca gerçek bir değişiklik olduğunda handler tetiklenir. Bu davranış, idempotency'nin pratikte nasıl işlediğini gösteren en net örnektir.

Playbook'u çalıştırmadan önce kuru çalıştırma (dry run) yapın; --check bayrağı hiçbir değişiklik uygulamadan neyin değişeceğini gösterir, --diff bayrağı ise dosya farklarını gösterir.

ansible-playbook -i inventory.ini playbook.yml --check --diff

# Sorun yoksa gercek calistirma
ansible-playbook -i inventory.ini playbook.yml

Ad-hoc komut ile playbook arasındaki fark çoğu yeni kullanıcının kafasını karıştırır. Aşağıdaki tablo ikisini ne zaman tercih etmeniz gerektiğini özetliyor.

ÖzellikAd-hoc komutPlaybook
Kullanım amacıTek seferlik, hızlı kontrolTekrarlanabilir, kalıcı yapılandırma
Sürüm kontrolüYok, komut geçmişte kaybolurGit ile takip edilebilir
KarmaşıklıkTek modül, tek görevÇoklu görev, koşullar, handler'lar
Örnek senaryo"Şu an disk doluluğunu göster""Web sunucusu kurulumunu standardize et"

Roller ile Organizasyon

Tek bir playbook dosyasına yüzlerce görev sıkıştırmak, altı ay sonra o dosyaya bakan herkes için anlaşılması zor hâle gelir. Roller, ilgili görevleri, değişkenleri, şablonları ve dosyaları standart bir dizin yapısında bir araya toplar. ansible-galaxy init komutu bu iskeleti otomatik oluşturur.

Terminalde ansible-vault encrypt_string komutunun çalıştırıldığı stilize görünüm
ansible-galaxy init roles/nginx

Oluşan yapı şu klasörleri içerir:

  • tasks/main.yml - rolün asıl görevleri
  • handlers/main.yml - servis yeniden başlatma gibi tetiklenen eylemler
  • templates/ - Jinja2 şablonları (örneğin nginx.conf.j2)
  • defaults/main.yml - varsayılan değişken değerleri
  • vars/main.yml - override edilmemesi gereken sabit değişkenler

Bir playbook içinde rolü çağırmak tek satırdır, roles: [nginx, postgresql] gibi bir liste yeterlidir. Büyük altyapılarda rolleri ayrı bir Git deposunda tutup requirements.yml üzerinden ansible-galaxy install -r requirements.yml ile çekmek, ekipler arası paylaşımı kolaylaştırır. Ansible Galaxy'deki topluluk rollerini kullanmadan önce kaynak kodunu gözden geçirin; üretim sunucusunda çalışacak kod budur.

Rol bağımlılıklarını yönetmek için meta/main.yml dosyasına dikkat etmek gerekir; bir rol başka bir role bağımlıysa bunu burada tanımlarsınız, Ansible bağımlı rolü otomatik olarak önce çalıştırır. Değişken önceliği konusunda da dikkatli olun: defaults/main.yml en düşük önceliğe sahiptir ve inventory'deki bir değişken bunun üzerine kolayca yazar. Bu önceliği bilmemek, tanımladığınız değerin neden çalışmadığını uzun süre araştırmanıza yol açar.

Ansible Vault ile Gizli Bilgi Yönetimi

Veritabanı şifrelerini ve API anahtarlarını playbook içine düz metin yazıp Git'e göndermek yaygın bir güvenlik hatasıdır. Ansible Vault bu değerleri AES256 ile şifreleyip dosya içinde saklar; şifrelenmiş dosya Git'e güvenle commit edilebilir. ansible-vault encrypt_string komutu tek bir değişkeni şifreler, tüm dosyayı şifrelemenize gerek kalmaz.

# Tek bir degiskeni sifrele
ansible-vault encrypt_string 'GizliSifre123' --name 'db_password'

# Tum bir dosyayi sifrele
ansible-vault encrypt group_vars/production/secrets.yml

# Playbook calistirirken vault sifresini sor
ansible-playbook -i inventory.ini playbook.yml --ask-vault-pass

# Sifreyi bir dosyadan oku (CI/CD icin)
ansible-playbook -i inventory.ini playbook.yml --vault-password-file ~/.vault_pass.txt

Vault şifresini kod deposuna asla eklemeyin; --vault-password-file kullanıyorsanız o dosyayı .gitignore'a ekleyin ve dosya izinlerini 600 yapın. CI/CD ortamlarında bu şifre genelde bir secrets manager'dan (GitHub Actions secrets, GitLab CI variables gibi) çekilip geçici bir dosyaya yazılır. Vault kullanımına dair resmi rehber (docs.ansible.com/ansible/latest/vault_guide/index.html) şifre rotasyonu ve çoklu vault ID senaryolarını da kapsıyor.

Idempotency ve Gerçek Dünya Tuzakları

Idempotency teoride basit görünür ama pratikte shell veya command modülüyle sık sık bozulur. Bu iki modül idempotent değildir; dosya zaten var olsa bile her çalıştırmada komutu yeniden çalıştırır. Mümkün olduğunca copy, template, file, apt, service gibi durum tabanlı (state-based) modülleri tercih edin; shell yalnızca gerçekten başka bir seçenek kalmadığında kullanılmalıdır.

Bir diğer yaygın tuzak, shell kullanmak zorunda kaldığınızda creates veya changed_when parametrelerini atlamaktır. Bu parametreler olmadan Ansible her çalıştırmada görevi "changed" olarak işaretler; playbook'u tekrar çalıştırdığınızda gerçekte hiçbir şey değişmediği hâlde loglar kirlenir. Bir kurulum script'ini shell ile çalıştırıyorsanız creates: /opt/app/.installed eklemek, script zaten çalıştıysa görevi atlamasını sağlar.

Ansible'ı Puppet, Chef veya SaltStack ile karşılaştıranlar genelde hangisinin daha hızlı öğrenildiğini sorar. Aşağıdaki tablo genel eğilimi gösteriyor; kesin performans rakamları ortamdan ortama değişir.

AraçMimariÖğrenme eğrisiDil
AnsibleAgentsız, SSH tabanlıDüşük-ortaYAML
PuppetAjan-master modeliOrta-yüksekPuppet DSL
ChefAjan-master modeliYüksekRuby DSL
SaltStackAgentsız veya ajanlı (opsiyonel)OrtaYAML

Son bir uyarı: become: true ile root yetkisi alan görevleri test ortamında --check modunda çalıştırmadan üretime almayın. Bazı modüller check modunda gerçek durumu tam simüle edemez; özel shell komutları içeren görevlerde check modu "değişiklik yok" derken gerçek çalıştırmada beklenmedik bir şey kırılabilir. Küçük bir test sunucusunda gerçek çalıştırmayı doğrulamak, üretimde sürpriz yememenin en güvenilir yoludur.

Celil Uyanikoglu

Yazan Celil Uyanikoglu

25 yıldır bilgi işlem piyasasında farklı dallarda uzmanlaşan bir Bilgisayar Mühendisi

Yorum

Henüz yorum yok.

Sohbete katıl. Yorumlar yayınlanmadan önce moderasyondan geçer.

Yorum yap

E-posta adresin yayınlanmaz. Yorumlar moderasyondan sonra yayınlanır.

Sırada

İlgili notlar