Ansible Nedir: Otomasyon Aracına Giriş ve Kurulum

Bir sunucuya bir şey kurmak için SSH bağlanıp komut çalıştırmak, iki sunucu için belki mantıklı görünür. Beş sunucu için biraz zahmetli ama idare edilir. Peki ya elli sunucu? Ya da her hafta yeniden yapılandırmanız gereken bir altyapı varsa? İşte tam bu noktada Ansible gibi araçlar hayat kurtarıcı olmaya başlıyor.

Ansible, Red Hat tarafından geliştirilen açık kaynaklı bir IT otomasyon aracıdır. Sunucu yapılandırması, uygulama dağıtımı, görev otomasyonu ve çok daha fazlası için kullanılır. Ama onu rakiplerinden ayıran birkaç temel özellik var: ajanssız çalışır, öğrenmesi kolaydır ve YAML tabanlı bir sözdizimi kullanır. Chef veya Puppet gibi araçların aksine, yönetmek istediğiniz sunuculara herhangi bir yazılım kurmanıza gerek yoktur. Sadece SSH bağlantısı ve Python yeterlidir.

Bu yazıda Ansible’ın ne olduğunu, nasıl çalıştığını, temel kavramlarını ve gerçek bir ortamda nasıl kurulup kullanılacağını ele alacağız.

Ansible Neden Var?

Sysadmin dünyasında “snowflake server” denen bir problem vardır. Her sunucu zamanla elle yapılan müdahaleler, acil yamalar, “bir bakayım” denen ama geri alınmayan değişiklikler yüzünden birbirinden farklılaşır. Altı ay sonra “bu sunucu neden farklı davranıyor?” sorusunu sormak kaçınılmaz hale gelir.

Ansible bu problemi Infrastructure as Code (Kod Olarak Altyapı) yaklaşımıyla çözer. Yapılandırmalarınızı kod olarak yazarsınız, bu kodu versiyon kontrolüne alırsınız ve her sunucuya aynı kodu uygularsınız. Böylece:

  • Sunucular arasında tutarsızlık ortadan kalkar
  • Değişiklikler izlenebilir ve geri alınabilir hale gelir
  • Yeni bir sunucu kurmak, mevcut playbook’u çalıştırmak kadar kolay olur
  • Ekipteki herkes neyin nasıl yapılandırıldığını görebilir

Ansible’ın Temel Mimarisi

Ansible’ın nasıl çalıştığını anlamak için birkaç temel kavramı bilmek gerekiyor.

Control Node ve Managed Nodes

Control Node, Ansible’ın kurulu olduğu ve komutların çalıştırıldığı makinedir. Kendi laptopunuz veya bir jump server olabilir. Windows üzerinde doğrudan çalışmaz, ama WSL2 üzerinden kullanılabilir.

Managed Nodes, yönetmek istediğiniz hedef sunuculardır. Bunlara herhangi bir Ansible yazılımı kurmanıza gerek yoktur. Sadece SSH erişimi ve Python 2.7+ veya Python 3.5+ yeterlidir. Modern Linux dağıtımlarının neredeyse hepsinde Python zaten kurulu gelir.

Inventory

Inventory, Ansible’ın hangi sunucuları yöneteceğini tanımladığı dosyadır. En basit haliyle bir metin dosyasıdır.

# /etc/ansible/hosts veya özel bir inventory dosyası
[webservers]
web01.example.com
web02.example.com
192.168.1.101

[dbservers]
db01.example.com
db02.example.com

[production:children]
webservers
dbservers

Modules

Ansible’ın işini yapan birimlerdir. Her modül belirli bir görevi gerçekleştirir: paket kurmak, dosya kopyalamak, servis başlatmak, kullanıcı oluşturmak gibi. Ansible’ın 3000’den fazla yerleşik modülü vardır ve gerektiğinde kendi modüllerinizi yazabilirsiniz.

Playbooks

Playbook’lar, Ansible’ın kalbidir. YAML formatında yazılan bu dosyalar, hangi sunucularda hangi görevlerin nasıl çalıştırılacağını tanımlar. “Bu sunuculara Nginx kur, bu konfigürasyon dosyasını yerleştir, servisi başlat” gibi adım adım talimatları içerir.

