Der Playbook-Lauf endet grün, die WireGuard-Unit ist aktiv, der Handshake funktioniert, und der neue Peer erreicht trotzdem nichts. Ein Playbook mit Erfolgsmeldung zu sehen, während der Server mit der Konfiguration von gestern läuft, ist auf besondere Weise frustrierend, denn an der Ausgabe ist nichts falsch. Ansible hat genau das getan, worum es gebeten wurde: Es hat sichergestellt, dass die Unit gestartet ist, und die Unit war bereits gestartet. Eine neu geschriebene Konfigurationsdatei anzuwenden ist eine andere Aufgabe, und das passiert nur, wenn etwas den Dienst dazu bringt, sie erneut zu lesen.

Sehen Sie, was ein zweiter Lauf tatsächlich meldet

Führen Sie das Playbook zweimal mit der geänderten Konfiguration aus und vergleichen Sie die Zusammenfassung. Der zweite Lauf sollte die Unit-Aufgabe als ok statt changed zeigen, denn ein bereits laufender Dienst wird konstruktionsbedingt in Ruhe gelassen. Das ist Idempotenz, die korrekt funktioniert, und zugleich der Grund, warum die neue Datei nie den Kernel erreicht.

Fügen Sie einen Prüflauf mit diff-Ausgabe hinzu, um zu sehen, welche Aufgaben überhaupt etwas anfassen würden.

ansible-playbook -i inventory site.yml --check --diff
systemctl show wg-quick@wg0 -p ActiveEnterTimestamp -p NRestarts
stat -c '%y %n' /etc/wireguard/wg0.conf

Die drei Zeitstempel erzählen die Geschichte, bevor Sie eine einzige Logzeile lesen. Ist die Konfigurationsdatei neuer als der Moment, in dem die Unit aktiv wurde, wurde das laufende Interface aus einer älteren Datei gebaut, und jedes weitere Symptom folgt daraus.

Das ist kein Ansible-Fehler. Dasselbe Verhalten zeigt jedes Konfigurationsmanagement-Werkzeug, das »stelle sicher, dass es läuft« von »stelle sicher, dass es dies läuft« trennt. Der Unterschied wirkt pedantisch, bis er Sie einen Nachmittag kostet.

Gestartet ist ein Zustand, kein Neuladen

state: started behauptet eine Bedingung über die Unit. Es verspricht nicht, dass der Dienst seine Eingaben neu liest, und es kann nicht wissen, dass sich eine Datei geändert hat, die es nie geöffnet hat. Bei einer wg-quick-Bereitstellung umfassen die Eingaben die Interface-Konfiguration, die Adressen, die Routen, die DNS-Einträge und alle post-up-Hooks.

Deshalb kann eine aktualisierte Datei einen neuen Peer, eine andere Adresse oder eine geänderte Routing-Anweisung enthalten, während das laufende Interface weiter den alten Satz bedient. Der Handshake gelingt weiterhin, weil die geladenen Schlüssel und Endpunkte noch gültig sind. Genau das macht den Fehler schwer sichtbar, und deshalb jagen Leute eine Stunde lang DNS hinterher, bevor sie einen Zeitstempel prüfen.

Zwei andere Moduloptionen werden häufig für eine Lösung gehalten. daemon_reload bringt systemd dazu, Unit-Dateien neu zu lesen, was für eine WireGuard-Konfigurationsdatei irrelevant ist. state: reloaded fordert die Unit auf, ihre Reload-Aktion auszuführen, und ob diese tut, was Sie brauchen, hängt ganz von der Unit ab. Keine von beiden ersetzt das Wissen, welche Eingaben der laufende Prozess tatsächlich gelesen hat.

Installieren Sie die Datei und benachrichtigen Sie dann einen Handler

Das Muster, das Idempotenz erhält und trotzdem Änderungen anwendet, ist das übliche: Die Aufgabe, die die Datei schreibt, benachrichtigt einen Handler, und der Handler läuft nur, wenn sich die Datei tatsächlich geändert hat. Ein zweiter Lauf ohne Änderungen tut nichts, und genau das wollen Sie.

