24 Eylül 2025 Çarşamba

Ansible 101 - Uygulamalı Başlangıç Rehberi

    Bir master, üç tane de worker olmak üzere 4 ubuntu'dan oluşan basit bir lab kurdum. Master ubuntu makineme ansible yükledim ve ssh public keyleri worker makinelerime kopyaladım. Böylelikle ansible workerlar ile şifresiz doğrudan iletişim kurabilecek. 


SSH key oluşturduğum komut:
ssh-keygen -t rsa -b 4096

Anahtarı worker'lara kopyaladım:
cat ~/.ssh/id_rsa.pub | ssh [email protected] "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys"

Multipass tarafı için aşağıdaki adımları uygulamadım: worker'de aşağıdaki kodlar çalıştırılır ve ubuntu user ile master makinede oluşturulan key içeriği manuel eklenir:

ssh key cat

worker ssh key ekleme


Lab için Ansible dizini oluşturdum:
mkdir -p ~/ansible-lab && cd ~/ansible-lab

İlk denemeler için bir envanter dosyası oluşturdum:
vi hosts

Bu dosyanın içeriğini worker'larıma göre doldurdum:
[web]
192.168.1.110

[db]
192.168.1.111

[prod]
192.168.1.112

[all:vars]
ansible_user=ubuntu
ansible_ssh_private_key_file=~/.ssh/id_rsa

İlk ansible komutumu denedim:
ansible all -i hosts -m ping

Bu komut, hosts envanter dosyasında tanımlı tüm sunuculara SSH ile bağlanır ve Ansible’ın ping modülünü çalıştırarak bağlantıyı test eder. Başarılıysa her sunucudan "pong" cevabı döner.

Ansible Ping


Bu komutu bir .sh dosyasına yazıyorum ve sh dosyasını çalıştırarak daha hızlı bir şekilde yanıt almak istiyorum:
vi pingle.sh

Dosya içeriği:
#!/bin/bash
ansible all -i hosts -m ping

Dosyaya çalıştırma izni: 
chmod +x pingle.sh

Test:
./pingle.sh

Worker'larda sudo yetkisi gerektiren komutları çalıştırmak istediğimde ya şifre sormasını sağlamamız gerekiyor yada şifresiz sudo yetkisini her bir workerda tanımlamak gerekiyor. (test ortamı için çok uygun) Örnek üzerinden bakalım. Tüm worker'larıma htop paketini yüklemek istiyorum, şifre sormasını istiyorsam bu komuttan yararlanabilirim:
ansible all -i hosts -m apt -a "name=htop state=present" --become --ask-become-pass

Ancak şifre sormadan doğrudan komutu koşmak için bir kerelik sudo şifresiz yetkisini workerlara tek tek tanımlamam gerekiyor.
echo "ubuntu ALL=(ALL) NOPASSWD:ALL" | sudo tee /etc/sudoers.d/ubuntu
sudo chmod 440 /etc/sudoers.d/ubuntu

Böylece şimdi koşacağım komutu şifre yazmadan veya girmeden doğrudan worker'larıma gönderebilirim:
ansible all -i hosts -m apt -a "name=htop state=present" --become

Ve aynı anda tüm makinelerime htop kurulumunu yapabildim:

htop

Bunu paket kurulumu adı altında bir .sh dosyasına da dönüştürebiliriz:


package_install.sh dosyası oluşturdum ve içeriğini bu şekilde doldurdum:
#!/bin/bash

# Kurulacak paketin adı (örnek: htop, curl, nginx, vs)
PAKET_ADI="htop"

# Ansible komutu
ansible all -i hosts -m apt -a "name=$PAKET_ADI state=present" --become

Böylece kurmak istediğim farklı paketler olduğunda içerisine girip paket adını güncellemem yeterli olabilir.

Dosyaya çalıştırma izni vermeyi de unutmuyoruz:
chmod +x paket_kur.sh

Şimdi ise ilk Playbook'umuzu deneyelim, birden fazla paket kurulumunu bir yml dosyası ile host'larımıza gönderelim.


vi package_install.yml dosyasını oluşturdum ve aşağıdaki bilgileri ekledim:

---
- name: Paket kurulumları
  hosts: all
  become: yes

  tasks:
    - name: htop kur
      apt:
        name: htop
        state: present

    - name: curl kur
      apt:
        name: curl
        state: present

    - name: git kur
      apt:
        name: git
        state: present

Ardından playbook dosyamı koşmak için bu komutu kullanıyorum:
ansible-playbook -i hosts package_install.yml

