Ansible’da Tag Kullanımı ile Seçici Görev Çalıştırma

Ansible’ı bir süre kullandıktan sonra herkesin karşılaştığı bir sorun var: Playbook’lar büyüdükçe her seferinde tüm görevleri çalıştırmak hem zaman kaybı hem de risk oluşturmaya başlıyor. 200 görevlik bir playbook yazdınız, ama sadece nginx konfigürasyonunu güncellemek istiyorsunuz. Ne yapacaksınız? İşte tam bu noktada Ansible tag sistemi hayat kurtarıcı oluyor.

Tag’ler, playbook içindeki görevlere, role’lere veya play’lere etiket eklemenizi ve çalıştırma sırasında sadece o etiketlere sahip görevleri çalıştırmanızı sağlıyor. Kulağa basit geliyor, ama doğru kullanıldığında otomasyon stratejinizi kökten değiştiren bir özellik bu.

Tag Nedir ve Neden Kullanmalısınız

Bir tag, bir Ansible görevine bağladığınız bir isimden ibaret. Görevi çalıştırırken --tags veya --skip-tags parametresiyle hangi görevlerin çalışacağını seçiyorsunuz.

Gerçek dünya senaryosunu düşünün: Bir web uygulama sunucusu konfigürasyon playbook’unuz var. Bu playbook şunları yapıyor:

  • Sistem paketlerini güncelliyor
  • Nginx kuruyor ve yapılandırıyor
  • PostgreSQL kuruyor ve veritabanları oluşturuyor
  • Uygulama kodunu deploy ediyor
  • SSL sertifikalarını yapılandırıyor
  • Firewall kurallarını ayarlıyor
  • Monitoring agent kurulumu yapıyor

Sadece uygulama kodunu güncellemek için tüm bu adımları tekrar çalıştırmak hem 10-15 dakika kaybettiriyor hem de gereksiz risk yaratıyor. Tag kullanırsanız sadece deploy adımını çalıştırabiliyorsunuz.

Temel Tag Kullanımı

En basit haliyle bir göreve tag eklemek şöyle görünüyor:

# tasks/main.yml
- name: Nginx kur
  ansible.builtin.package:
    name: nginx
    state: present
  tags:
    - nginx
    - webserver
    - install

- name: Nginx konfigürasyonunu kopyala
  ansible.builtin.template:
    src: nginx.conf.j2
    dest: /etc/nginx/nginx.conf
  tags:
    - nginx
    - config

- name: Nginx servisini başlat
  ansible.builtin.service:
    name: nginx
    state: started
    enabled: yes
  tags:
    - nginx
    - service

Şimdi sadece nginx ile ilgili görevleri çalıştırmak için:

ansible-playbook site.yml --tags nginx

Sadece konfigürasyon değişikliklerini uygulamak için:

ansible-playbook site.yml --tags config

Nginx kurulumunu atlayıp direkt servis yönetimine geçmek için:

ansible-playbook site.yml --skip-tags install

Birden Fazla Tag ile Çalışmak

Birden fazla tag belirterek daha granüler kontrol sağlayabilirsiniz:

# Hem nginx hem de postgresql görevlerini çalıştır
ansible-playbook site.yml --tags "nginx,postgresql"

# Hem install hem de config etiketli görevleri atla
ansible-playbook site.yml --skip-tags "install,config"

Gerçek bir örnek üzerinden gidelim. Diyelim ki şu playbook yapınız var:

# site.yml
---
- name: Web sunucusu kurulumu
  hosts: webservers
  become: yes
  
  tasks:
    - name: Sistem paketlerini güncelle
      ansible.builtin.apt:
        update_cache: yes
        upgrade: dist
      tags:
        - system
        - update

    - name: Nginx kur
      ansible.builtin.apt:
        name: nginx
        state: present
      tags:
        - nginx
        - install

    - name: Nginx konfigürasyonu oluştur
      ansible.builtin.template:
        src: templates/nginx.conf.j2
        dest: /etc/nginx/sites-available/myapp
      notify: nginx reload
      tags:
        - nginx
        - config

    - name: PostgreSQL kur
      ansible.builtin.apt:
        name: postgresql
        state: present
      tags:
        - postgresql
        - database
        - install

    - name: Uygulama kodunu deploy et
      ansible.builtin.git:
        repo: "https://github.com/company/myapp.git"
        dest: /var/www/myapp
        version: "{{ app_version | default('main') }}"
      tags:
        - app
        - deploy

    - name: Uygulama bağımlılıklarını kur
      ansible.builtin.pip:
        requirements: /var/www/myapp/requirements.txt
        virtualenv: /var/www/myapp/venv
      tags:
        - app
        - dependencies

  handlers:
    - name: nginx reload
      ansible.builtin.service:
        name: nginx
        state: reloaded