- name: write the interface configuration
  ansible.builtin.template:
    src: wg0.conf.j2
    dest: /etc/wireguard/wg0.conf
    owner: root
    mode: "0600"
  notify: apply wg0

- name: ensure the interface unit is enabled
  ansible.builtin.systemd_service:
    name: wg-quick@wg0
    enabled: true
    state: started

- name: apply wg0
  listen: apply wg0
  ansible.builtin.systemd_service:
    name: wg-quick@wg0
    state: restarted

Handler laufen am Ende des Plays, nach den Aufgaben, die sie benachrichtigt haben, daher kann eine spätere Aufgabe im selben Play noch das alte Interface sehen. Wenn die Reihenfolge wichtig ist, leeren Sie die Handler ausdrücklich mit meta: flush_handlers, bevor die Aufgabe läuft, die von der neuen Konfiguration abhängt.

Verwenden Sie restart statt reload, sofern Sie die Reload-Aktion der Unit nicht geprüft haben. Die Upstream-wg-quick-Unit unterstützt eine und synchronisiert die WireGuard-Konfiguration, führt aber die Einrichtung von Adressen, Routen, DNS und Hooks nicht erneut aus. Ein reload nach dem Hinzufügen einer Routen-Anweisung scheint daher zu gelingen und ändert nichts.

Vergleichen Sie das laufende Gerät mit der Datei

Die Prüfung, die diese Fehlerklasse schließt, ist ein Vergleich zwischen dem, was der Kernel hält, und dem, was in der Datei steht. Zwei Befehle liefern vergleichbare Ausgabe, und die Differenz ist die Abweichung.

sudo wg showconf wg0
sudo wg-quick strip wg0
sudo diff <(sudo wg showconf wg0) <(sudo wg-quick strip wg0)

wg showconf gibt das laufende Gerät aus, einschließlich des privaten Schlüssels, behandeln Sie diese Ausgabe also als Geheimnis und kleben Sie sie nicht in ein Ticket. wg-quick strip gibt die Datei ohne die wg-quick-spezifischen Schlüssel aus, und deshalb sind die beiden überhaupt vergleichbar.

Ein Unterschied in der Peer-Liste bedeutet, dass die Datei nie angewendet wurde. Ein Unterschied, der auf Schlüssel oder Endpunkte beschränkt ist, die Sie ändern wollten, bedeutet, dass etwas sie teilweise angewendet hat. Kein Unterschied bedeutet, dass die Konfiguration aktuell ist und der Fehler woanders liegt, was für sich genommen ein nützliches Ergebnis ist.

Zahlen Sie die Kosten des Neustarts bewusst

Ein Neustart des Interfaces reißt den Tunnel ab, und wenn dieser Tunnel Ihre administrative Sitzung trägt, beendet der Neustart die Sitzung, die ihn angefordert hat. Legen Sie den Handler hinter ein Änderungsfenster, oder führen Sie das Playbook über einen Verwaltungspfad aus, der nicht vom Neustart des Interfaces abhängt.

Die Kosten sind der Grund, warum Leute zum reload greifen. Das ist ein vernünftiger Instinkt, und er wird richtig, sobald Sie wissen, welche Änderungen ein reload tatsächlich anwendet. Für Peer- und Schlüsseländerungen an der Upstream-wg-quick-Unit reicht er; für Adressierung, Routing und Hooks nicht. Das einmal zu klären ist billiger, als es während eines Änderungsfensters zu entdecken.

Die Dokumentation des systemd_service-Moduls erklärt den Unterschied zwischen started, restarted und reloaded, und sie lohnt einmal gelesen zu werden, statt ihn aus einer grünen Zusammenfassung zu erraten. Alles in dieser Anleitung folgt aus diesem einen Unterschied.

Ähnliche Artikel