SSD Nodes Learn Hosting plans →
Rehberler Matt ConnorYazan Matt Connor · Güncellendi 2026-08-21

Ansible Check Mode ve --diff ile Dry Run Kullanımı

Ansible check mode ve --diff bayraklarının çalışma mantığını öğrenin. Hangi modüllerin dry run sırasında hata verebileceğini ve simülasyonun sınırlarını keşfedin.

Ansible check mode ne işe yarar

Ansible check mode bir "dry run" (kuru çalışma) işlemidir: ansible-playbook --check play içerisindeki her bir sunucuya bağlanır, her modüle mevcut durumun istenen durumla eşleşip eşleşmediğini sorar ve hiçbir değişiklik yapmadan nelerin değişeceğini raporlar. --diff eklendiğinde, üzerinde işlem yapılacak dosyaların önceki ve sonraki içeriklerini de yazdırır. Bu iki özellik birlikte, her gerçek çalıştırmadan önce sorulması gereken şu soruyu yanıtlar: bu sunucularda neler değişmek üzere?

Check mode, playbook'unuzun bir simülasyonu değildir. Sunucunun herhangi bir yerde bir modeli tutulmaz. Her modülden sadece yazmak yerine bakması istenir. Salt okunur yanıt verebilen bir modül changed raporlar ve bir sonraki adıma geçer. Yanıt veremeyen bir modül ise hiçbir şey yapmaz ve hiçbir şey raporlamaz. Ansible dokümantasyonu bunu tek bir satırda özetler: "Check mode desteği olmayan modüller hiçbir şey raporlamaz ve hiçbir şey yapmaz." İşte bu boşluk, kuru çalışmanın size yanlış cevap verebileceği noktadır; bu rehberin büyük bir kısmı da bu boşluk hakkındadır.

Deneme çalıştırmasını gerçekleştirin: --check ve --diff

ansible-playbook -i inventory.ini site.yml --check --diff --limit web1

-C ve -D, bu iki bayrağın kısa biçimleridir. --limit kullanımı kasıtlıdır. Tek bir sunucunun diff çıktısı okunabilir bir şeydir. Yirmi sunucunun diff çıktısı ise hızlıca geçip gideceğiniz bir yığındır.

Dört sonuç kelimesi tüm raporu özetler.

  • ok: [web1], modülün kontrol ettiğini ve durumun zaten eşleştiğini belirtir. Hiçbir şey değişmeyecektir.
  • changed: [web1], modülün bir şeyler yazacağını belirtir. --diff ile birlikte, üzerindeki satırlar nelerin değişeceğini gösterir.
  • skipping: [web1], görevin değerlendirilmediği anlamına gelir. Ya bir when yanlıştır ya da modül kontrol modunda çalışamıyordur.
  • fatal: [web1], görev kontrol edilirken hata oluştuğu anlamına gelir. Playbook'un bozuk olduğunu varsaymadan önce mesajı okuyun.

--diff, dosya modülleri için birleşik bir diff çıktısı verir; kaldırılan satırlar - ile, eklenen satırlar ise + ile işaretlenir. Bu çıktı, satırları --- before ve +++ after ile başlayan ve hedef yolu belirten bir başlık altında sunulur. Dosya yazmayan modüller kendi öncesi ve sonrası durumlarını yazdırır; bu nedenle ansible.builtin.user, dosya içeriği yerine değişecek öznitelikleri gösterir.

Bayrağı unutmamak için diff özelliğini ansible.cfg içerisinde kalıcı olarak açın:

[diff]
always = true
context = 5

Kontrol modundan önce iki daha düşük maliyetli kontrol uygulanabilir. ansible-playbook site.yml --syntax-check, hiçbir sunucuyla bağlantı kurmadan YAML dosyasını ve play yapısını ayrıştırır. ansible-playbook site.yml --list-tasks, çalışacak görevleri listeler; etiketli olduğunu düşündüğünüz bir rolün aslında neden etiketli olmadığını bu şekilde anlarsınız. Her ikisi de bağlantı kurmadığı için anında sonuç verir.

Kontrol modunun kendisi ise bağlantı kurar. Belirtilen düzendeki her sunucuya SSH ile bağlanır ve verileri toplar; bu nedenle kapalı olan bir sunucu deneme çalıştırmasının başarısız olmasına neden olur. Bu durum başlı başına yararlı bir sinyaldir ve aynı zamanda erişilemeyen sunucular için bir playbook'un ne yapması gerektiğine karar vermenin bir deneme çalıştırmasını CI sürecine dahil etmeden önce neden önemli olduğunun nedenidir.