Bu yapıyla artık çok esnek çalışabiliyorsunuz:

# Sadece uygulama deploy et
ansible-playbook site.yml --tags deploy

# Nginx ve uygulama konfigürasyonlarını güncelle
ansible-playbook site.yml --tags "config,app"

# Veritabanı ile ilgili hiçbir şeyi çalıştırma
ansible-playbook site.yml --skip-tags database

Role Seviyesinde Tag Kullanımı

Tag’leri sadece task seviyesinde değil, role seviyesinde de kullanabilirsiniz. Bu özellikle büyük playbook’larda çok işe yarıyor:

# site.yml
---
- name: Tüm sunucu konfigürasyonu
  hosts: all
  become: yes
  
  roles:
    - role: common
      tags: common
    
    - role: nginx
      tags:
        - nginx
        - webserver
    
    - role: postgresql
      tags:
        - postgresql
        - database
    
    - role: monitoring
      tags:
        - monitoring
        - observability

Bu sayede tek bir role’ü çalıştırmak için:

ansible-playbook site.yml --tags postgresql

Özel Tag Değerleri: always ve never

Ansible’ın iki özel tag değeri var: always ve never. Bunları doğru anlamak önemli.

always: Bu tag’e sahip görev, siz --tags ile başka bir şey belirtseniz bile her zaman çalışır.

never: Bu tag’e sahip görev, siz özellikle bu tag’i belirtmedikçe hiçbir zaman çalışmaz.

# tasks/main.yml
---
- name: Kritik sistem kontrolleri
  ansible.builtin.assert:
    that:
      - ansible_memory_mb.real.total > 1024
      - ansible_distribution in ['Ubuntu', 'Debian']
    fail_msg: "Sistem gereksinimleri karşılanmıyor"
  tags:
    - always  # Bu görev her zaman çalışır

- name: Nginx kur
  ansible.builtin.apt:
    name: nginx
    state: present
  tags:
    - nginx

- name: Tehlikeli: Tüm verileri sil
  ansible.builtin.file:
    path: /var/www
    state: absent
  tags:
    - never  # Bu görev ASLA otomatik çalışmaz
    - destructive

- name: Test verisini yükle
  ansible.builtin.script: load_test_data.sh
  tags:
    - never
    - testing

never tag’li görevi çalıştırmak için:

# Yıkıcı görevi çalıştır (dikkatli ol!)
ansible-playbook site.yml --tags destructive

# Test verisi yükle
ansible-playbook site.yml --tags testing

Bu pattern özellikle üretim ortamında tehlikeli operasyonları korumak için mükemmel. Kazara bir playbook çalıştırdığınızda never tag’li görevler es geçilecek.

Block Seviyesinde Tag Kullanımı

Birbirleriyle ilişkili görevleri block içine alıp tek bir tag ile yönetebilirsiniz:

# tasks/deploy.yml
---
- name: Uygulama deployment işlemleri
  block:
    - name: Mevcut uygulamayı yedekle
      ansible.builtin.archive:
        path: /var/www/myapp
        dest: "/var/backups/myapp-{{ ansible_date_time.iso8601 }}.tar.gz"

    - name: Yeni kodu çek
      ansible.builtin.git:
        repo: "{{ app_repo }}"
        dest: /var/www/myapp
        version: "{{ app_version }}"

    - name: Bağımlılıkları güncelle
      ansible.builtin.pip:
        requirements: /var/www/myapp/requirements.txt
        virtualenv: /var/www/myapp/venv

    - name: Veritabanı migrasyonlarını çalıştır
      ansible.builtin.command:
        cmd: /var/www/myapp/venv/bin/python manage.py migrate
        chdir: /var/www/myapp

    - name: Statik dosyaları topla
      ansible.builtin.command:
        cmd: /var/www/myapp/venv/bin/python manage.py collectstatic --noinput
        chdir: /var/www/myapp

  rescue:
    - name: Yedekten geri yükle
      ansible.builtin.unarchive:
        src: "/var/backups/myapp-{{ ansible_date_time.iso8601 }}.tar.gz"
        dest: /var/www/
        remote_src: yes

  tags:
    - deploy
    - app

Block seviyesinde tag eklendiğinde, block içindeki tüm görevler o tag’i otomatik olarak miras alır. Hem temiz hem de pratik.

Include ve Import ile Tag Kullanımı

Büyük playbook’larda görevleri ayrı dosyalara bölmek yaygın bir pratik. Tag’lerle include/import kullanırken dikkat edilmesi gereken bazı farklar var.

import_tasks ile tag kullanımı (statik):

# site.yml
---
- name: Web sunucusu kurulumu
  hosts: webservers
  become: yes
  
  tasks:
    - name: Nginx görevlerini import et
      ansible.builtin.import_tasks: tasks/nginx.yml
      tags:
        - nginx

    - name: Veritabanı görevlerini import et
      ansible.builtin.import_tasks: tasks/database.yml
      tags:
        - database