Playbook - Package Installation

    Ve böylece tek bir yml dosyasını çalıştırarak ansible sayesinde tüm hosts makinelerime aynı anda birden fazla uygulama kurulumunu gerçekleştirmiş oldum. Makinelere tek tek bağlanmadım, paketleri tek tek kurmayı denemedim ve zaman kaybı yaşamadım.


Tüm makineleri kapatmak için bir .sh dosyası
#!/bin/bash

# Ansible inventory dosyasını belirt
INVENTORY_FILE="hosts"

# Tüm makineleri anında kapat
ansible all -i "$INVENTORY_FILE" -a "/sbin/shutdown now" --become

chmod +x shutdown-all.sh

Tüm makinelerde bir klasör oluşturmak için: create_folder.sh
#!/bin/bash

# Ansible inventory dosyası
INVENTORY_FILE="hosts"

# Uzak makinelerde klasör oluştur
ansible all -i "$INVENTORY_FILE" -m file -a "path=/tmp/yeni_klasor state=directory mode=0755"
chmod +x create_folder.sh

Bir istisna, tüm hostlara değil, özel bir gruba işlem yapmak için ek bir parametre kullanılır:
ansible-playbook -i hosts package_install.yml --limit web

Command modülü ile uptime bilgisini öğrenme:
ansible all -i hosts -m command -a "uptime"

Copy komutu ile dosyaları hostlara kopyalamak:
ansible all -i hosts -m copy -a "src=dosya.txt dest=/tmp/dosya.txt"

uptime

Şimdi ise bir playbook ile hem paket kurulumu hem de bir dosya oluşturarak içerisine veri yazmayı deneyelim:


Playbook 2

- name: Paket kur ve dosya kopyala
  hosts: all
  become: yes
  tasks:
    - name: htop paketini kur
      apt:
        name: htop
        state: present

    - name: Bilgi dosyasını kopyala
      copy:
        content: "Bu dosya Ansible tarafından oluşturulmuştur\n"
        dest: /tmp/ansible_bilgi.txt
        owner: ubuntu
        group: ubuntu
        mode: '0644'

Sırada bir servis kurmak ve o servisin çalışıp çalışmadığını check etmek var:


apache_setup.yml dosyasını oluşturuyorum ve içeriğini aşağıdaki gibi yapıyorum:

- name: Apache kurulumu ve servisi yönetimi
  hosts: all
  become: yes
  tasks:
    - name: Apache2 paketini kur
      apt:
        name: apache2
        state: present
        update_cache: yes

    - name: Apache servisini başlat
      service:
        name: apache2
        state: started
        enabled: yes

Bu servisi sadece web hostlarıma kurmak istedim, o yüzden bu şekilde bir komut koşuyorum:
ansible-playbook -i hosts apache_setup.yml --limit web

Ve servislerin durumunu check etmek istiyorum:

apache2 ansible service check


When kullanarak bir yml dosyasının içerisine koşul ekleyebiliriz. Ancak bunu zaten --limit komutu ile de yapabilyoruz:


- name: Koşullu görev örneği
  hosts: all
  become: yes
  tasks:
    - name: Sadece worker1'de bu dosyayı oluştur
      copy:
        content: "Bu dosya sadece worker1 içindir\n"
        dest: /tmp/worker1_ozel.txt
      when: inventory_hostname == "worker1"

Gruplamayı yml dosyasının içerisinde de yapabiriz, böylelikle when koşulu veya --limit kullanmadan birden fazla görevi aslında yml dosyasında tek tek host gruplarına atamak mümkün:


Yeni bir yml dosyası oluşturdum: group_specific_tasks.yml 
Bu yml dosyası sadece web ve db makinelerime işlem yapacak ve bu işlem örnekteki gibi bir file oluşturma işlemi olacağı gibi, app kurulumu, güncellemesi vs. gibi herhangi bir işlem olabilir:

- name: Web grubuna özel görev
  hosts: web
  become: yes
  tasks:
    - name: Web makinesine özel bilgi dosyası
      copy:
        content: "Bu worker bir WEB sunucusudur.\n"
        dest: /tmp/web_bilgi.txt

- name: DB grubuna özel görev
  hosts: db
  become: yes
  tasks:
    - name: DB makinesine özel bilgi dosyası
      copy:
        content: "Bu worker bir VERİTABANI sunucusudur.\n"
        dest: /tmp/db_bilgi.txt

Ansible Roles Yapısının Kullanımı

    Ansible'da roles, yapılandırmaları görev, değişken, şablon, handler gibi mantıksal klasörlere ayırır.