Why check mode fails on a fresh server

This play is correct. Run it with --check against a server that does not have nginx yet, and most of it fails.

- name: Install nginx
  ansible.builtin.apt:
    name: nginx
    state: present

- name: Write the site config
  ansible.builtin.template:
    src: site.conf.j2
    dest: /etc/nginx/conf.d/site.conf

- name: Start and enable nginx
  ansible.builtin.service:
    name: nginx
    state: started
    enabled: true

The apt task reports changed, and it is right: the package is absent, so a real run would install it. Check mode did not install it. The template task then fails, because /etc/nginx/conf.d/ does not exist on this host and nothing created it. The service task fails as well, because there is no nginx unit for it to query. Neither failure is a bug in the playbook. The dry run ran out of the state it needed, which is what the documentation means when it warns that check mode cannot produce useful output for a task whose input depends on a prior task's change.

So the honest version of the rule: check mode is accurate against a host the playbook has already converged, and noisy against a fresh one. A --check run where every task reports ok is a real statement about a converged host, because it means nothing would change. On a brand new host, --check mostly tells you the host is new. When you write your first Ansible playbook against a VPS, expect the first dry run to be a wall of red, and judge the playbook by the second one.

Komut ve kabuk görevlerinin kontrol modunda neden atlandığı

ansible.builtin.command ve ansible.builtin.shell, çalıştırdığınız komutun ne işe yaradığını bilmez. Rastgele bir ikili dosyayı salt okunur şekilde çalıştırmanın bir yolu yoktur, bu nedenle kontrol modunda modül bu komutu çalıştırmayı reddeder. Görev sonucu skipped: true değerini ve Command would have run if not in check mode mesajını taşır, çıktınızda ise skipping: [web1] görünür.

Modül belgeleri, kontrol modu desteğini "kısmi" olarak adlandırır ve önerdiği geçici çözüm creates ve removes kullanımıdır. Göreve bir creates yolu verirseniz, kontrol modu en azından dosya testini değerlendirebilir:

- name: Extract the release bundle
  ansible.builtin.command: /usr/bin/tar xf /tmp/app.tar.gz -C /opt/app
  args:
    creates: /opt/app/bin/app

Eğer /opt/app/bin/app zaten mevcutsa, kontrol modu Would not run command since '/opt/app/bin/app' exists raporlar; bu geçerli bir yanıttır. Eğer yol eksikse, Command would have run if not in check mode sonucunu alırsınız; bu da geçerli bir yanıttır. creates olmadan, bu görev kuru çalışmanızda boş bir alan olarak kalır.

Bunun zincirleme etkisi, boş alandan daha kötüdür. Atlanan bir görev yine de bir sonuç kaydeder, ancak bu sonuç bir atlama sonucudur ve stdout anahtarına sahip değildir. Bir sonraki görevin koşulu değerlendirilirken hata oluşur ve 'dict object' has no attribute 'stdout' ifadesine yakın bir hata mesajı alırsınız. Playbook'unuz gerçek bir çalıştırmada düzgün çalışırken kuru çalışmada hata verir; bu, söz konusu özelliğin en kafa karıştırıcı başarısızlık durumudur.

check_mode: false ve ait olduğu tek yer

Bir görev üzerinde check_mode: false kullanmak, "--check altında olsa bile bunu gerçekten çalıştır" anlamına gelir. Bu, atlanan komut sorununa yönelik çözümdür ve yalnızca okuma yapan görevlerde güvenlidir.

- name: Read the installed app version
  ansible.builtin.command: /usr/local/bin/app --version
  register: app_version
  check_mode: false
  changed_when: false

Bu görev her iki modda da dürüsttür. Bir sürüm bilgisini okur ve hiçbir zaman yazma yapmaz; changed_when: false, yapmadığı bir değişikliği raporlamasını engeller ve check_mode: false, app_version.stdout değerinin bir deneme çalışması (dry run) sırasında var olmasını sağlar, böylece buna dayalı koşullar değerlendirilmeye devam eder.

Anahtar kelimeyi başka bir yere yapıştırmadan önce anlamını tam olarak okuyun. check_mode: false içeren bir görev, ansible-playbook --check sırasında sunucularınıza yazma işlemi yapar. Bunu bir apt veya template görevi üzerinde kullanırsanız, deneme çalışması daha düzenli görünür ancak artık bir deneme çalışması olmaktan çıkar. Yazma yapan bir görev güvenli hale getirilemiyorsa, bunun yerine onu korumaya alın:

- name: Apply the database migration
  ansible.builtin.command: /usr/local/bin/app migrate --apply
  when: not ansible_check_mode

ansible_check_mode, Ansible'ın bir deneme çalışması sırasında true değerine atadığı sihirli bir değişkendir. Bunun tersi olan anahtar kelime de mevcuttur. check_mode: true, bir görevi gerçek bir çalıştırma sırasında bile her zaman deneme moduna sabitler; bu da onu bir sapma (drift) denetleyicisine dönüştürür: sonucu kaydedin; bir changed raporu, sunucunun artık görevin talep ettiği durumla eşleşmediği anlamına gelir.

Bir görevin her çalıştırıldığında neden değiştiğini bildirmesi

Playbook'u araya hiçbir şey girmeden arka arkaya iki kez çalıştırın. İkinci çalıştırmada her görev ok bildirmelidir. Hâlâ changed bildiren herhangi bir görev size iki şeyden birini söylüyordur: modül yönettiği durumu göremiyordur ya da sağladığınız girdi kararlı değildir. Her ikisi de düzeltilebilir ve hiçbiri susturulması gereken bir gürültü değildir.

  • creates, removes veya changed_when içermeyen command ve shell, modülün bir şeyin gerçekleşip gerçekleşmediğini bilme yolu olmadığından her seferinde changed bildirir. creates ekleyin veya çıktıdaki bir dizgeye karşı changed_when ayarlayın.
  • state: touch içeren ansible.builtin.file, bir dosyaya dokunmak zaman damgalarını güncellediği için tasarım gereği her çalıştırmada changed bildirir. Yalnızca sahibi veya modu ayarlamak istiyorsanız state: file kullanın.
  • Oluşturulan çıktısı değişen bir template, dosyayı her çalıştırmada yeniden yazar. ansible_date_time'den gelen bir zaman damgası, now() çağrısı veya her seferinde yeni oluşturulan bir parola farklı baytlar üretir, bu nedenle modül doğru bir şekilde değişiklik bildirir. Değişken değeri şablondan çıkarın.
  • password: "{{ pw | password_hash('sha512') }}" içeren ansible.builtin.user her çalıştırmada değişir, çünkü password_hash her çağrıldığında rastgele bir tuz (salt) seçer, bu nedenle ortaya çıkan özet (hash) /etc/shadow içinde zaten var olanla asla eşleşmez. Kararlı bir şeyden türetilen açık bir tuz değeri geçirin.
  • Bir paket modülündeki state: latest, bir yükseltme mevcut olduğunda changed bildirir. Bu dürüst bir durumdur. state: latest'in sonucunu tahmin edemeyeceğiniz bir playbook vermesinin nedeni de budur. state: present kullanın ve yükseltmeyi bilinçli olarak yapın.
  • creates içermeyen bir URL'ye işaret eden ansible.builtin.unarchive, veriyi yeniden çeker ve yeniden çıkarır. Ona creates bir yol verin.

--diff, bunları birbirinden ayırmanın en hızlı yoludur. Bir görev changed diyorsa ve fark (diff) farklı baytlar gösteriyorsa, girdiniz kararsızdır. Eğer changed diyorsa ve fark hiçbir şey göstermiyorsa, modül neyi değiştirdiğini ifade edemiyordur; bu genellikle bir command görevi veya zaman damgası gibi yalnızca meta veri yazan bir işlem anlamına gelir.

Gürültülü bir görevi susturmak için changed_when: false kullanmayın. Bu, raporu bastırır; dolayısıyla notify asla tetiklenmez ve servisi yeniden başlatan işleyici (handler) asla çalışmaz. Bunun yerine görevi düzeltin.

Etki alanını daraltma: --limit, --tags ve --step

Check mode, nelerin değişeceğini size bildirir. Bu bayraklar, aynı anda kaç makinenin işlemden etkileneceğini belirler.

--limit, çalışmayı envanterin bir alt kümesiyle sınırlar. hosts: ile aynı desenleri kabul eder, bu nedenle hem --limit web1 hem de --limit 'webservers:!web3' çalışır. Deseni tırnak içine alın. Etkileşimli bir bash oturumunda tırnak içine alınmamış bir !, ünlem işareti üzerinde geçmiş genişletmesini tetikler ve Ansible komutu görmeden önce kabuğunuz komutu yeniden yazar.