import_tasks statik çalışır, tag’ler import edilen dosyanın içindeki tüm görevlere uygulanır.

include_tasks ile tag kullanımı (dinamik):

# site.yml
---
- name: Ortama göre görevleri dahil et
  hosts: all
  become: yes
  
  tasks:
    - name: Ortama özel görevleri yükle
      ansible.builtin.include_tasks: "tasks/{{ env_type }}.yml"
      tags:
        - env_specific
      when: env_type is defined

include_tasks dinamik çalışır. Burada dikkat: include_tasks ile tag’lerin davranışı farklıdır. --tags env_specific belirtseniz bile include edilen dosya içindeki görevler sadece kendi tag’lerine göre çalışır. Bu yüzden import_tasks tercih edilebilir durumlarda onu kullanın.

Gerçek Dünya: CI/CD Pipeline Entegrasyonu

Tag sistemi, CI/CD pipeline’larınızla entegre ettiğinizde gerçek gücünü gösteriyor. Bir GitLab CI örneği:

# .gitlab-ci.yml içinden ansible çağrısı örneği
# Bu dosya ansible playbook çağrılarını gösteriyor

# Sadece uygulama kodunu deploy et (hızlı güncelleme)
ansible-playbook -i inventory/production site.yml 
  --tags deploy 
  --extra-vars "app_version=${CI_COMMIT_SHA}"

# Sadece konfigürasyon değişikliklerini uygula
ansible-playbook -i inventory/production site.yml 
  --tags config 
  --diff

# Tam kurulum (yeni sunucu provisioning)
ansible-playbook -i inventory/production site.yml 
  --tags "install,config,service"

Şimdi daha kapsamlı bir üretim senaryosu düşünelim. Bir e-ticaret platformu yönetiyorsunuz ve farklı ekipler farklı sorumluluk alanlarına sahip:

# roles/ecommerce/tasks/main.yml
---
# Altyapı ekibi sorumluluğu
- name: Sistem paketlerini güncelle
  ansible.builtin.apt:
    update_cache: yes
    upgrade: security
  tags:
    - infra
    - security
    - always

- name: Fail2ban yapılandır
  ansible.builtin.template:
    src: fail2ban.conf.j2
    dest: /etc/fail2ban/jail.local
  tags:
    - infra
    - security

# Backend ekibi sorumluluğu
- name: Uygulama servisini güncelle
  ansible.builtin.systemd:
    name: ecommerce-api
    state: restarted
    daemon_reload: yes
  tags:
    - backend
    - service
    - deploy

- name: API konfigürasyonunu güncelle
  ansible.builtin.template:
    src: api-config.yml.j2
    dest: /etc/ecommerce/api-config.yml
  tags:
    - backend
    - config

# Frontend ekibi sorumluluğu
- name: Statik dosyaları deploy et
  ansible.builtin.synchronize:
    src: "{{ frontend_build_path }}/"
    dest: /var/www/html/
    delete: yes
    recursive: yes
  tags:
    - frontend
    - deploy

- name: CDN önbelleğini temizle
  ansible.builtin.uri:
    url: "{{ cdn_purge_url }}"
    method: POST
    headers:
      Authorization: "Bearer {{ cdn_api_key }}"
  tags:
    - frontend
    - cdn

# Veritabanı ekibi sorumluluğu
- name: Veritabanı yedek al
  ansible.builtin.command:
    cmd: "pg_dump -U postgres ecommerce > /var/backups/ecommerce-{{ ansible_date_time.date }}.sql"
  tags:
    - database
    - backup
    - never  # Sadece açıkça belirtildiğinde çalış

- name: Veritabanı indekslerini optimize et
  ansible.builtin.command:
    cmd: psql -U postgres -c "REINDEX DATABASE ecommerce;"
  tags:
    - database
    - maintenance
    - never

Bu yapıyla her ekip kendi alanını bağımsız yönetebiliyor:

# Backend ekibi deploy yapar
ansible-playbook site.yml --tags backend

# Frontend güncellemesi
ansible-playbook site.yml --tags "frontend,cdn"

# Güvenlik yamaları uygula
ansible-playbook site.yml --tags security

# Veritabanı bakımı (planlı bakım penceresi)
ansible-playbook site.yml --tags "database,maintenance"

Tag’leri Listeleme ve Debug Etme

Hangi tag’lerin mevcut olduğunu görmek için:

# Playbook'taki tüm tag'leri listele
ansible-playbook site.yml --list-tags

# Hangi görevlerin çalışacağını önizle (gerçekten çalıştırmadan)
ansible-playbook site.yml --tags nginx --list-tasks

# Tüm görevleri listele
ansible-playbook site.yml --list-tasks

Bu komutların çıktısı şuna benzer:

# --list-tags çıktısı
playbook: site.yml

  play #1 (webservers): Web sunucusu kurulumu
    TASK TAGS: [always, app, config, database, deploy, install, nginx, postgresql, security, service, system, update]

Bu özelliği özellikle yeni ekip üyelerine playbook’u anlatırken çok kullanıyorum. Bir playbook’un ne yaptığını anlamanın en hızlı yolu.

Tag İsimlendirme Konvansiyonu

Tutarlı bir tag isimlendirme stratejisi olmadan büyük playbook’larda kaos yaşanıyor. Kendi deneyimlerimden oluşan bir konvansiyon öneririm:

Bileşen bazlı tag’ler (ne üzerinde çalışıyorsunuz):

  • nginx, postgresql, redis, docker

Eylem bazlı tag’ler (ne yapıyorsunuz):

  • install, config, deploy, restart, backup

Ortam bazlı tag’ler (nerede çalışıyor):

  • production, staging, development

Sorumluluk bazlı tag’ler (kim yönetiyor):

  • infra, backend, frontend, database, security

Zaman bazlı tag’ler (ne zaman çalışıyor):

  • daily, weekly, on_change, bootstrap
# Konvansiyona uygun örnek
- name: Redis konfigürasyonunu güncelle
  ansible.builtin.template:
    src: redis.conf.j2
    dest: /etc/redis/redis.conf
  tags:
    - redis          # bileşen
    - config         # eylem
    - infra          # sorumluluk
    - on_change      # zaman

Yaygın Hatalar ve Çözümleri

Hata 1: Tag’leri unutmak

Yeni bir görev ekleyip tag koymayı unutmak çok yaygın. Bu durumda o görev her zaman çalışır, --tags ile başka bir şey belirtseniz bile. Bunu önlemek için:

# Tüm görevlerin tag'e sahip olduğunu kontrol et
ansible-playbook site.yml --list-tasks | grep -v "TAGS:"

Hata 2: include_tasks ile tag davranışını yanlış anlamak

include_tasks ile eklenen dosyalar dinamik olduğu için tag filtrelemesi farklı çalışır. Beklediğiniz gibi çalışmıyorsa import_tasks kullanmayı deneyin.

Hata 3: Handler’ların tag’lerden etkilenmesi

Handler’lar görev tarafından tetiklendiğinde çalışır, tag’lere bakılmaksızın. Yani nginx config görevini tag ile çalıştırdınız ve handler tetiklendi, handler’ın tag’i olmasa da çalışır. Bu genellikle istenen davranıştır ama bilinmesi önemli.

Hata 4: always tag’ini gereğinden fazla kullanmak

Her önemli göreve always eklemek tag sisteminin amacını ortadan kaldırır. always sadece gerçekten kritik ön kontroller için kullanın.

İleri Seviye: Tag’leri Değişkenlerle Dinamik Kullanım

Tag’leri dinamik hale getirmenin bir yolu, playbook başında koşullara göre farklı görev grupları çalıştırmak:

# Ortama ve değişkenlere göre seçici çalıştırma
ansible-playbook site.yml 
  --tags "{{ deployment_type | default('full') }}" 
  --extra-vars "app_version=v2.3.1 env=production"

# deployment_type değişkenine göre:
# full: Tam kurulum
# app: Sadece uygulama
# config: Sadece konfigürasyon

Bunu CI/CD sisteminde environment variable olarak geçirirseniz çok esnek bir pipeline elde edersiniz.

Sonuç

Tag sistemi, Ansible’ı gerçek anlamda operasyonel bir araç haline getiren özelliklerden biri. Doğru uygulandığında şunları elde edersiniz:

  • Hız: 200 görevlik playbook’u komple çalıştırmak yerine 10 görevlik bir alt küme çalıştırırsınız
  • Güvenlik: Üretimde yanlışlıkla bir şeyleri bozma riskini azaltırsınız
  • Takım çalışması: Farklı ekipler kendi alanlarını bağımsız yönetebilir
  • CI/CD entegrasyonu: Pipeline’larınız daha granüler ve hızlı hale gelir
  • Bakım kolaylığı: Playbook’larınız daha anlaşılır ve belgelenmiş olur

Başlangıçta tag eklemek fazladan iş gibi görünebilir. Ama 6 ay sonra o büyümüş playbook’u yönetmeye çalışırken, ya da bir acil durumda sadece belirli bir bileşeni hızla güncellemek zorunda kaldığınızda, bu küçük yatırımın ne kadar değerli olduğunu anlıyorsunuz. Eğer henüz tag kullanmıyorsanız, şu an çalıştığınız playbook’u açın ve bileşen bazlı tag’leri eklemeye başlayın. Bir haftada farkını göreceksiniz.

Yorum yapın