Gerçek projelerde playbook'lar roles kullanılarak kurulur.

Örneğin webserver için bir role oluşturmak istiyorum, bu durumda aşağıdaki komutu çalıştırıyorum:
ansible-galaxy init roles/webserver

Ansible bu role için kendi özel yapısını oluşturur:


Ansible Roles

Tasks/main.yml içerisine aşağıdaki konfiği girdim:

- name: Apache kur
  apt:
    name: apache2
    state: present
    update_cache: yes

- name: Apache2 servis başlasın ve aktif kalsın
  service:
    name: apache2
    state: started
    enabled: yes

- name: Özel hoşgeldiniz sayfası
  copy:
    content: "Merhaba Hakan! Apache başarıyla çalışıyor.\n"
    dest: /var/www/html/index.html
    owner: root
    group: root
    mode: '0644'

Projeyi çalıştırabilmek için ana dizinimde (benim için ansible lab çalışmalarını yaptığım ve diğer hosts dosyamın bulunduğu yer) site.yml isimli bir dosya oluşturuyorum ve aşağıdaki gibi konfig giriyorum:

- name: Web makinelerine apache kur, servisi başlat, aktif kalsın ve özel hoşgeldin sayfası oluştur.
  hosts: web
  become: yes
  roles:
    - webserver

 Böylelikle site.yml dosyasını playbook ile koştuğumda webserver rolünde daha önce tanımladığım tüm işlemler gerçekleştiriliyor. Daha işlevsel bir yapıya kavuşmuş oluyorum. Her şey tek bir yml dosyasında olmaktansa görev ve sorumluluklara göre yani rollere göre yml dosyalarını aslında ayırmış oluyorum.

ansible-playbook -i hosts site.yml

sudo systemctl status apache2
sudo systemctl restart apache2
ss -tuln | grep :80
sudo ufw allow 80
sudo ufw allow 443
sudo ufw reload
sudo ufw status

    Ve ardından kendi ana bilgisayarımın tarayıcısını kullanarak http://192.168.1.110:80 bağlantısına gitmeyi çalıştığımda worker1 isimli makinemde çalışan apache2 üzerindeki sayfaya ulaşabildim. Ansible ile gönderilen ve sayfa girişine eklenen yazı da karşıma çıkmış oldu. Böylece çalışmayı başarıyla tamamladım.

Apache2 Main Page

Handlers Kullanımına Örnek

    Bu deneme için init komutunu tekrar koştum ve ikinci bir dizin oluşmasını sağladım, ikinci bir role gibi. ansible-galaxy init roles/webroles2-handlers ve ilgili rolü koşmak için yeni bir yml dosyası oluşturarak ilerledim.

Ansible Handlers


    Handlers, bir görev değişiklik algılandığında tetiklenen özel görevlerdir. Genellikle servisleri yeniden başlatmak, yeniden yüklemek gibi işlemler için kullanılır. Bizde Apache web sayfamızın içeriğinde bir değişiklik algılandığında örnek olması için bir tetikleyici kurgulayacağız ve sistem bu değişikliği algılayarak otomatik olarak apache servisini restart edecek. Bu sadece basit bir örnek, ihtiyaca göre buradaki handlers yeteneklerinden farklı şekillerde yararlanılabilir.


roles/webroles2-handlers/tasks/main.yml içerisine bir ekleme yapıyorum, daha önce eklediğimiz görevlere ek olarak:

---
- name: Apache web sunucusunun kurulu olduğundan emin olun
  ansible.builtin.apt:
    name: apache2
    state: present
    update_cache: yes
  become: yes
  notify: restart_apache_service

- name: Ana sayfa içeriğini değiştirin
  ansible.builtin.copy:
    content: "<html><body><h1>Ansible Handler Pratiği Başarılı!</h1></body></html>"
    dest: /var/www/html/index.html
  become: yes
  notify: restart_apache_service

Şimdi ise Handler dosyasını oluşturarak içerisine tetikleyicimizi ekliyoruz:

vi roles/webroles2-handlers/handlers/main.yml

---
- name: restart_apache_service
  ansible.builtin.service:
    name: apache2
    state: restarted
  become: yes

Şimdi ise Playbook'u oluşturalım: vi 11-handlers-web-webroles.yml

---
- name: Web server rolünü çalıştırma
  hosts: web
  roles:
    - webroles2-handlers

Şimdi ise tetikleyiciyi test edebiliriz:
ansible-playbook -i hosts 11-handlers-web-webroles.yml

