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.