Ansible Jinja2 şablonları ve handler kullanımı
Nginx yapılandırma dosyasını Jinja2 ile oluşturun ve handler kullanarak sadece değişiklik olduğunda servisi yeniden başlatın. Idempotency prensibini uygulamalı görün.
Ansible şablonları ve işleyicileri ilk playbook'unuza neler katar
Ansible şablonları ve işleyicileri, statik bir playbook'u işlevsel hale getiren iki temel bileşendir. Şablon, yapılandırma dosyasını değişkenlerinizden oluşturur; böylece tek bir dosya tüm sunucular için kullanılabilir. İşleyici ise yalnızca bir görevde gerçekten değişiklik yapıldığında çalışır; bu sayede servis, yalnızca yapılandırma değiştiğinde yeniden yüklenir, diğer zamanlarda ise müdahale edilmez.
Bu rehber, tam olarak VPS üzerinde ilk Ansible playbook'unuz konusunun kaldığı yerden devam eder. Halihazırda bir paket kuran ve bir servis başlatan bir play'iniz bulunuyor. Aşağıdaki işlemlerin tamamı tek bir makine üzerinde çalışır, çünkü play yerel bağlantı üzerinden localhost hedefini kullanır. Takip etmek için ikinci bir sunucuya ihtiyacınız yoktur. Aynı play, görevlerde hiçbir değişiklik yapılmadan gerçek envanter sunucularına karşı da çalıştırılabilir; son bölüm ise nelerin değişeceğini ele alır.
Çalışma dizinini ayarlama
sudo apt update
sudo apt install -y ansible nginx
ansible --version
mkdir -p ~/ansible-templates/templates
cd ~/ansible-templatesnginx, yapılandırma dosyasına ve yeniden yükleme komutuna sahip gerçek bir servis olduğu için burada kullanılmıştır; bu, örnek için gereken her şeyi karşılar. ansible --version, ansible-core sürümünü ve kullanacağı Python yorumlayıcısını yazdırır. Her ikisini de not edin. Aşağıdaki playbook, Ansible 2.10 veya daha yeni bir sürüm gerektiren ansible.builtin.template gibi tam nitelikli modül adlarını kullanır; güncel dağıtım paketlerinin tamamı bu sürümün üzerindedir.
inventory.ini dosyasını oluşturun:
[local]
localhost ansible_connection=local ansible_python_interpreter="{{ ansible_playbook_python }}"ansible_connection=local, Ansible'a her görevi kendisine bir SSH oturumu açmak yerine yerel bir süreç olarak çalıştırmasını söyler. İkinci ayar bir süsleme değildir. Bir envanter dosyasına localhost yazdığınızda, bu ifade sıradan bir host haline gelir ve Ansible'ın örtük localhost'a ücretsiz olarak sağladığı yorumlayıcıyı kaybeder. Bu durumda yorumlayıcı keşfine geri döner ve playbook'u çalıştıran Python'dan farklı bir Python seçebilir. ansible_playbook_python, şu anda ansible-playbook'i çalıştıran yorumlayıcıdır ve ikisinin uyumlu kalmasını sağlar.
ansible.cfg dosyasını oluşturun:
[defaults]
inventory = inventory.iniBu dosya olmadan her komutta -i inventory.ini parametresini geçmeniz gerekir. Hiç envanter dosyası olmadığında Ansible [WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all' çıktısını verir ve hosts: all içeren bir play hiçbir şeyle eşleşmez. ansible.cfg hakkında bir nokta daha: Ansible, dosya herkes tarafından yazılabilir (world-writable) bir dizinde bulunduğunda onu yok sayar; bu nedenle projeyi ev dizininiz altında tutun. Bir envanter dosyası, host listesinden daha fazlasını içerir ve bu, işi yapan en küçük envanter dosyasıdır.
template ve copy karşılaştırması ve kullanım alanları
ansible.builtin.copy bir dosyayı olduğu gibi aktarır. ansible.builtin.template ise dosyayı önce Jinja2 üzerinden geçirir ve sonucu aktarır. Modül kaynağı, template için "tamamen bir eylem eklentisi olarak uygulanan ve kontrolcü üzerinde çalışan sanal bir modül" tanımını yapar; bu durumun unutulmaması gereken bir sonucu vardır: işleme süreci, ansible-playbook komutunu girdiğiniz makinede gerçekleşir. Hedef sunucu değişkenlerinizi hiçbir zaman görmez ve Jinja2'nin kurulu olmasına ihtiyaç duymaz.
Dosya her sunucuda aynı olduğunda copy kullanın. Her sunucu için bir değer farklılaştığında veya bir {% for %} döngüsüne ya da {% if %} bloğuna ihtiyaç duyduğunuzda template kullanın. copy modülünün bir content: parametresi vardır ve içindeki değişkenler diğer görev argümanları gibi işlenir; ancak bu modülde döngü veya koşullu ifadeler bulunmaz. Bu nedenle yapısal gereksinimler içeren her şey template modülüne aittir. Her iki modül de aynı dosya seçeneklerini kabul eder çünkü her ikisi de aynı dokümantasyon parçalarını kullanır; bu nedenle owner, group, mode, backup ve validate her iki modülde de aynı şekilde davranır.
Şablonu yazın: bir değişken, bir döngü
Bunu templates/app.conf.j2 olarak kaydedin:
# {{ ansible_managed }}
upstream {{ app_name }}_backend {
{% for backend in app_backends %}
server {{ backend.host }}:{{ backend.port }} weight={{ backend.weight }};
{% endfor %}
}
server {
listen {{ app_listen_port }};
server_name {{ app_server_name }};
location / {
proxy_pass http://{{ app_name }}_backend;
proxy_set_header Host $host;
}
}Burada işi iki tür Jinja2 etiketi yapar. {{ ... }} bir ifadedir ve değerini yazdırır. {% ... %} bir komuttur ve kendi başına hiçbir şey yazdırmaz. app_backends bir sözlük listesidir, bu nedenle backend.host her girdiden bir anahtarı okur ve döngü, siz kaç tane tanımlarsanız tanımlayın, girdi başına bir server satırı yazar.
Boşluk karakterleri hakkında bir detay, çünkü bu durum Jinja2'yi başka yerlerden bilenleri şaşırtır. Ansible, trim_blocks değerini varsayılan olarak yes olarak ayarlar; Jinja2'nin kendisi bunu yapmaz. Bu nedenle, bir {% ... %} etiketinden hemen sonra gelen yeni satır kaldırılır ve döngü arkasında boş bir satır bırakmaz. Ansible, lstrip_blocks değerini no olarak bırakır, bu yüzden bir {% etiketinin önüne koyduğunuz tüm boşluklar korunur ve oluşturulan dosyada görünür. Çıktınızda istenmeyen girintiler oluşursa, şablon görevinde lstrip_blocks: true ayarını yapın.
{{ ansible_managed }} varsayılan olarak Ansible managed metni şeklinde oluşturulur. Bunu bu şekilde bırakın. İnsanlar genellikle ansible_managed değerini bir tarih içerecek şekilde ansible.cfg içinde yeniden tanımlarlar; bunu yaptıkları anda, oluşturulan dosya her çalıştırıldığında farklılaşır, görev her çalıştırıldığında bir değişiklik bildirir ve servis her çalıştırıldığında yeniden yüklenir. Bu tek ayar, bu kılavuzun geri kalanının üzerine inşa edildiği özelliği yok eder. .j2 uzantısı bir gelenektir ve Ansible bunu kontrol etmez.
Playbook
Bunu site.yml olarak kaydedin:
- name: Render an nginx site from a template
hosts: local
become: true
vars:
app_name: learn
app_listen_port: 8080
app_server_name: learn.example.com
app_backends:
- host: 127.0.0.1
port: 9001
weight: 3
- host: 127.0.0.1
port: 9002
weight: 1
tasks:
- name: Install nginx
ansible.builtin.apt:
name: nginx
state: present
update_cache: true
cache_valid_time: 3600
- name: Render the site configuration
ansible.builtin.template:
src: templates/app.conf.j2
dest: "/etc/nginx/conf.d/{{ app_name }}.conf"
owner: root
group: root
mode: '0644'
backup: true
notify: nginx config changed
- name: Make sure nginx is enabled and running
ansible.builtin.service:
name: nginx
state: started
enabled: true
handlers:
- name: Test the nginx configuration
ansible.builtin.command:
cmd: /usr/sbin/nginx -t
changed_when: false
listen: nginx config changed
- name: Reload nginx
ansible.builtin.service:
name: nginx
state: reloaded
listen: nginx config changedmode: '0644' kasten tırnak içine alınmıştır. Dosya seçenekleri dokümantasyonu, Ansible'ın bir dizge alıp kendi dönüşümünü yapabilmesi için sekizlik sayıların tırnak içine alınmasını belirtir. Tırnak kullanılmadığında, YAML ayrıştırıcısı 0644 ifadesini düz bir sayı olarak okur ve sonuçta istenmeyen izinlerle karşılaşabilirsiniz.
notify: nginx config changed bir handler değil, bir konu başlığı belirtir. Her iki handler da listen: nginx config changed içerir, bu nedenle tek bir notify her ikisini de tetikler. Daha sonra aynı listen satırına sahip üçüncü bir handler eklerseniz, şablon görevinin düzenlenmesine gerek kalmaz. cache_valid_time: 3600, bir saat içinde ikinci bir çalıştırmanın paket yansımalarına tekrar gitmesini engeller.
Bir kez çalıştırın ve çıktısını okuyun
ansible-playbook site.ymlEğer sudo parolanızı sorarsa -K ekleyin; Ansible parolanızı isteyecektir.
Önce görev bazlı satırları, ardından en alttaki PLAY RECAP kısmını okuyun. Her görev, Ansible bir işlem yaptığında changed:, sunucu zaten istenen durumdaysa ok: çıktısı verir; özet kısmı ise bu sayaçları sunucu bazında toplar. Play içindeki her görev tamamlandıktan hemen sonra, bir an bile önce değil, RUNNING HANDLER [Test the nginx configuration] ve ardından RUNNING HANDLER [Reload nginx] bilgisini alırsınız.
Şimdi çıktıya güvenmek yerine makinenin kendisini kontrol edin:
sudo cat /etc/nginx/conf.d/learn.conf
sudo /usr/sbin/nginx -t
curl -sI http://127.0.0.1:8080/nginx -t, birleştirilmiş yapılandırma ayrıştırıldığında nginx: configuration file /etc/nginx/nginx.conf test is successful çıktısını verir. curl, nginx'ten bir durum satırı döndürür; sunucu bloğu canlı olduğu ve 9001 ya da 9002 numaralı portlarda herhangi bir dinleme olmadığı için burada doğru cevap 502 Bad Gateway olacaktır. sudo tail /var/log/nginx/error.log, nedeni açık bir dille belirtir: connect() failed (111: Connection refused) while connecting to upstream.
İdempotency durumunu kanıtlamak için ikinci kez çalıştırın
ansible-playbook site.ymlBu, asıl önemli olan çalıştırma aşamasıdır; bu nedenle çıktısını ilk çalıştırmayla satır satır karşılaştırın. Şablon görevi, daha önce changed: yazdırdığı yerde artık ok: yazdırmalı ve hiçbir handler çıktıda görünmemelidir.
Mekanizma basittir ve hata ayıklama sürecinde temel teşkil ettiği için bilinmesi gerekir. template, dosyayı kontrolcü üzerinde oluşturur ve sonucun sağlama toplamını (checksum), dest konumunda hâlihazırda bulunan dosyanın sağlama toplamıyla karşılaştırır. İçerik, sahiplik ve izinler eşleşiyorsa yapılacak bir işlem yoktur; bu nedenle görev ok rapor eder, notify tetiklenmez ve dolayısıyla handler çalışmaz. Handler'lar yalnızca changed durumunda tetiklenir, başka hiçbir durumda çalışmazlar.
Diğer yönü de doğrulayın. vars içindeki weight: 3 değerini weight: 1 olarak değiştirin ve play'i tekrar çalıştırın; şablon görevi changed rapor edecek, her iki handler çalışacak ve sudo cat /etc/nginx/conf.d/learn.conf yeni değeri gösterecektir.
Eğer ikinci bir özdeş çalıştırma hâlâ bir değişiklik rapor ediyorsa, oluşturulan çıktı kararlı (stable) değildir. Öncelikle çıktı içerisinde zamana bağlı bir değişken olup olmadığını kontrol edin; bu yaygın bir nedendir ve genellikle özelleştirilmiş bir ansible_managed bu soruna yol açar. Ardından, görev üzerindeki mode ve owner değerlerinin diskteki gerçek değerlerle eşleştiğinden emin olun; çünkü baytlar aynı olsa bile bir uyumsuzluk değişiklik olarak algılanır.
Değişiklik yapmadan önce sonucu görün
ansible-playbook site.yml --check --diff--check, ana makinede herhangi bir değişiklik yapmadan playbook'u çalıştırır. --diff, her bir görevin neleri değiştireceğini listeler; template için bu, oluşturulan çıktı ile diskteki dosya arasındaki satır bazlı farktır. Bu iki seçenek birlikte, "bu komut çalıştırılsaydı ne olurdu" sorusunu, herhangi bir işlem yapmadan yanıtlar. Check mode'un kendine has riskleri vardır; bu durum özellikle, sonucu check mode'un aslında gerçekleştirmediği önceki bir göreve bağlı olan görevlerde ortaya çıkar.
Handler'ların neden play sonuna kadar beklediği
Handler dokümantasyonu bu konuda oldukça nettir: "Varsayılan olarak handler'lar, belirli bir play içerisindeki tüm görevler tamamlandıktan sonra çalışır. Bildirilen handler'lar, aşağıdaki bölümlerin her birinden sonra, belirtilen sırayla otomatik olarak yürütülür: pre_tasks, roles/tasks ve post_tasks."
Bunun nedeni toplu işlemedir (batching). Bir servis için dört farklı yapılandırma dosyası oluşturan bir play, servisi dört kez değil, tüm dosyalar yerleştirildikten sonra, en sonda bir kez yeniden başlatmalıdır. Her dosyadan sonra yeniden başlatma yapmak servisi dört kez başlatmaya neden olur ve bu başlatmaların üçü yarım kalmış bir yapılandırmayı yükler. Aynı sayfa, garantiyi açıkça belirtir: "Aynı handler'ın birden fazla kez bildirilmesi, kaç görev tarafından bildirilirse bildirilsin, handler'ın yalnızca bir kez yürütülmesiyle sonuçlanır."
Sıralama da sabittir: "Handler'lar, notify ifadesinde listelendikleri sırayla değil, handlers bölümünde tanımlandıkları sırayla yürütülür." İşte bu yüzden Test the nginx configuration, playbook içerisinde Reload nginx'ün üzerinde yer alır. Test ilk sırada yazıldığı için ilk önce çalışır ve notify satırındaki hiçbir şey bunu etkilemez.
İşleyicileri erken çalıştırma ve hata sonrası çalıştırma yöntemleri
Bazen aynı oyun (play) içerisindeki sonraki bir görevin, yeni yapılandırmayı çalıştıran servise ihtiyacı olur. Bu noktada bildirilmiş işleyicileri (handlers) meta modülü ile çalıştırın; belgelerde bu modülün "Ansible'ın o ana kadar bildirilmiş tüm işleyici görevlerini çalıştırmasını sağladığı" belirtilmektedir.
- name: Run the notified handlers now instead of at the end of the play
ansible.builtin.meta: flush_handlers
- name: Wait for the new listener to accept connections
ansible.builtin.wait_for:
host: 127.0.0.1
port: 8080
timeout: 10meta satırını kaldırdığınızda, wait_for görevi nginx hala eski yapılandırmayı sunarken çalışır. İlk çalıştırmada 8080 numaralı portta henüz hiçbir dinleyici (listener) bulunmadığından, görev tam on saniye bekler ve ardından başarısız olur.
İkinci durum ise hata halidir. "Bir görev bir işleyiciyi tetikler ancak oyunun ilerleyen kısımlarında başka bir görev başarısız olursa, varsayılan olarak işleyici o sunucuda çalışmaz; bu durum sunucuyu beklenmedik bir halde bırakabilir." Bir yapılandırmayı oluşturan ve ardından ilgisiz bir görevde takılan oyun, yeni dosyayı diskte bırakırken çalışan serviste eski yapılandırmayı yüklü tutar. Bunu, komut satırında --force-handlers ile veya oyun içerisinde force_handlers: true ile geçersiz kılın. Aynı anahtar ansible.cfg içerisindeki [defaults] altında force_handlers = True olarak ve ANSIBLE_FORCE_HANDLERS ortam değişkeni olarak da mevcuttur. Varsayılan değer False şeklindedir.
İşleyici isimleri çakışıyor ve kaybeden sessiz kalıyor
Belgeler kuralı şu şekilde belirtir: "Her işleyicinin (handler) küresel olarak benzersiz bir isme sahip olması gerekir. Aynı isimle birden fazla işleyici tanımlanırsa, yalnızca play içerisine yüklenen sonuncusu bildirilebilir ve çalıştırılabilir." Bir rolün içinde tanımlanan işleyiciler, o role özgü kapsamda da değildir. Bu işleyiciler, tüm play için tek bir küresel işleyici listesine eklenir; dolayısıyla her biri Restart nginx tanımlayan iki rolünüz olduğunda, isim tam olarak bunlardan birine çözümlenir ve bildirimde bulunduğunuz rol değil, yükleme sırası hangisinin çalışacağını belirler.
Buna güvenmeden önce kuralı test edin. Bunu handlers-dup.yml olarak kaydedin:
- name: Two handlers, one name
hosts: local
gather_facts: false
tasks:
- name: Notify the duplicated name
ansible.builtin.command:
cmd: /bin/true
changed_when: true
notify: Duplicated handler
handlers:
- name: Duplicated handler
ansible.builtin.file:
path: /tmp/dup-first
state: touch
mode: '0644'
- name: Duplicated handler
ansible.builtin.file:
path: /tmp/dup-second
state: touch
mode: '0644'rm -f /tmp/dup-first /tmp/dup-second
ansible-playbook handlers-dup.yml
ls -l /tmp/dup-first /tmp/dup-secondPlay başarılı olur, RUNNING HANDLER [Duplicated handler] bir kez görünür ve ls, /tmp/dup-first için bir satır, diğeri için ise ls: cannot access '/tmp/dup-second': No such file or directory yazdırır. Çalışan işleyici, belgelerdeki cümlenin öngördüğünün aksine, yüklenen sonuncu değil, ilk yazılan işleyicidir.
Bu farkı anlamak önemlidir, çünkü belgelenen kural dosyadaki satırlardan ziyade işleyici blokları ile ilgilidir. Farklı yerlerden, önce bir rol ve sonra diğeri olmak üzere gelen işleyiciler ayrı bloklardır ve sonraki blok, önceki bloğu gölgeler (shadowing). Bir play içindeki düz bir handlers: listesi tek bir bloktur ve blok içindeki arama yukarıdan aşağıya doğru çalışır ve eşleşen ilk isimde durur. Dolayısıyla tek bir dosya içinde ilk tanım yanıt verir ve ikincisine ulaşılamaz; roller arasında ise gölgeleme belgelerde açıklandığı gibi çalışır. Her iki durumda da ikisine birden asla ulaşamazsınız ve hiçbir yöntem üzerine inşa edilecek kadar güvenilir değildir.
Bu durumdan kurtulmanın iki temiz yolu vardır. Her işleyici ismine rolüne özgü bir önek verin veya belgelerde "bir rolden gelen işleyicinin, aynı isme sahip rol dışındaki bir işleyicinin aksine bildirilmesini sağlamak" için belirtilen role_name : handler_name nitelikli biçimini kullanın. İki nokta üst üste işaretinin etrafındaki boşluklar bu sözdiziminin bir parçasıdır. Bu durum, siz yazmadığınız rolleri kullanmaya başladığınız anda canlı bir sorun haline gelir.
Aynı sayfadan bir kural daha: "İşleyici isminde değişken kullanmaktan kaçının. İşleyici isimleri erken aşamada şablonlandığı için, Ansible böyle bir işleyici ismi için bir değere sahip olmayabilir." Restart {{ service_name }} olarak adlandırılan bir işleyici, isim şablonlandığı sırada değişken tanımlı değilse tüm play'in başarısız olmasına neden olur. İşleyici isimlerini sabit dizeler olarak tutmak ve bunları listen ile gruplandırmak bu sorunu ortadan kaldırır.
doğrulama: bozuk bir render dosyasının yüklenmesini reddetme
validate, Ansible dosyayı nihai hedefine taşımadan önce render edilmiş dosya üzerinde bir komut çalıştırır. Dokümantasyon şu şekildedir: "Güncellenmiş dosya nihai hedefine kopyalanmadan önce çalıştırılacak doğrulama komutu. Doğrulama için geçici bir dosya yolu kullanılır ve bu yol, aşağıdaki örneklerde olduğu gibi mutlaka bulunması gereken %s aracılığıyla aktarılır. Ayrıca komut güvenli bir şekilde iletilir; bu nedenle genişletme (expansion) ve boru hatları (pipes) gibi kabuk özellikleri çalışmayacaktır."
Bu metinden doğrudan iki kural çıkar. %s zorunludur ve bu ifadeyi içermeyen bir doğrulama dizisi, görevin validate must contain %s hatasıyla başarısız olmasına neden olur. Ayrıca kabuk (shell) ortamı yoktur; bu nedenle boru hatları, yönlendirme, globbing ve && çalışmaz. Tek komut, tek dosya argümanı.
Resmi modül örnekleri, bu işlemin mükemmel şekilde çalıştığı iki durumu gösterir:
- name: Copy a new sudoers file into place, after passing validation with visudo
ansible.builtin.template:
src: /mine/sudoers
dest: /etc/sudoers
validate: /usr/sbin/visudo -cf %s
- name: Update sshd configuration safely, avoid locking yourself out
ansible.builtin.template:
src: etc/ssh/sshd_config.j2
dest: /etc/ssh/sshd_config
owner: root
group: root
mode: '0600'
validate: /usr/sbin/sshd -t -f %s
backup: yesHer iki örnek de çalışır çünkü her denetleyici tek bir dosyayı okur ve kendi kurallarına göre değerlendirir. visudo -cf bir sudoers dosyasını okur. sshd -t -f ise tam bir sshd_config dosyasını okur.
Neden doğrulama işlemi bu rehberdeki nginx dosyasını kontrol edemiyor
Yukarıdaki şablon görevine validate: /usr/sbin/nginx -t -c %s eklediğinizde görev başarısız olur. Hata mesajı nedenini belirtir:
nginx: [emerg] "upstream" directive is not allowed here in <ansible temporary path>:2nginx -t -c, en üst seviyede events ve http blokları ile başlayan bütün bir yapılandırma bekler. Bu playbook tarafından oluşturulan dosya, /etc/nginx/nginx.conf içindeki include /etc/nginx/conf.d/*.conf; ile http bloğuna çekilen bir parçadır. Kendi başına, bu bağlamın dışında ele alındığında upstream gerçekten yanlış yerdeki bir direktiftir; bu nedenle nginx, aslında bulunduğu yerde tamamen doğru olan bir dosyayı reddeder. Denetleyiciye bir parça verilmiş ve bunu bütün bir yapılandırma olarak ele alması istenmiştir.
Uygulanabilir çözüm, playbook içinde halihazırda bulunan yöntemdir. Parçayı yükleyin, ardından yeniden yükleme (reload) işleyicisinin üzerinde tanımlanan bir işleyicide birleştirilmiş yapılandırmayı kontrol edin. İşleyiciler tanımlandıkları sırayla çalıştıkları için nginx -t, parçanızın dahil edildiği gerçek /etc/nginx/nginx.conf dosyasını görür ve oradaki bir hata, systemctl reload çağrılmadan önce playbook'u durdurur. Maliyet konusunda net olun: bu kontrol başarısız olduğunda bozuk dosya diskte kalır ve nginx, biri onu yeniden başlatana kadar yüklediği son yapılandırmayı sunmaya devam eder.
backup: true bu noktada önem kazanır. Üzerine yazmadan önce orijinal dosyanın bir kopyasını basename.PID.YYYY-MM-DD@HH:MM:SS~ adıyla yanına kaydeder, böylece dizinde learn.conf.4127.2026-08-20@11:42:09~ gibi girdiler oluşur. Bir değişiklikten sonra sudo ls -l /etc/nginx/conf.d/ komutunu çalıştırırsanız bir tane bulabilirsiniz.
Bu isimlendirme detayı göründüğünden daha önemlidir. Yedek dosya /etc/nginx/conf.d/ içinde zararsızdır çünkü ana yapılandırma yalnızca conf.d/*.conf dosyasını içerir ve yedek dosya adı tilde işaretiyle biter. Ancak doğrudan * ile dahil edilen bir dizinde bu durum zararsız değildir; Debian ve Ubuntu üzerinde /etc/nginx/nginx.conf, /etc/nginx/sites-enabled/* dizinini tam olarak bu şekilde dahil eder. backup: true ile sites-enabled dizinine şablon oluşturursanız, nginx yedek dosyayı ikinci bir canlı sunucu bloğu olarak yükler; bu playbook'un conf.d dizinine yazmasının nedeni budur.
Aynı play'i gerçek envanter sunucularında çalıştırma
hosts: local değerini kullandığınız grup adıyla değiştirin; play içindeki başka hiçbir şeyi değiştirmeniz gerekmez. Şablon her host için bir kez oluşturulur, bu nedenle app_listen_port ve app_backends değerleri group_vars ve host_vars içinden gelebilir; şablon dosyasının kendisi ise tek kalır. Değerleri dosya içine gömmek yerine değişkenlere atamanın sağladığı avantaj budur.
İki şey değişir. become: true artık her hedefte sudo parolası gerektirir; parolasız sudo yapılandırmanız yoksa -K bayrağını ekleyin. Ayrıca şablondaki veritabanı parolası veya API anahtarı gibi hiçbir gizli bilgi, commit ettiğiniz bir dosyada düz metin (vars:) olarak bulunmamalıdır. Bu değerleri Ansible Vault ile şifreleyin ve tıpkı şu an yaptığınız gibi isimleriyle referans verin; çünkü şablon, değişkenin nereden geldiğiyle ilgilenmez.
Play, tek bir servisin ötesine geçip büyüdüğünde vars:, templates/ ve handlers: için zaten hazır bekleyen standart bir dizin yapısı mevcuttur. Bunları ilgili yerlere taşımak, playbook ve role ayrımının temel amacını oluşturur.
FAQ
Ansible handler neden çalışmadı?
Bunun nedeni neredeyse her zaman, onu tetikleyen görevin changed yerine ok rapor etmesidir. Handler'lar yalnızca bir değişiklik olduğunda çalışır; bu nedenle, oluşturulan içerik diskteki dosya ile aynıysa, template görevi hiçbir şeyi tetiklemez. Bu durumdan sonra dört noktayı kontrol edin. notify içindeki ifade, handler name veya listen konusu ile büyük/küçük harf ve boşluklar dahil olmak üzere tam olarak eşleşmelidir. O host üzerinde başarısız olan sonraki bir görev, --force-handlers parametresini kullanmadığınız sürece tetiklenen handler'ları engeller. Farklı bir play içinde tanımlanan bir handler, bu play içinden görünmez. Ayrıca, bir when koşulu ile atlanan bir görev hiçbir zaman tetikleme yapmaz.
Playbook neden her çalıştırıldığında changed rapor ediyor?
Oluşturulan metin, çalıştırmalar arasında kararlı değildir. En yaygın neden, çıktı içindeki bir zaman damgasıdır; tarih içeren özelleştirilmiş bir ansible_managed dizisi tam olarak buna neden olur. Kontrol edilmesi gereken bir sonraki şey, görev üzerindeki mode ve owner değerleridir: eğer bunlar diskteki dosya ile eşleşmiyorsa, Ansible bunları düzeltir ve içerik aynı olsa bile bir değişiklik rapor eder. Hangisinin olduğunu görmek için ansible-playbook site.yml --check --diff komutunu çalıştırın, çünkü --diff görevin yapmayı amaçladığı farkı size gösterir.
Ansible'da template ve copy arasındaki fark nedir?
ansible.builtin.copy bir dosyayı değiştirmeden gönderir. ansible.builtin.template ise dosyayı önce controller üzerinde Jinja2 ile işler ve sonucu gönderir; böylece değişkenler ve döngüler dosya hedef hosta ulaşmadan önce çözümlenmiş olur. Her yerde bayt düzeyinde aynı olan dosyalar için copy kullanın. Host bazında değişen her şey için template kullanın. Her iki modül de aynı dosya seçeneklerini paylaşır, bu nedenle mode, owner, backup ve validate her ikisinde de aynı şekilde çalışır.
Bir handler'ı play'in ortasında nasıl çalıştırabilirim?
Çalışmalarını istediğiniz noktaya bir görev olarak ansible.builtin.meta: flush_handlers ekleyin. Bu, o ana kadar tetiklenen tüm handler'ları çalıştırır ve ardından play normal şekilde devam eder. Aynı play içindeki sonraki bir görevin, yeni yapılandırmayı çalıştıran servise bağlı olduğu durumlarda (örneğin, yeniden yüklemeden sonra var olan bir port üzerinde wait_for yapılması gibi) bunu kullanın. Bu, bir handler'ı play'in sonundan önce çalıştırmanın desteklenen yoludur.
Nginx yapılandırma parçası ile validate kullanabilir miyim?
nginx -t -c %s ile kullanamazsınız. Bu komut, en üst düzey events ve http bloklarıyla başlayan tam bir yapılandırma bekler; bu nedenle conf.d parçasını "upstream" directive is not allowed here gibi bir mesajla reddeder. Parça, http bloğu içinde geçerlidir ancak tek başına geçersizdir. Dosyayı yükleyin, ardından yeniden yükleme handler'ının üzerinde tanımlanan bir handler içinde birleştirilmiş yapılandırmaya karşı nginx -t komutunu çalıştırın. Handler'lar tanımlandıkları sırayla çalışır; bu nedenle hatalı bir yapılandırma, yeniden yükleme denenmeden önce play'i başarısız kılar. Önceki dosyanın geri yüklenebilmesi için template görevi üzerinde backup: true ayarını yapın.