Handler Ornek


    Bu çıktı bize şunu söylüyor: Ansible, web sayfasının içeriğinin değiştiğini algıladı. Bu değişiklik nedeniyle, playbook'taki diğer görevler tamamlandıktan sonra, tanımladığınız restart_apache_service handler'ını çalıştırdı. Handler başarılı bir şekilde çalışarak Apache'yi yeniden başlattı ve playbook'unuzu hatasız bir şekilde tamamladı.

Jinja2 Şablon Kullanımına Örnek


Öncelikle yeni bir role oluşturuyorum, bu 12. yml file'ım olmuş olacak.

#ansible-galaxy init info_creator

/roles/info_creator/templates/ dizini altında bilgi.txt.j2 isimli bir dosya oluşturdum ve içeriğini aşağıdaki gibi güncelledim:

Burada toplanan verilere aynı zamanda Ansible Facts ismi verilir.

Bu sunucuya ait bilgiler: Hostname: 
{{ ansible_hostname }} 
IP Adresi: {{ ansible_host }} 
İşletim Sistemi: {{ ansible_distribution }} {{ ansible_distribution_version }} 
Tarih: {{ ansible_date_time.iso8601 }}

/tasks/main.yml içerisine de ilgili ana görevimi ekliyorum:

---
- name: Dinamik bilgi dosyasını oluşturun
  ansible.builtin.template:
    src: bilgi.txt.j2
    dest: /home/ubuntu/bilgi.txt
    owner: ubuntu
    group: ubuntu
    mode: '0644'
  become: yes

ve artık playbook'u oluşturup koşabilirim:

#vi 12-create_info_jinja2_file.yml

ve içerisine:

---
- name: Dinamik bilgi dosyasını oluşturma
  hosts: web
  roles:
    - info_creator

Artık playbook'u koştuktan sonra ilgili makinenin /home/ubuntu/ dizininde yeralan bilgi.txt dosyasını kontrol edebilir ve dinamik bir şekilde bu belgenin güncellendiğini görebilirim:

jinja2


    Jinja2 şablonları, statik dosyaları olduğu gibi kopyalamak yerine, dinamik olarak oluşturmanızı sağlar. Bu şablonlar, her sunucuya özel bilgileri (IP adresi, hostname, port gibi) kullanarak yapılandırma dosyalarını otomatik olarak doldurabilir. Örneğin, bir web sunucusu için Apache sanal host yapılandırma dosyası oluştururken ServerName ve DocumentRoot gibi değerleri sunucunun hostname'ine göre dinamik olarak ayarlayabilirsiniz. Bu sayede, farklı sunucular için ayrı ayrı dosyalar oluşturmak yerine tek bir şablonu kullanabilir ve kod tekrarını önleyebilirsiniz. Aynı zamanda veritabanı yapılandırma dosyalarında bellek ayarları gibi değerleri, sunucunun özelliklerine göre belirlemek için de Jinja2 şablonlarından yararlanabilirsiniz.

    Diyelimki zabbix server'ınız var ve zabbix agentları onlarca makineye kurdunuz ve konfigüre ettiniz. Çeşitli nedenlerle zabbix server IP'ni değişti. Gidip tek tek makinelerinizdeki zabbix conf dosyasını düzenlemenize gerek yok, bunu bir yml file ile ansible kullanarak kolaylıkla halledebilirsiniz.

    Bir başka örnek, makinelerinize cronjob ekleyebilirsiniz. Hatta düzenli cronjoblarınız varsa, envanterinize yeni eklenen bir makine olduğunda crontab'ına ilgili jobların eklenmesini de otomatikleştirebilirsiniz. Cronjob yml dosyanızı bir scriptin içerisine yazarsınız ve ilgili scripti de ansible kurulu makinenizin crontab'ine istediğiniz zaman aralığına göre eklerseniz. Bundan böylelikle sadece envanter dosyanızı yani hosts file'ı güncellemeniz yeterli olacaktır. Crontab otomatik zamanı geldiğinde eklenecek.

    Veya farklı bir örnek, NTP sunucusu kurmak istediniz. Bunu elbette Crony ile yapabilirsiniz. Hem kurulumarı hem de ilgili konfigürasyonu ansible ile koşmanız mümkün. Birkaç dakikada tüm makinelerinizin baktığı NTP sunucusunu güncellenir. Ansible bu ve benzeri birden fazla esneklik ve kolaylık sağlıyor. Zaman zaman bazı örnekler paylaşmaya devam edeceğim, şimdilik bu yazıyı burada sonlandırıyorum.

Hiç yorum yok: