SSD Nodes Learn Hosting plans →
Gidsen Matt ConnorDoor Matt Connor · Bijgewerkt 2026-10-05

Ansible templates en handlers gebruiken: een voorbeeld

Leer hoe u een nginx configuratie rendert met Jinja2 en een handler inzet voor idempotente service herstarts. Zie in dit voorbeeld hoe u wijzigingen efficiënt doorvoert.

Verified Every command ran end-to-end on a fresh Ubuntu 24.04 server, August 20, 2026.

Wat Ansible-templates en -handlers toevoegen aan uw eerste playbook

Ansible-templates en -handlers zijn de twee onderdelen die een statisch playbook veranderen in een nuttig hulpmiddel. Een template genereert een configuratiebestand op basis van uw variabelen, waardoor één bestand volstaat voor elke host. Een handler wordt alleen uitgevoerd wanneer een taak daadwerkelijk iets heeft gewijzigd. Hierdoor wordt de service alleen herladen bij een daadwerkelijke configuratiewijziging en blijft deze de rest van de tijd ongemoeid.

Deze handleiding gaat verder waar uw eerste Ansible-playbook op een VPS ophield. U heeft al een play die een pakket installeert en een service start. Alles hieronder wordt uitgevoerd op één machine, omdat de play zich richt op localhost via een lokale verbinding. U heeft geen tweede server nodig om dit te volgen. Dezelfde play werkt op echte inventory-hosts zonder wijzigingen aan de taken, en de laatste sectie behandelt wat er wel verandert.

De werkmap instellen

sudo apt update
sudo apt install -y ansible nginx
ansible --version
mkdir -p ~/ansible-templates/templates
cd ~/ansible-templates

nginx wordt hier enkel gebruikt omdat het een echte service is met een configuratiebestand en een reload-commando; dit is alles wat het voorbeeld nodig heeft. ansible --version toont de versie van ansible-core en de Python-interpreter die zal worden gebruikt. Noteer beide. Het onderstaande playbook gebruikt volledig gekwalificeerde modulenamen zoals ansible.builtin.template, waarvoor Ansible 2.10 of nieuwer vereist is; elk actueel distributiepakket voldoet hier ruimschoots aan.

Maak inventory.ini aan:

[local]
localhost ansible_connection=local ansible_python_interpreter="{{ ansible_playbook_python }}"

ansible_connection=local instrueert Ansible om elke taak als een lokaal proces uit te voeren in plaats van een SSH-sessie naar zichzelf te openen. De tweede instelling is geen overbodige luxe. Wanneer u localhost in een inventory-bestand schrijft, wordt het een gewone host en verliest het de interpreter die Ansible standaard aan de impliciete localhost toewijst. Hierdoor valt het terug op interpreter-detectie en kan het een andere Python-versie kiezen dan degene die de play uitvoert. ansible_playbook_python is de interpreter die op dit moment ansible-playbook uitvoert, wat ervoor zorgt dat beide op één lijn blijven.

Maak ansible.cfg aan:

[defaults]
inventory = inventory.ini

Zonder dat bestand moet u bij elk commando -i inventory.ini opgeven. Zonder inventory geeft Ansible [WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all' weer, en een play met hosts: all komt dan met niets overeen. Nog één punt over ansible.cfg: Ansible negeert het bestand als het in een map staat die voor iedereen schrijfbaar is; bewaar het project daarom in uw home-map. Een inventory-bestand bevat meer dan alleen een lijst met hosts, en dit is de kleinst mogelijke variant die aan de vereisten voldoet.

template versus copy, en wanneer u welke gebruikt

ansible.builtin.copy verplaatst een bestand zoals het is. ansible.builtin.template haalt het bestand eerst door Jinja2 en verplaatst het resultaat. De module-broncode beschrijft template als "een virtuele module die volledig is geïmplementeerd als een action plugin en op de controller draait", en dat heeft een consequentie die u moet onthouden: het renderen gebeurt op de machine waar u ansible-playbook hebt getypt. De doelhost ziet nooit uw variabelen en hoeft Jinja2 niet geïnstalleerd te hebben.

Gebruik copy wanneer het bestand op elke host identiek is. Gebruik template zodra één waarde per host verschilt, of wanneer u een {% for %} loop of een {% if %} block nodig hebt. copy heeft wel een content: parameter, en variabelen daarin worden vervangen zoals bij elk ander taakargument, maar er zijn daar geen loops en geen conditionals, dus alles met structuur hoort in een template thuis. Beide modules gebruiken dezelfde bestandsopties, omdat beide dezelfde documentatiefragmenten ophalen, dus owner, group, mode, backup en validate gedragen zich in beide gevallen op dezelfde manier.

Schrijf het template: één variabele, één loop

Sla dit op als templates/app.conf.j2:

# {{ 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;
    }
}