Güvenmeden önce deseni doğrulayın. ansible-playbook site.yml --limit 'webservers:!web3' --list-hosts, eşleşen ana bilgisayarları yazdırır ve hiçbirine bağlanmadan çıkar. Hiçbir şeyle eşleşmeyen bir desen güvenlidir çünkü Ansible tüm envantere geri dönmez. Ana bilgisayar deseniyle eşleşemediğine dair bir uyarı yazdırır ve ardından ana bilgisayarların ve --limit ifadesinin hiçbir ana bilgisayarla eşleşmediğini belirten bir hatayla çıkar. Envanter dosyasının bu grupları nasıl tanımladığını bilmek, bir desenin öngörülebilir olmasını sağlayan temel unsurdur.

--tags deploy yalnızca etiketli görevleri çalıştırır, --skip-tags packages ise diğer her şeyi çalıştırır. --list-tags, mevcut olanları listeler. Etiketler, bir play tümünü çalıştırmak istemeyeceğiniz kadar büyüdüğünde işe yarar; bu durum aynı zamanda uzun bir playbook'u rollere bölmenin nedenlerinden biridir.

--start-at-task "Write the site config", başarısız olan bir çalışmayı adlandırılmış bir görevden itibaren devam ettirir. Kurtarma için kullanın ve maliyetini anlayın: o görevden önceki her şey atlanır; buna fact'leri ayarlayan veya sonraki görevlerin okuduğu değişkenleri kaydeden görevler de dahildir.

--step, her görevden önce onay ister ve evet, hayır veya devam et yanıtınızı bekler. Yavaştır ancak yıkıcı bir işlemi ilk kez çalıştırırken doğru araçtır; çünkü yirmi görev sonrasında değil, iki görev arasında durabilirsiniz.

Değişikliği serial ile kademeli olarak dağıtma

Varsayılan olarak Ansible, bir play içindeki her görevi, bir sonrakine geçmeden önce tüm hostlar üzerinde çalıştırır. Bu yöntem hızlıdır ancak hatalı bir görev, tüm filoyu aynı anda etkiler. Siz hatayı fark edip Ctrl-C tuşuna basana kadar değişiklik çoktan her yere yayılmış olur.

serial, play'i gruplara böler. Tüm play önce ilk grup üzerinde çalışır, ardından sıradaki gruba geçer.

- name: Roll out the web tier
  hosts: webservers
  serial: [1, 5, "30%"]
  max_fail_percentage: 0
  tasks:
    - name: Deploy the release
      ansible.builtin.include_role:
        name: webapp

İlk grup tek bir hosttan oluşur. Eğer bu host sorunsuz çalışırsa, ikinci grup beş hosttan oluşur ve sonraki her grup, play'deki toplam host sayısının yüzde 30'unu kapsar. max_fail_percentage: 0, bir gruptaki herhangi bir host başarısız olduğunda play'i hemen durdurur; böylece hatalı bir sürüm sadece tek bir makinede kalır. any_errors_fatal: true ise daha sert bir yöntemdir ve ilk host hatasında tüm play'i herkes için sonlandırır.

İlk olarak tek bir host üzerinde çalıştırmak paranoya değildir; bunun belirli bir nedeni vardır. Envanter grupları zamanla birbirinden farklılaşabilir. Diğerlerinden altı ay sonra eklenen bir sunucu, farklı bir dağıtım sürümü çalıştırıyor olabilir, birisi tarafından manuel olarak kurulmuş bir servis barındırıyor olabilir veya disk yapılandırması farklı olabilir. Playbook grup için doğru olsa da o tek host için hatalı olabilir ve konfigürasyonu tamamlanmış bir host üzerinde yapılan kuru bir çalıştırma (dry run) bunu göstermeyecektir. Linux sunucu filosunu yönetmek, büyük ölçüde değişiklik yapılmadan önce bu uyumsuz hostu bulma pratiğidir.

Çalıştırma sırası

  1. ansible-playbook site.yml --syntax-check, ağ bağlantısı gerektirmeksizin YAML ve yapı hatalarını yakalar.
  2. ansible-playbook site.yml --limit web1 --list-hosts, deseninizin düşündüğünüz eşleşmeyi sağladığını kanıtlar.
  3. ansible-playbook site.yml --limit web1 --check --diff bir deneme çalıştırmasıdır. Farkları (diff) inceleyin.
  4. ansible-playbook site.yml --limit web1 --diff, yapılandırmayı ilgili tek bir sunucuya uygular.
  5. 4. adımı tekrar çalıştırın. Her şey ok rapor etmelidir. Hâlâ changed durumunda olan herhangi bir öğe, tüm filoya dokunmadan önce düzeltilmesi gereken bir görevdir.
  6. Tüm envanter genelinde ansible-playbook site.yml --check --diff artık anlamlı bir yanıt döndürür; çünkü yakınsanan (converged) sunucular sessizdir ve geriye kalanlar gerçek farkı (delta) temsil eder.
  1. adımla ilgili bir uyarı: --diff, dosya içeriklerini terminalinize ve CI iş günlüğünüze yazdırır; bu nedenle veritabanı parolası oluşturan bir şablon, bu parolayı günlüğe açık metin olarak yansıtır. Çıktıyı gizlemek için ilgili görevde diff: false ayarını kullanın veya sonucun tamamını gizlemek için no_log: true seçeneğini tercih edin. Değerin kendisini ise depoda tutmak yerine şifrelenmiş bir Ansible Vault dosyası içinde saklayın.

FAQ

ansible-playbook --check komutu sunucuda herhangi bir değişiklik yapar mı?

Hayır, kontrolünüz altında olan bir istisna dışında. Check modunda her modülden yazmak yerine rapor vermesi istenir; bunu yapamayan modüller ise hiçbir şey rapor etmez ve hiçbir işlem yapmaz. İstisna, o tek görevin --check çalışması sırasında bile gerçek anlamda yürütülmesini zorunlu kılan check_mode: false görev anahtar kelimesidir. Bir "dry run" (deneme çalıştırması) işlemine güvenmeden önce playbook ve rollerinizi check_mode: false için tarayın ve her eşleşmenin yalnızca durumu okuyan bir görev olduğunu doğrulayın.

--check ve --diff arasındaki fark nedir?

--check, herhangi bir işlemin gerçekten çalışıp çalışmayacağına karar verir. --diff ise ne kadar detay göreceğinize karar verir. --check tek başına kullanıldığında, bir dosyanın değişeceğini size bildirir. --diff tek başına kullanıldığında değişikliği uygular ve değişen satırları gösterir. Okunabilir bir deneme çalıştırması için bunları birlikte kullanın ve ansible.cfg içindeki [diff] altında always = true ayarını yaparak gerçek çalıştırmalar için de --diff özelliğini açık bırakın.

Ansible görevim neden her çalıştırmada changed raporu veriyor?

Çünkü modül yönettiği durumu göremiyor ya da ona verdiğiniz değer her seferinde farklılık gösteriyor. command ve shell, creates veya changed_when eklemediğiniz sürece her zaman changed rapor eder. state: touch ile file, tasarımı gereği değişiklik yapar. Zaman damgası veya yeni oluşturulmuş bir parola içeren bir şablon, her çalıştırmada farklı baytlar üretir; bu nedenle dosya gerçekten yeniden yazılır. Playbook'u arka arkaya iki kez çalıştırın: ikinci geçişte hala changed olan görev, düzeltilmesi gereken görevdir.

command ve shell görevlerim neden deneme çalıştırması sırasında atlanıyor?

Çünkü rastgele bir komutu çalıştırmanın salt okunur bir yolu yoktur. Check modunda command modülü, Command would have run if not in check mode mesajı ile skipped: true durumunu ayarlar. Check modunun dosya testini değerlendirebilmesi için creates veya removes ekleyin. Yalnızca durumu okuyan bir görev için, changed_when: false ile birlikte check_mode: false ayarını yapın; böylece kayıtlı sonuç deneme çalıştırması sırasında var olmaya devam eder ve buna dayalı koşullar çalışmaya devam eder.

Check modu neden yeni bir sunucuda başarısız oluyor ancak mevcut olanda başarılı oluyor?

Çünkü check modu, sonraki görevlerin bağlı olduğu durumu oluşturmaz. nginx kurulu olmayan bir ana bilgisayara karşı yapılan deneme çalıştırması, kurulumu changed olarak rapor eder, ardından /etc/nginx/conf.d/ içine yazan görevde başarısız olur; çünkü bu dizin hiçbir zaman oluşturulmamıştır. Bu beklenen bir davranıştır. Check modu, playbook'un halihazırda yakınsadığı ana bilgisayarlar için bir sapma tespit edicidir. İlk çalıştırmayı doğrulayamaz. Yeni bir ana bilgisayarda, playbook'u bir makineye uygulayın ve ikinci çalıştırmayı okuyun.

#ansible#check-mode#idempotency#automation#safety