SSD Nodes Learn 🎉 VPS vanaf $5.50/mnd
Gidsen Matt ConnorDoor Matt Connor

Ansible onbereikbare hosts negeren met ignore_unreachable

Leer hoe u ignore_unreachable gebruikt om onbereikbare hosts in Ansible te negeren. Voorkom dat uw play stopt bij verbindingsfouten en beheer uw updates effectief op alle servers.

Een onbereikbare host is geen mislukte taak

Om onbereikbare hosts in Ansible te negeren, stelt u ignore_unreachable: true in; deze switch werkt zoals verwacht. Het is essentieel om te weten wanneer u deze gebruikt, omdat Ansible twee verschillende problemen op twee verschillende manieren afhandelt. Een taak die op de host is uitgevoerd en een foutmelding gaf, is een mislukking. Een host waarmee Ansible helemaal geen verbinding kon maken, is onbereikbaar. ignore_errors dekt alleen het eerste geval. ignore_unreachable dekt alleen het tweede geval.

Hieronder ziet u het verschil in een play-samenvatting.

PLAY RECAP *********************************************************************
web1  : ok=7  changed=2  unreachable=0  failed=0  skipped=0  rescued=0  ignored=0
web2  : ok=0  changed=0  unreachable=1  failed=0  skipped=0  rescued=0  ignored=0

Ansible maakte verbinding met web1 en voerde zeven taken uit. web2 toont unreachable=1 en failed=0, wat betekent dat er op die host helemaal niets is uitgevoerd. Ansible kreeg nooit een verbinding, dus verwijderde het de host uit de play en ging door met de rest. Als die play een beveiligingsupdate installeerde, beschikt een van uw servers nu niet over deze update.

Wat maakt een host onbereikbaar

Onbereikbaar betekent dat de verbinding is mislukt voordat een module de host kon bereiken. Er is geen module-output om te lezen, enkel een verbindingsfout, en deze verschijnt bij de eerste taak die de machine raakt.

fatal: [web2]: UNREACHABLE! => {"changed": false, "msg": "Failed to connect to the host via ssh: ssh: connect to host 203.0.113.20 port 22: Connection refused", "unreachable": true}

Het veld msg bevat de werkelijke oorzaak. Dit zijn de fouten die u zult tegenkomen:

  • Connection refused: de TCP-verbinding werd geweigerd, wat betekent dat er niets op die poort luistert. sshd is gestopt, of SSH is verplaatst naar een andere poort terwijl uw inventaris nog steeds 22 aangeeft.
  • Connection timed out: er kwam helemaal geen antwoord. Een firewall negeert de pakketten, of de server staat uit. Elke poging kost de volledige verbindingstime-out, die standaard 10 seconden bedraagt.
  • Host key verification failed.: de sleutel in ~/.ssh/known_hosts komt niet overeen met de sleutel die de server presenteerde. Een opnieuw geïnstalleerde VPS behoudt zijn IP-adres en krijgt een nieuwe hostsleutel, dus dit is te verwachten na een herinstallatie en is ernstig op elk ander moment.
  • Permission denied (publickey): SSH antwoordde en wees uw sleutel af. De poort is in orde, dus dit is een authenticatieprobleem, meestal de verkeerde ansible_user of een sleutel die niet is geladen.
  • Timeout (12s) waiting for privilege escalation prompt: de verbinding werkte, maar become niet. sudo wacht op een wachtwoord dat nooit aankomt.

Een ontbrekende Python-interpreter is de oorzaak die mensen in die lijst verwachten, maar daar hoort deze niet thuis. SSH maakt verbinding, dus de host is bereikbaar. De module heeft vervolgens geen omgeving om in te draaien:

fatal: [db1]: FAILED! => {"changed": false, "module_stdout": "/bin/sh: 1: /usr/bin/python3: not found\r\n", "msg": "The module failed to execute correctly, you probably need to set the interpreter", "rc": 127}

