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.