Roles

Roller, playbook’ları organize etmenin standart yoludur. Büyük playbook’ları daha küçük, yeniden kullanılabilir parçalara ayırır. Bir “webserver” rolü, web sunucusu kurmak için gereken her şeyi (görevler, şablonlar, değişkenler, handler’lar) tek bir yapı altında toplar.

Kurulum

Control Node Üzerinde Ansible Kurulumu

Ansible’ı control node’a kurmak oldukça basittir. Birkaç farklı yöntem var:

Ubuntu/Debian üzerinde:

sudo apt update
sudo apt install software-properties-common
sudo add-apt-repository --yes --update ppa:ansible/ansible
sudo apt install ansible -y

# Versiyon kontrolü
ansible --version

RHEL/CentOS/Rocky Linux üzerinde:

sudo dnf install epel-release -y
sudo dnf install ansible -y

# Alternatif olarak pip ile:
pip3 install ansible

pip ile (tüm sistemlerde, en güncel versiyon için önerilen):

python3 -m pip install --user ansible

# Upgrade için:
python3 -m pip install --upgrade --user ansible

ansible --version

SSH Key Tabanlı Kimlik Doğrulama Kurulumu

Ansible şifre sormadan çalışabilmek için SSH key kullanmalıdır. Eğer henüz yoksa:

# SSH key çifti oluştur
ssh-keygen -t ed25519 -C "ansible-control"

# Public key'i managed node'lara kopyala
ssh-copy-id -i ~/.ssh/id_ed25519.pub [email protected]
ssh-copy-id -i ~/.ssh/id_ed25519.pub [email protected]

# Bağlantıyı test et
ssh [email protected]

Ansible Konfigürasyon Dosyası

Ansible’ın davranışını ansible.cfg dosyasıyla özelleştirebilirsiniz. Ansible bu dosyayı sırasıyla şu yerlerde arar: mevcut dizin, kullanıcının home dizini, /etc/ansible/ansible.cfg.

# ansible.cfg örneği
[defaults]
inventory = ./inventory
remote_user = deploy
private_key_file = ~/.ssh/id_ed25519
host_key_checking = False
retry_files_enabled = False
stdout_callback = yaml

[privilege_escalation]
become = True
become_method = sudo
become_user = root

host_key_checking = False ayarı üretim ortamında dikkatli kullanılmalıdır. Test ortamı için pratik olsa da, production’da SSH fingerprint doğrulamasını devre dışı bırakmak güvenlik riski yaratabilir.

İlk Adımlar: Ad Hoc Komutlar

Playbook yazmadan önce Ansible’ı ad hoc komutlarla test etmek hem öğretici hem de pratiktir. Ad hoc komutlar, tek satırda çalıştırılan Ansible komutlarıdır.

# Tüm sunuculara ping at (Ansible ping modülü, ICMP değil)
ansible all -m ping

# Belirli bir gruba ping at
ansible webservers -m ping

# Tüm sunucularda uptime kontrol et
ansible all -m command -a "uptime"

# Disk kullanımını kontrol et
ansible webservers -m shell -a "df -h"

# Bir paketi kur
ansible webservers -m apt -a "name=nginx state=present" --become

# Servisi yeniden başlat
ansible webservers -m service -a "name=nginx state=restarted" --become

# Belirli bir dosyayı kopyala
ansible webservers -m copy -a "src=/tmp/test.conf dest=/etc/nginx/conf.d/test.conf" --become

Başarılı bir ping çıktısı şöyle görünür:

web01.example.com | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python3"
    },
    "changed": false,
    "ping": "pong"
}

İlk Playbook’unuzu Yazma

Şimdi gerçek bir senaryo üzerinden gidelim: Birkaç web sunucusuna Nginx kurmak, bir konfigürasyon dosyası yerleştirmek ve servisi başlatmak istiyoruz.

Önce proje yapısını oluşturalım:

mkdir -p ansible-proje/{inventory,playbooks,templates}
cd ansible-proje

# Inventory dosyası
cat > inventory/hosts << 'EOF'
[webservers]
web01 ansible_host=192.168.1.10
web02 ansible_host=192.168.1.11

[dbservers]
db01 ansible_host=192.168.1.20

[all:vars]
ansible_user=deploy
ansible_ssh_private_key_file=~/.ssh/id_ed25519
EOF

Şimdi playbook’u yazalım:

# playbooks/nginx-setup.yml
---
- name: Web sunucularına Nginx kurulumu
  hosts: webservers
  become: true
  vars:
    nginx_port: 80
    server_name: "example.com"
    nginx_worker_processes: 2

  tasks:
    - name: Sistem paketlerini güncelle
      apt:
        update_cache: yes
        cache_valid_time: 3600

    - name: Nginx'i kur
      apt:
        name: nginx
        state: present

    - name: Nginx konfigürasyonunu yerleştir
      template:
        src: ../templates/nginx.conf.j2
        dest: /etc/nginx/nginx.conf
        owner: root
        group: root
        mode: '0644'
      notify: nginx'i yeniden başlat

    - name: Nginx servisinin aktif ve çalışır olduğunu doğrula
      service:
        name: nginx
        state: started
        enabled: yes

    - name: 80 portunu firewall'da aç
      ufw:
        rule: allow
        port: "{{ nginx_port }}"
        proto: tcp

  handlers:
    - name: nginx'i yeniden başlat
      service:
        name: nginx
        state: restarted

Bu playbook’ta dikkat edilmesi gereken birkaç nokta var. Handlers, sadece ilgili task “changed” durumuna geçtiğinde çalışır. Yani nginx.conf değişmediyse servis gereksiz yere yeniden başlatılmaz. Bu idempotency kavramının güzel bir örneğidir: aynı playbook’u kaç kez çalıştırırsanız çalıştırın, sonuç her zaman aynı olur ve gereksiz değişiklik yapılmaz.

Jinja2 Template Kullanımı

Ansible, konfigürasyon dosyaları için Jinja2 şablonlama motorunu kullanır. Bu sayede dinamik konfigürasyon dosyaları oluşturabilirsiniz:

# templates/nginx.conf.j2
user www-data;
worker_processes {{ nginx_worker_processes }};
pid /run/nginx.pid;

events {
    worker_connections 1024;
}

http {
    server {
        listen {{ nginx_port }};
        server_name {{ server_name }};

        location / {
            root /var/www/html;
            index index.html;
        }

        # Ansible tarafından yönetilen sunucu: {{ inventory_hostname }}
        # Son güncelleme: {{ ansible_date_time.date }}
    }
}

Playbook’u çalıştırmak için:

# Dry run (gerçekte hiçbir şey yapmaz, ne yapacağını gösterir)
ansible-playbook playbooks/nginx-setup.yml --check

# Gerçek çalıştırma
ansible-playbook playbooks/nginx-setup.yml

# Belirli bir tag ile çalıştır
ansible-playbook playbooks/nginx-setup.yml --tags "install"

# Verbose mod
ansible-playbook playbooks/nginx-setup.yml -v

Variables ve Ansible Facts

Ansible’da değişkenler birçok yerden gelebilir ve bir öncelik sırası vardır. En yaygın kullanılan yerler:

inventory’de tanımlı değişkenler:

# inventory/group_vars/webservers.yml
---
nginx_port: 80
max_connections: 1000
app_environment: production
# inventory/host_vars/web01.yml
---
nginx_port: 8080  # Bu host için farklı port

Ansible Facts, Ansible’ın managed node’lardan otomatik olarak topladığı sistem bilgileridir. RAM miktarı, işlemci sayısı, işletim sistemi versiyonu, IP adresleri gibi bilgilere bu şekilde ulaşabilirsiniz:

# Bir host'un tüm fact'lerini gör
ansible web01 -m setup

# Belirli bir fact filtrele
ansible web01 -m setup -a "filter=ansible_distribution*"

Bu fact’leri playbook’larda kullanabilirsiniz:

- name: OS'a göre paket yöneticisi seç
  apt:
    name: nginx
    state: present
  when: ansible_distribution == "Ubuntu"

- name: RAM bilgisini göster
  debug:
    msg: "Bu sunucuda {{ ansible_memtotal_mb }} MB RAM var"

Roles ile Yapıyı Organize Etme

Gerçek dünyada tek bir büyük playbook yazmak yerine, her şeyi roller halinde organize edersiniz. Bir rol şu dizin yapısını takip eder:

# Role yapısı oluştur
ansible-galaxy init roles/webserver

# Oluşturulan yapı:
roles/webserver/
├── defaults/
│   └── main.yml      # Varsayılan değişkenler (en düşük öncelik)
├── files/
│   └── index.html    # Statik dosyalar
├── handlers/
│   └── main.yml      # Handler'lar
├── tasks/
│   └── main.yml      # Ana görevler
├── templates/
│   └── nginx.conf.j2 # Jinja2 şablonları
├── vars/
│   └── main.yml      # Değişkenler (yüksek öncelik)
└── meta/
    └── main.yml      # Rol metadata ve bağımlılıklar

Rolü kullanan basit bir playbook:

# site.yml
---
- name: Web sunucuları yapılandırması
  hosts: webservers
  become: true
  roles:
    - webserver
    - monitoring
    - security-hardening

- name: Veritabanı sunucuları yapılandırması
  hosts: dbservers
  become: true
  roles:
    - postgresql
    - backup

Bu yapı sayesinde “webserver” rolünü farklı projelerde tekrar kullanabilir, Ansible Galaxy’den hazır roller indirebilir veya kendi rol kütüphanenizi oluşturabilirsiniz.

Gerçek Dünya Senaryosu: Uygulama Güncelleme Playbook’u

Şimdi gerçekten işe yarayan bir senaryo düşünelim: Staging ve production ortamlarında çalışan bir web uygulamasını güncellemek istiyorsunuz. Manuel yapıldığında her seferinde şunları yapmanız gerekiyor: uygulamayı durdurmak, kodu güncellemek, bağımlılıkları kurmak, veritabanı migration’larını çalıştırmak, uygulamayı yeniden başlatmak.

# playbooks/deploy-app.yml
---
- name: Web uygulaması deployment
  hosts: "{{ target_env | default('staging') }}"
  become: true
  vars:
    app_dir: /var/www/myapp
    app_user: www-data
    git_repo: "https://github.com/sirket/myapp.git"
    git_branch: "{{ branch | default('main') }}"

  tasks:
    - name: Uygulamayı maintenance moduna al
      file:
        path: "{{ app_dir }}/maintenance.flag"
        state: touch
        owner: "{{ app_user }}"

    - name: Mevcut kodu yedekle
      archive:
        path: "{{ app_dir }}"
        dest: "/tmp/myapp-backup-{{ ansible_date_time.date }}.tar.gz"

    - name: Güncel kodu çek
      git:
        repo: "{{ git_repo }}"
        dest: "{{ app_dir }}"
        version: "{{ git_branch }}"
        force: yes
      notify: Uygulamayı yeniden başlat

    - name: Python bağımlılıklarını güncelle
      pip:
        requirements: "{{ app_dir }}/requirements.txt"
        virtualenv: "{{ app_dir }}/venv"

    - name: Veritabanı migration'larını çalıştır
      command: "{{ app_dir }}/venv/bin/python manage.py migrate --noinput"
      args:
        chdir: "{{ app_dir }}"
      become_user: "{{ app_user }}"

    - name: Static dosyaları topla
      command: "{{ app_dir }}/venv/bin/python manage.py collectstatic --noinput"
      args:
        chdir: "{{ app_dir }}"
      become_user: "{{ app_user }}"

    - name: Maintenance modunu kapat
      file:
        path: "{{ app_dir }}/maintenance.flag"
        state: absent

  handlers:
    - name: Uygulamayı yeniden başlat
      service:
        name: gunicorn
        state: restarted

Bu playbook’u şöyle çalıştırırsınız:

# Staging ortamına deploy
ansible-playbook playbooks/deploy-app.yml -e "target_env=staging"

# Production'a belirli bir branch ile deploy
ansible-playbook playbooks/deploy-app.yml -e "target_env=production branch=v2.1.0"

# Sadece migration'ları çalıştır
ansible-playbook playbooks/deploy-app.yml --tags "migration" -e "target_env=staging"

Ansible Vault: Hassas Bilgileri Koruma

Playbook’larda şifre, API anahtarı gibi hassas bilgileri açık metin olarak saklamak büyük bir güvenlik sorunudur. Ansible Vault bu problemi çözer:

# Yeni şifreli dosya oluştur
ansible-vault create secrets.yml

# Mevcut dosyayı şifrele
ansible-vault encrypt group_vars/production/vault.yml

# Şifreli dosyayı düzenle
ansible-vault edit secrets.yml

# Şifreli dosyanın içeriğini görüntüle
ansible-vault view secrets.yml

# Playbook'u vault şifresiyle çalıştır
ansible-playbook site.yml --ask-vault-pass

# Şifre dosyası ile çalıştır (CI/CD için)
ansible-playbook site.yml --vault-password-file ~/.vault_pass

Şifreli değişken dosyası içeriği tipik olarak şöyle görünür:

# group_vars/production/vault.yml (şifreli)
---
vault_db_password: "super-secret-password-123"
vault_api_key: "sk-abcdef1234567890"
vault_smtp_password: "mail-secret-pass"

Yaygın Hatalar ve Çözümleri

Ansible kullanmaya başladığınızda karşılaşacağınız bazı tipik sorunlar var:

“UNREACHABLE” hatası: SSH bağlantısı kurulamıyor demektir. SSH key’in doğru yerde olduğunu, kullanıcı adının doğru olduğunu ve hedef sunucunun erişilebilir olduğunu kontrol edin.

# Debug için verbose mod
ansible web01 -m ping -vvv

“sudo: a password is required” hatası: Sudoers yapılandırması eksik. Hedef sunucuda deploy kullanıcısına passwordless sudo yetkisi verin:

# Hedef sunucuda:
echo "deploy ALL=(ALL) NOPASSWD:ALL" | sudo tee /etc/sudoers.d/deploy

Idempotency sorunları: command ve shell modülleri her çalıştırmada “changed” döndürür çünkü Ansible değişiklik olup olmadığını anlayamaz. Bu modülleri kullanırken changed_when ve creates parametrelerini kullanın:

- name: Veritabanını ilklendir
  command: /opt/app/init-db.sh
  args:
    creates: /var/lib/myapp/.db_initialized
  changed_when: false

Sonuç

Ansible, sysadmin araç setinizde olması gereken bir araçtır. Başlangıçta birkaç sunucuyu yönetirken “buna gerek yok” gibi görünebilir ama altyapı büyüdükçe elde ettiğiniz kazanımlar katlanarak artar.

Bu yazıda temel kavramları, kurulumu, ad hoc komutları, playbook yazmayı, variables ve facts kullanımını, roller ile organizasyonu, gerçek bir deployment senaryosunu ve Ansible Vault’u ele aldık. Bunlar Ansible’ın temelini oluşturuyor.

Buradan sonraki adımlar için şunları öneririm: Önce kendi test ortamınızda (Vagrant veya birkaç VPS yeterli) basit playbook’lar yazın. Mevcut kurulum prosedürlerinizi playbook’lara dönüştürün ve Git’e alın. Sonra Ansible Galaxy’yi keşfedin: ansible-galaxy install geerlingguy.nginx gibi hazır, test edilmiş rolleri kullanmak işi hızlandırır. Daha ileri gitmek isteyenler için dynamic inventory, Ansible Tower/AWX, ve callback plugin’leri incelemeye değer konular.

En önemli şey: mükemmel bir yapı kurmaya çalışarak başlamayı ertelemek yerine, bugün elinizin altındaki en tekrarlayan görevi Ansible ile otomatize etmeye başlamak. Geri kalanı gelir.

Yorum yapın