Die regel zegt FAILED! en de samenvatting telt dit onder failed, dus ignore_unreachable zal de host nooit bereiken. Stel ansible_python_interpreter in voor die host, of installeer python3 op de machine.

Onbereikbare hosts negeren in een play

Op taakniveau staat het trefwoord naast de module:

- name: Read the package list, and do not stop if the host is down
  ansible.builtin.command: dpkg -l
  register: packages
  changed_when: false
  ignore_unreachable: true

Op play-niveau stelt het de standaard in voor elke taak in de play, en een individuele taak kan dit weer terugdraaien:

- name: Opportunistic fleet maintenance
  hosts: all
  ignore_unreachable: true
  tasks:
    - name: This runs, cannot connect, and the play carries on
      ansible.builtin.ping:

    - name: This one still ends the play for a host that is down
      ansible.builtin.ping:
      ignore_unreachable: false

Het is nuttig om te weten wat er onder de motorkap verandert. Wanneer ignore_unreachable is ingesteld, wordt de host niet langer uit de play verwijderd. Hierdoor probeert elke volgende taak opnieuw verbinding te maken en faalt deze op dezelfde wijze. Elke poging wacht de verbindingstime-out af; dit is 10 seconden, tenzij u timeout aanpast in ansible.cfg. Een play met twintig taken tegen één dode server voegt ongeveer 200 seconden toe aan de uitvoering en twintig rode regels aan het logbestand.

Controleer daarom één keer en stop die host vervolgens netjes:

- name: Opportunistic fleet maintenance
  hosts: all
  gather_facts: false
  tasks:
    - name: Check that the host answers before doing any work
      ansible.builtin.ping:
      register: reachable
      ignore_unreachable: true

    - name: End the play for this host if it never answered
      ansible.builtin.meta: end_host
      when: reachable.unreachable | default(false)

    - name: Gather facts now that the connection is known good
      ansible.builtin.setup:

    - name: Refresh the package index
      ansible.builtin.apt:
        update_cache: true
      become: true

Dit resulteert in één verbindingspoging per dode host in plaats van één per taak. end_host, toegevoegd in Ansible 2.8, beëindigt de play voor de huidige host zonder deze als mislukt te markeren. De sleutel unreachable is alleen aanwezig in het geregistreerde resultaat wanneer de verbinding is mislukt, dus zorgt default(false) ervoor dat de voorwaarde geldig blijft op elke host die wel antwoordde. Het verzamelen van feiten (fact gathering) staat uit op play-niveau, omdat de impliciete Gathering Facts-taak anders de taak zou zijn die de verbroken verbinding tegenkomt, terwijl u wilt dat dit uw eigen ping-taak is.

ignore_unreachable is zowel een play-trefwoord als een taak-trefwoord. Houd dit in de playbook waar een lezer het kan zien, in plaats van in een role, omdat het bepaalt welke hosts tijdens een run mogen ontbreken. Het onderscheid tussen playbooks en roles behandelt welke laag verantwoordelijk moet zijn voor een dergelijke instelling.

Waarom ignore_errors hier de verkeerde oplossing is

De Ansible-documentatie is duidelijk over deze beperking. ignore_errors "werkt alleen wanneer de taak kan worden uitgevoerd en een 'failed'-waarde retourneert. Het zorgt er niet voor dat Ansible fouten negeert met betrekking tot niet-gedefinieerde variabelen, verbindingsfouten, uitvoeringsproblemen (zoals ontbrekende pakketten) of syntaxfouten."

Een verbindingsfout wordt nooit een taakresultaat met failed: true. Het komt binnen als een afzonderlijke vlag en Ansible reageert daar als eerste op: de host wordt op de unreachable-lijst geplaatst en uit de play gehaald. Plaats ignore_errors: true op alle twaalf taken van een play en een host met een gesloten SSH-poort stopt nog steeds bij de eerste taak. Dit is de meest voorkomende verwarring op dit gebied en het is de moeite waard om uw oudere playbooks hierop te doorzoeken met grep, zeker die welke zijn geschreven tijdens het leren schrijven van een eerste playbook voor een VPS.

Debuggen voordat u onderdrukt

Onderdrukking die permanent wordt, leidt tot configuratieverloop in een serverpark, omdat de host die niemand kan bereiken ook de host is die niemand bijwerkt. Doorloop eerst deze volgorde. Elk commando hier leest alleen gegevens.

  1. ansible web2 -i inventory.ini -m ansible.builtin.ping -o voert één module uit op één host en print één regel.
  2. Voeg -vvvv toe aan datzelfde commando. Ansible print het volledige ssh-commando dat het opbouwt, inclusief de doelgebruiker, de poort, de private key en de opties die het meegeeft.
  3. Voer dat ssh-commando zelf uit met -v. Als een standaard ssh-verbinding niet lukt, ligt het probleem onder Ansible en zal geen enkel playbook-keyword dit oplossen.
  4. Lees de msg-string en vergelijk deze met de bovenstaande lijst. Connection refused en Connection timed out wijzen naar twee verschillende locaties: één naar de SSH-service en één naar het netwerkpad.
  5. Kijk voor Host key verification failed. naar wat u heeft opgeslagen met ssh-keygen -F web2.example.com. Als de server opnieuw is opgebouwd, verwijder dan het oude item met ssh-keygen -R web2.example.com en accepteer de nieuwe sleutel nadat u deze heeft gecontroleerd via de console van de provider. Het instellen van host_key_checking = False in ansible.cfg wist de foutmelding, maar verwijdert ook de controle die u zou waarschuwen als een andere machine op dat adres antwoordt.
  6. Bevestig voor Permission denied (publickey) wat Ansible denkt dat het moet gebruiken. ansible-inventory -i inventory.ini --host web2 print de actieve variabelen, inclusief ansible_user en ansible_port.
  7. Als SSH werkt maar modules niet, controleer dan de interpreter met ansible web2 -m ansible.builtin.raw -a 'command -v python3 || echo none'. De raw-module voert een commando uit via de shell en heeft geen python nodig op de doelmachine.

Pas daarna is het negeren van de host een bewuste beslissing in plaats van een gewoonte.

De samenvatting telt onbereikbare hosts afzonderlijk, en CI mist dit meestal

ansible-playbook geeft 0 terug bij succes, 2 wanneer ten minste één host faalde en 4 wanneer ten minste één host onbereikbaar was. Deze twee waarden zijn bit-flags in de broncode, dus een run met een gefaalde host en een onbereikbare host geeft 6 terug. Het ansible-commando geeft dezelfde codes terug. Deze zijn in augustus 2026 gecontroleerd tegen de ansible-core broncode.

Stel nu ignore_unreachable: true in en voer dezelfde play met zeven taken uit tegen dezelfde dode host:

PLAY RECAP *********************************************************************
web1  : ok=7  changed=2  unreachable=0  failed=0  skipped=0  rescued=0  ignored=0
web2  : ok=7  changed=0  unreachable=0  failed=0  skipped=0  rescued=0  ignored=7

web2 rapporteert unreachable=0 en zeven taken ok, en de run eindigt met exitcode 0. Wanneer het trefwoord is ingesteld, verhoogt Ansible de ok- en ignored-tellers voor die host in plaats van de teller die het dark noemt, wat de teller is die de unreachable-kolom vult. De rode UNREACHABLE!-regels worden nog steeds afgedrukt, dus het logbestand is eerlijk, terwijl de samenvatting en de exitcode dat niet zijn.

Een CI-job die de playbook uitvoert en alleen $? controleert, bestempelt die run als geslaagd, en niets in de samenvatting vermeldt dat een machine nooit is aangeraakt. Maak van de bereikbaarheidscontrole een eigen stap, voorafgaand aan de play:

ansible all -i inventory.ini -m ansible.builtin.ping -o

Dit drukt één regel per host af en geeft 4 terug als een host onbereikbaar is, wat de pipeline een reden geeft om te falen en u de namen in het logbestand toont. ping vereist een werkende Python-interpreter op de doelmachine, dus het bewijst iets meer dan alleen de verbinding, wat meestal is wat u wilt. Voer daarna de playbook uit met ignore_unreachable zodat de hosts die wel online zijn alsnog hun wijziging ontvangen.

any_errors_fatal en max_fail_percentage binnen een batch

Deze twee trefwoorden bepalen wat er gebeurt nadat er iets misgaat bij een deel van het serverpark, en ze gaan verschillend om met onbereikbare hosts.

any_errors_fatal: true reageert wel op een onbereikbare host. Ansible voltooit de huidige taak op de rest van de batch en stopt vervolgens de play voor elke host daarin. Gebruik dit wanneer een run alleen zin heeft als alles of niets slaagt, zoals bij een gecoördineerde schemawijziging.

max_fail_percentage: 30 reageert niet op een onbereikbare host. De controle deelt het aantal gefaalde hosts door de grootte van de batch, en onbereikbare hosts worden in een aparte lijst gehouden, waardoor ze dat getal nooit beïnvloeden. Tien hosts waarvan er vier onbereikbaar zijn, gaan door onder max_fail_percentage: 10, terwijl twee hosts die falen op een taak de play stoppen. De documentatie voegt nog een valkuil toe: "Het ingestelde percentage moet worden overschreden, niet geëvenaard." Bij serial: 4 betekent stoppen na twee fouten op vier hosts dat u 49 moet schrijven, niet 50.

Er is één geval waarin onbereikbare hosts een run uit zichzelf stoppen. Als elke host in de batch is gefaald of onbereikbaar is, heeft Ansible niets meer om mee te werken en beëindigt de play met NO MORE HOSTS LEFT.

serial: een wijziging uitrollen over het serverpark

- name: Rolling nginx config update
  hosts: webservers
  serial: 2
  max_fail_percentage: 25
  tasks:
    - name: Deploy the site config
      ansible.builtin.template:
        src: site.conf.j2
        dest: /etc/nginx/conf.d/site.conf
        owner: root
        mode: "0644"
      become: true
      notify: Reload nginx
  handlers:
    - name: Reload nginx
      ansible.builtin.service:
        name: nginx
        state: reloaded
      become: true

serial: 2 voert het volledige playbook uit op twee hosts, rondt dit af en start vervolgens de volgende twee. serial: "25%" schaalt mee met de grootte van de groep. Een lijst, serial: [1, 5, 10], is de vorm voor een canary-release: eerst één host, dan vijf, dan tien, waarbij eventuele overgebleven hosts in batches van de laatst gekozen grootte worden verwerkt. max_fail_percentage wordt per batch gemeten, waardoor beide instellingen samenwerken. Als de eerste machine faalt, stopt de uitvoering voordat er veertig machines worden beïnvloed. Dat is wat het beheren van een serverpark met Linux-servers vanaf één controle-machine veilig maakt om vanaf één enkel commando uit te voeren.

Wanneer onbereikbare hosts negeren, en wanneer niet

Negeer ze voor opportunistisch werk. Een fact collection-run of een uurlijkse controle op configuratieafwijkingen verliest niets door een host over te slaan die offline is, omdat de volgende run deze weer oppikt. Play-niveau ignore_unreachable: true is daar het juiste antwoord, in combinatie met de ping-stap, zodat de overgeslagen namen ergens terechtkomen waar een beheerder ze kan lezen.

Negeer ze nooit voor een run met beveiligingspatches. De waarde van die run is de garantie dat elke host de fix heeft; het onderdrukken van de onbereikbare status verandert "één server is nog kwetsbaar" in een foutloze, groene samenvatting. De host die al twee weken onbereikbaar is, is de host die waarschijnlijk het verst achterloopt. Laat die run exit 4 teruggeven en laat een beheerder ernaar kijken.

Eén regel geldt in beide gevallen: onderdruk het stoppen, nooit de registratie. Als een host is overgeslagen, moet iets dat melden: in de samenvatting, in het CI-logboek of in een monitoring-alert. Ansible weet alleen dat een host bestaat tijdens de seconden dat een play erop draait, dus het is een slechte plek om te ontdekken dat een server al sinds dinsdag offline is. Die taak hoort bij monitoring, en een Ansible playbook dat Zabbix installeert zorgt ervoor dat u in een middag een overzicht van het hele serverpark heeft.

FAQ

Wat is het verschil tussen ignore_errors en ignore_unreachable in Ansible?

ignore_errors: true is van toepassing op een taak die op de host is uitgevoerd en een foutmelding gaf, zoals een commando dat met een status ongelijk aan nul eindigde. ignore_unreachable: true is van toepassing op een host waarmee Ansible geen verbinding kon maken, waarbij geen enkele module is uitgevoerd. Ze lezen verschillende velden in het taakresultaat en de een dekt de andere situatie niet af. De documentatie van Ansible stelt dat ignore_errors "Ansible niet dwingt om fouten door ongedefinieerde variabelen, verbindingsfouten, uitvoeringsproblemen (bijvoorbeeld ontbrekende pakketten) of syntaxfouten te negeren", en een gesloten SSH-poort is een verbindingsfout.

Verbergt ignore_unreachable de host in het overzicht aan het einde van de play?

In de praktijk wel. Wanneer dit trefwoord is ingesteld, stopt Ansible met het meetellen van die host onder unreachable en telt deze per taak als ok en ignored, waarna de uitvoering met exitcode 0 eindigt. De fatal: [host]: UNREACHABLE!-regels worden nog steeds afgedrukt, dus het logbestand is accuraat, ook al zijn het overzicht en de exitcode dat niet. Houd de ignored-kolom in de gaten, of voer ansible all -m ansible.builtin.ping -o uit als een afzonderlijke stap, zodat een onbereikbare host alsnog een exitcode ongelijk aan nul genereert.

Welke exitcode geeft ansible-playbook terug wanneer een host onbereikbaar is?

Dit is 4. Een run met ten minste één mislukte host geeft 2 terug. Omdat deze twee waarden bit-flags zijn, geeft een run met zowel een fout als een onbereikbare host 6 terug. Een succesvolle run geeft 0 terug. Deze codes zijn in augustus 2026 gecontroleerd aan de hand van de broncode van ansible-core. Het instellen van ignore_unreachable: true verwijdert de 4, wat de reden is dat een pipeline die alleen de exitcode test, een overgeslagen machine niet kan detecteren.

Hoe sla ik de rest van een play over voor een host die niet reageerde?

Maak de eerste taak ansible.builtin.ping met ignore_unreachable: true en register: reachable, en laat deze volgen door ansible.builtin.meta: end_host onder de voorwaarde when: reachable.unreachable | default(false). end_host beëindigt de play voor die host zonder deze als mislukt te markeren. Stel gather_facts: false in op de play, zodat uw ping de taak is die de verbroken verbinding detecteert. Zonder dit patroon blijft de onbereikbare host in de play en wacht elke volgende taak opnieuw de verbindingstime-out af.

Moet ik onbereikbare hosts negeren tijdens het uitvoeren van beveiligingsupdates?

Nee. Een update-run is waardevol omdat deze de garantie biedt dat elke host de update heeft ontvangen. Het negeren van onbereikbare hosts vervangt die garantie door een groen overzicht. Laat de run eindigen met 4, lees de namen van de hosts die niet reageerden en herstel deze. Het onderdrukken van fouten is alleen zinvol bij herhaalde, opportunistische runs waarbij de volgende poging alles oppikt wat gemist is.

#ansible#playbooks#error-handling#inventory#automation