Twee soorten Jinja2-tags voeren hier het werk uit. {{ ... }} is een expressie en drukt de waarde ervan af. {% ... %} is een statement en drukt zelf niets af. app_backends is een lijst met dictionaries, dus backend.host leest één key uit elk item, en de loop schrijft één server-regel per item, ongeacht hoeveel u er definieert.

Eén detail over de witruimte, omdat dit mensen verrast die Jinja2 uit andere contexten kennen. Ansible stelt trim_blocks standaard in op yes, wat Jinja2 zelf niet doet. Hierdoor wordt de nieuwe regel direct na een {% ... %}-tag verwijderd en laat de loop geen lege regel achter. Ansible laat lstrip_blocks op no staan, dus alle spaties die u voor een {%-tag plaatst, blijven behouden en verschijnen in het gegenereerde bestand. Als uw output ongewenste inspringing bevat, stel dan lstrip_blocks: true in op de template-taak.

{{ ansible_managed }} wordt standaard gerenderd als de letterlijke tekst Ansible managed. Laat dit zo. Mensen herdefiniëren ansible_managed vaak in ansible.cfg om een datum toe te voegen, en zodra ze dat doen, verschilt het gegenereerde bestand bij elke uitvoering, rapporteert de taak bij elke uitvoering een wijziging en herlaadt de service bij elke uitvoering. Die ene instelling vernietigt de eigenschap waar de rest van deze handleiding over gaat. De .j2-extensie is een conventie en Ansible controleert deze niet.

Het playbook

Sla dit op als site.yml:

- 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 changed

mode: '0644' staat bewust tussen aanhalingstekens. De documentatie voor bestandsopties stelt dat octale getallen tussen aanhalingstekens moeten staan "zodat Ansible een string ontvangt en zelf de conversie van string naar getal kan uitvoeren". Zonder aanhalingstekens leest de YAML-parser 0644 als een gewoon getal, waardoor u mogelijk andere rechten krijgt dan u had beoogd.

notify: nginx config changed benoemt een onderwerp, geen handler. Beide handlers bevatten listen: nginx config changed, dus één notify bereikt ze allebei. Voeg later een derde handler toe met dezelfde listen-regel en de template-taak hoeft niet te worden aangepast. cache_valid_time: 3600 voorkomt dat een tweede uitvoering binnen hetzelfde uur opnieuw verbinding maakt met de pakket-mirrors.

Voer het eenmaal uit en lees de uitvoer

ansible-playbook site.yml

Als uw sudo om een wachtwoord vraagt, voeg dan -K toe en Ansible zal hierom vragen.

Lees eerst de regels per taak en daarna de PLAY RECAP onderaan. Elke taak toont changed: wanneer Ansible een actie moest uitvoeren, of ok: wanneer de host zich al in de gewenste staat bevond. De samenvatting telt deze counters per host op. Nadat elke taak in de play is voltooid, en geen moment eerder, krijgt u RUNNING HANDLER [Test the nginx configuration] gevolgd door RUNNING HANDLER [Reload nginx].

Controleer nu de machine zelf in plaats van op de uitvoer te vertrouwen:

sudo cat /etc/nginx/conf.d/learn.conf
sudo /usr/sbin/nginx -t
curl -sI http://127.0.0.1:8080/

nginx -t toont nginx: configuration file /etc/nginx/nginx.conf test is successful wanneer de samengestelde configuratie correct wordt geparseerd. De curl geeft een statusregel terug van nginx, en 502 Bad Gateway is hier het juiste antwoord, omdat het serverblok actief is en er niets luistert op poort 9001 of 9002. sudo tail /var/log/nginx/error.log vermeldt de reden in duidelijke bewoordingen: connect() failed (111: Connection refused) while connecting to upstream.

Voer het een tweede keer uit om de idempotentie te bewijzen

ansible-playbook site.yml

Dit is de uitvoering die ertoe doet; vergelijk de uitvoer regel voor regel met de eerste keer. De template-taak zou nu ok: moeten weergeven waar deze voorheen changed: toonde, en geen van beide handlers zou in de uitvoer moeten verschijnen.

Het mechanisme is eenvoudig en essentieel om te kennen, omdat u hierop debugt. template rendert het bestand op de controller en vergelijkt de checksum van het resultaat met de checksum van het bestand dat zich al op dest bevindt. Bij overeenkomende inhoud, eigenaarschap en rechten is er niets te doen, dus rapporteert de taak ok. Hierdoor wordt notify nooit geactiveerd en draait de handler niet. Handlers worden alleen geactiveerd bij changed en verder nergens door.

Bewijs ook de andere richting. Wijzig weight: 3 naar weight: 1 in vars, voer de play opnieuw uit; de template-taak rapporteert nu changed, beide handlers draaien en sudo cat /etc/nginx/conf.d/learn.conf toont de nieuwe waarde.

Als een tweede identieke uitvoering nog steeds een wijziging rapporteert, is de rendering niet stabiel. Zoek eerst naar tijdsafhankelijke elementen in de uitvoer, aangezien dit de meest voorkomende oorzaak is en een aangepaste ansible_managed meestal de boosdoener is. Controleer daarna of mode en owner op de taak overeenkomen met wat er daadwerkelijk op de schijf staat, omdat een mismatch daar een wijziging vormt, zelfs als de bytes identiek zijn.

Bekijk een wijziging voordat u deze doorvoert

ansible-playbook site.yml --check --diff

--check voert de play uit zonder de host te wijzigen. --diff toont wat elke taak zou hebben aangepast, wat voor template neerkomt op een regel-voor-regel verschil tussen de gegenereerde output en het bestand op de schijf. Samen beantwoorden ze de vraag "wat zou deze uitvoering doen" zonder actie te ondernemen. Check mode heeft zijn eigen beperkingen, voornamelijk bij taken waarvan het resultaat afhangt van een eerdere taak die in check mode niet daadwerkelijk is uitgevoerd.

Waarom handlers wachten tot het einde van de play

De documentatie over handlers is hierover duidelijk: "Standaard worden handlers uitgevoerd nadat alle taken in een specifieke play zijn voltooid. Aangeroepen handlers worden automatisch uitgevoerd na elk van de volgende secties, in de volgende volgorde: pre_tasks, roles/tasks en post_tasks."

De reden hiervoor is batching. Een play die vier configuratiebestanden voor één service genereert, moet die service slechts één keer herstarten, aan het einde, wanneer alle vier de bestanden op hun plek staan. Herstarten na elk bestand zou leiden tot vier herstarts, waarbij drie van die herstarts een onvolledige configuratie zouden laden. Dezelfde pagina stelt de garantie expliciet: "Het meerdere keren aanroepen van dezelfde handler resulteert erin dat de handler slechts één keer wordt uitgevoerd, ongeacht hoeveel taken deze aanroepen."

De volgorde staat eveneens vast: "Handlers worden uitgevoerd in de volgorde waarin ze zijn gedefinieerd in de sectie handlers, niet in de volgorde waarin ze worden vermeld in de instructie notify." Daarom staat Test the nginx configuration boven Reload nginx in het playbook. De test wordt als eerste uitgevoerd omdat deze als eerste is geschreven, en niets in de regel notify heeft daar invloed op.

Handlers vroegtijdig uitvoeren en uitvoeren na een fout

Soms moet een latere taak in dezelfde play gebruikmaken van een service die al op de nieuwe configuratie draait. Forceer de uitvoering van aangemelde handlers op dat punt met de meta-module, die volgens de documentatie "Ansible alle handler-taken laat uitvoeren die tot dan toe zijn aangemeld".

    - 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: 10

Laat u die meta-regel weg, dan wordt de wait_for-taak uitgevoerd terwijl Nginx nog steeds de oude configuratie serveert. Bij een eerste uitvoering luistert er nog niets op poort 8080, waardoor de taak de volledige tien seconden wacht en vervolgens faalt.

Het tweede geval is een fout. "Als een taak een handler aanmeldt, maar een andere taak later in de play faalt, wordt de handler standaard niet uitgevoerd op die host. Dit kan de host in een onverwachte staat achterlaten." Een play die een configuratie genereert en vervolgens struikelt over een niet-gerelateerde taak, laat daardoor het nieuwe bestand op de schijf staan terwijl de oude configuratie nog in de actieve service is geladen. Overschrijf dit gedrag met --force-handlers op de opdrachtregel, of met force_handlers: true in de play. Dezelfde schakelaar bestaat als force_handlers = True onder [defaults] in ansible.cfg, en als de omgevingsvariabele ANSIBLE_FORCE_HANDLERS. De standaardwaarde is False.

Handler-namen conflicteren en de verliezer zwijgt

De documentatie stelt de volgende regel: "Elke handler moet een globaal unieke naam hebben. Als er meerdere handlers met dezelfde naam worden gedefinieerd, kan alleen de laatste die in de play wordt geladen, worden aangeroepen en uitgevoerd." Handlers die binnen een role zijn gedefinieerd, zijn bovendien niet beperkt tot die role. Ze worden ingevoegd in één globale handler-lijst voor de gehele play. Hierdoor resulteren twee roles die elk Restart nginx definiëren in een naam die naar slechts één van beide verwijst. De laadvolgorde bepaalt welke dit is, niet de role van waaruit u de melding verstuurt.

Test deze regel voordat u erop vertrouwt. Sla dit op als handlers-dup.yml:

- 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-second

De play slaagt, RUNNING HANDLER [Duplicated handler] verschijnt één keer en ls print een regel voor /tmp/dup-first en ls: cannot access '/tmp/dup-second': No such file or directory voor de andere. De handler die werd uitgevoerd is degene die als eerste is geschreven, niet degene die als laatste is geladen. Dit is het tegenovergestelde van wat de zin voorspelt.

Het is belangrijk om dit verschil te begrijpen, omdat de gedocumenteerde regel betrekking heeft op handler-blokken in plaats van op regels in een bestand. Handlers die uit verschillende bronnen komen, zoals de ene role na de andere, zijn afzonderlijke blokken, en een later blok overschaduwt inderdaad een eerder blok. Een eenvoudige handlers:-lijst in een play is echter één enkel blok. De zoekopdracht binnen een blok verloopt van boven naar beneden en stopt bij de eerste naam die overeenkomt. Binnen één bestand reageert dus de eerste definitie en is de tweede onbereikbaar, terwijl tussen roles de overschaduwing werkt zoals de documentatie beschrijft. In beide gevallen kunt u nooit beide bereiken, en geen van beide methoden is een solide basis om op te bouwen.

Er zijn twee nette oplossingen. Geef elke handler-naam een prefix die specifiek is voor de bijbehorende role, of gebruik de gekwalificeerde vorm role_name : handler_name. De documentatie geeft dit aan als de manier "om te garanderen dat een handler uit een role wordt aangeroepen in plaats van een handler van buiten de role met dezelfde naam". De spaties rond de dubbele punt maken deel uit van deze syntaxis. Dit wordt een acuut probleem zodra u roles gaat gebruiken die u niet zelf heeft geschreven.

Nog een regel van dezelfde pagina: "Vermijd het plaatsen van variabelen in de naam van de handler. Omdat handler-namen vroegtijdig worden getemplated, beschikt Ansible mogelijk niet over een waarde voor een handler-naam zoals deze." Een handler genaamd Restart {{ service_name }} laat de gehele play falen wanneer die variabele op het moment van templating niet is gedefinieerd. Door handler-namen als vaste strings te behouden en ze te groeperen met listen, omzeilt u dit probleem.

validate: weigeren om een defect render-bestand te installeren

validate voert een commando uit op het gerenderde bestand voordat Ansible het naar de definitieve locatie verplaatst. De documentatie stelt: "Het validatiecommando dat moet worden uitgevoerd voordat het bijgewerkte bestand naar de uiteindelijke bestemming wordt gekopieerd. Een tijdelijk bestandspad wordt gebruikt voor de validatie en wordt doorgegeven via %s, dat aanwezig moet zijn zoals in de onderstaande voorbeelden. Bovendien wordt het commando veilig doorgegeven, waardoor shell-functies zoals expansie en pipes niet werken."

Twee regels vloeien direct voort uit deze tekst. De %s is verplicht en een validate-string zonder deze parameter laat de taak falen met validate must contain %s. Daarnaast is er geen shell beschikbaar, dus pipes, redirectie, globbing en && werken niet. Eén commando, één bestandsargument.

De officiële modulevoorbeelden tonen de twee gevallen waarin dit perfect werkt:

- 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: yes

Beide voorbeelden werken omdat elke checker één bestand inleest en dit op eigen merites beoordeelt. visudo -cf leest een sudoers-bestand. sshd -t -f leest een volledige sshd_config.

Waarom validate het nginx-bestand in deze handleiding niet kan controleren

Voeg validate: /usr/sbin/nginx -t -c %s toe aan de bovenstaande template-taak en de taak faalt. Het bericht benoemt de oorzaak:

nginx: [emerg] "upstream" directive is not allowed here in <ansible temporary path>:2

nginx -t -c verwacht een volledige configuratie die op het hoogste niveau begint met events en http blokken. Het bestand dat deze play genereert is een fragment, dat in het http blok wordt getrokken door include /etc/nginx/conf.d/*.conf; binnen /etc/nginx/nginx.conf. Op zichzelf staand, buiten die context, is upstream inderdaad een directive op de verkeerde plek, waardoor nginx een bestand afwijst dat volledig correct is op de plek waar het daadwerkelijk thuishoort. De checker kreeg een fragment en werd gevraagd dit als een volledige configuratie te behandelen.

De werkbare oplossing is degene die al in de playbook staat. Installeer het fragment en controleer vervolgens de samengestelde configuratie in een handler die boven de reload-handler is gedefinieerd. Omdat handlers worden uitgevoerd in de volgorde waarin ze zijn gedefinieerd, ziet nginx -t de echte /etc/nginx/nginx.conf inclusief uw fragment, en een fout daar laat de play falen voordat systemctl reload ooit wordt aangeroepen. Wees u bewust van de consequentie: het defecte bestand staat op de schijf wanneer die controle faalt, en nginx blijft de laatst geladen configuratie serveren totdat iemand het herstart.

Dat is waar backup: true zijn waarde bewijst. Het schrijft een kopie van het vorige bestand naast het origineel voordat het wordt overschreven, genaamd basename.PID.YYYY-MM-DD@HH:MM:SS~, waardoor de map uiteindelijk items bevat zoals learn.conf.4127.2026-08-20@11:42:09~. Voer sudo ls -l /etc/nginx/conf.d/ uit na een wijziging en u zult er een vinden.

Dat naamgevingsdetail is belangrijker dan het lijkt. De back-up is onschadelijk in /etc/nginx/conf.d/ omdat de hoofdconfiguratie alleen conf.d/*.conf bevat en de back-upnaam eindigt op een tilde. Het is niet onschadelijk in een map die wordt ingesloten met een kale *, en op Debian en Ubuntu bevat /etc/nginx/nginx.conf /etc/nginx/sites-enabled/* precies op die manier. Template naar sites-enabled met backup: true en nginx laadt de back-up als een tweede live server-blok, wat de reden is dat deze play naar conf.d schrijft in plaats daarvan.

Dezelfde play uitvoeren op echte inventory-hosts

Wijzig hosts: local naar de groepsnaam die u gebruikt; verder hoeft er niets in de play te worden aangepast. De template wordt eenmaal per host gegenereerd, dus app_listen_port en app_backends kunnen afkomstig zijn van group_vars en host_vars, terwijl het templatebestand zelf ongewijzigd blijft. Dat is het voordeel van het plaatsen van waarden in variabelen in plaats van in het bestand zelf.

Er veranderen twee zaken. become: true vereist nu een sudo-wachtwoord op elke doelhost, tenzij u daar wachtwoordloze sudo heeft ingesteld; voeg daarom -K toe. Elk geheim in die template, zoals een databasewachtwoord of een API-token, mag niet in leesbare vars: in een bestand staan dat u commit. Versleutel deze waarden met Ansible Vault en verwijs ernaar op naam, precies zoals u nu doet, omdat het voor de template niet uitmaakt waar een variabele vandaan komt.

Wanneer de play groter wordt dan één service, hebben vars:, templates/ en handlers: al een standaardlocatie die op hen wacht. Het verplaatsen daarvan naar die locatie is precies het doel van de splitsing tussen een playbook en een role.

FAQ

Waarom werd mijn Ansible handler niet uitgevoerd?

Dit komt bijna altijd doordat de taak die de melding verstuurt ok rapporteerde in plaats van changed. Handlers worden alleen geactiveerd bij een wijziging. Een template-taak waarvan de gegenereerde output al overeenkomt met het bestand op de schijf, verstuurt daarom geen melding. Controleer daarnaast vier zaken. De string in notify moet exact overeenkomen met de handler name of een listen-onderwerp, inclusief hoofdlettergebruik en spaties. Een latere taak die faalt op die host onderdrukt gemelde handlers, tenzij u --force-handlers meegeeft. Een handler die in een andere play is gedefinieerd, is niet zichtbaar vanuit deze play. Een taak die wordt overgeslagen vanwege een when-conditie, verstuurt bovendien nooit een melding.

Waarom rapporteert mijn playbook bij elke uitvoering een wijziging?

De gegenereerde tekst is niet stabiel tussen uitvoeringen. De meest voorkomende oorzaak is een tijdstempel in de output; een aangepaste ansible_managed-string die een datum bevat, veroorzaakt dit precies. Controleer vervolgens mode en owner op de taak: als deze niet overeenkomen met het bestand dat al op de schijf staat, corrigeert Ansible deze en rapporteert het een wijziging, ook al is de inhoud identiek. Voer ansible-playbook site.yml --check --diff uit om te zien welke van de twee het is, aangezien --diff u het verschil toont dat de taak beoogt aan te brengen.

Wat is het verschil tussen template en copy in Ansible?

ansible.builtin.copy verstuurt een bestand ongewijzigd. ansible.builtin.template rendert het bestand eerst via Jinja2 op de controller en verstuurt vervolgens het resultaat, waardoor variabelen en loops worden opgelost voordat het bestand de doelhost bereikt. Gebruik copy voor een bestand dat overal byte-identiek moet zijn. Gebruik template voor alles wat per host verschilt. Ze delen dezelfde bestandsopties, dus mode, owner, backup en validate werken op dezelfde manier in beide.

Hoe laat ik een handler halverwege een play uitvoeren?

Voeg ansible.builtin.meta: flush_handlers toe als taak op het punt waar u wilt dat ze worden uitgevoerd. Dit activeert elke handler die tot dan toe is aangemeld, waarna de play normaal doorgaat. Gebruik dit wanneer een latere taak in dezelfde play afhankelijk is van de service die al op de nieuwe configuratie draait, bijvoorbeeld een wait_for op een poort die pas bestaat na de herlaadactie. Dit is de ondersteunde methode om een handler uit te voeren vóór het einde van de play.

Kan ik validate gebruiken met een nginx-configuratiefragment?

Niet met nginx -t -c %s. Dat commando verwacht een volledige configuratie die begint met de top-level events- en http-blokken, dus het wijst een conf.d-fragment af met een melding zoals "upstream" directive is not allowed here. Het fragment is geldig binnen het http-blok en ongeldig op zichzelf. Installeer het bestand en voer vervolgens nginx -t uit op de samengestelde configuratie in een handler die vóór de herlaad-handler is gedefinieerd. Handlers worden uitgevoerd in de volgorde waarin ze zijn gedefinieerd, dus een foutieve configuratie laat de play falen voordat de herlaadactie wordt geprobeerd. Stel backup: true in op de template-taak zodat het vorige bestand beschikbaar blijft voor herstel.

#ansible#jinja2#handlers#idempotence#automation