Ansible spune pornit, dar WireGuard rulează încă vechea configurație
state: started lasă în pace o unitate care rulează deja, așa că un wg0.conf rescris nu este niciodată aplicat. Adaugă un handler de modificare și apoi compară dispozitivul activ cu fișierul.
Rularea playbook-ului se termină verde, unitatea WireGuard este activă, handshake-ul funcționează, iar noul peer tot nu ajunge nicăieri. Să vezi un playbook raportând succes în timp ce serverul rulează configurația de ieri este deosebit de frustrant, pentru că nimic din ieșire nu este greșit. Ansible a făcut exact ce i s-a cerut: s-a asigurat că unitatea este pornită, iar unitatea era deja pornită. Aplicarea unui fișier de configurare rescris este altă sarcină și se întâmplă doar dacă ceva îi spune serviciului să îl recitească.
Vezi ce raportează de fapt a doua rulare
Rulează playbook-ul de două ori cu configurația modificată și compară rezumatul. A doua rulare ar trebui să arate sarcina unității ca ok, nu ca changed, pentru că un serviciu deja pornit este lăsat în pace prin proiectare. Aceasta este idempotența care funcționează corect și este și motivul pentru care noul fișier nu ajunge niciodată la kernel.
Adaugă o rulare de verificare cu ieșire diff pentru a vedea ce sarcini ar atinge măcar ceva.
ansible-playbook -i inventory site.yml --check --diff
systemctl show wg-quick@wg0 -p ActiveEnterTimestamp -p NRestarts
stat -c '%y %n' /etc/wireguard/wg0.confCele trei momente de timp spun povestea înainte de a citi o singură linie de log. Dacă fișierul de configurare este mai nou decât momentul în care unitatea a devenit activă, interfața care rulează a fost construită dintr-un fișier mai vechi, iar fiecare simptom ulterior decurge de acolo.
Nu este un defect al Ansible. Același comportament apare la orice instrument de gestionare a configurației care separă „asigură-te că rulează” de „asigură-te că rulează exact asta”. Diferența pare pedantă până când te costă o după-amiază.
Pornit este o stare, nu o reîncărcare
state: started afirmă o condiție despre unitate. Nu promite că serviciul își recitește intrările și nu poate ști că un fișier pe care nu l-a deschis niciodată s-a schimbat. Într-un deployment wg-quick intrările includ configurația interfeței, adresele, rutele, înregistrările DNS și orice hook post-up.
De aceea un fișier actualizat poate conține un peer nou, altă adresă sau o directivă de rutare modificată, în timp ce interfața activă continuă să servească setul vechi. Handshake-ul reușește încă pentru că cheile și punctele finale încărcate sunt încă valide. Exact asta face defectul greu de observat, și de aceea oamenii alergau după DNS o oră înainte să verifice un moment de timp.
Alte două opțiuni ale modulului sunt adesea confundate cu o soluție. daemon_reload face systemd să recitească fișierele de unitate, ceea ce este irelevant pentru un fișier de configurare WireGuard. state: reloaded cere unității să execute acțiunea sa de reîncărcare, iar dacă aceasta face ce ai nevoie depinde în întregime de unitate. Niciuna nu înlocuiește să știi ce intrări a citit procesul care rulează.
Instalează fișierul, apoi notifică un handler
Modelul care păstrează idempotența și totuși aplică modificările este cel obișnuit: sarcina care scrie fișierul notifică un handler, iar handler-ul rulează doar când fișierul s-a schimbat cu adevărat. A doua rulare fără modificări nu face nimic, și asta vrei.
- 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: restartedHandlerele rulează la sfârșitul play-ului, după sarcinile care le-au notificat, așa că o sarcină mai târzie din același play poate vedea încă interfața veche. Dacă ordinea contează, golește handlerele explicit cu meta: flush_handlers înainte de sarcina care depinde de noua configurație.
Folosește restart în loc de reload, dacă nu ai verificat acțiunea de reîncărcare a unității. Unitatea wg-quick upstream suportă una și sincronizează configurația WireGuard, dar nu reexecută configurarea adreselor, rutelor, DNS sau hook-urilor. De aceea un reload după adăugarea unei directive de rută pare reușit și nu schimbă nimic.
Compară dispozitivul activ cu fișierul
Verificarea care închide această clasă de erori este o comparație între ce deține kernelul și ce spune fișierul. Două comenzi produc o ieșire comparabilă, iar diferența este abaterea.
sudo wg showconf wg0
sudo wg-quick strip wg0
sudo diff <(sudo wg showconf wg0) <(sudo wg-quick strip wg0)wg showconf afișează dispozitivul activ, inclusiv cheia privată, așa că tratează acea ieșire ca pe un secret și nu o lipi într-un tichet. wg-quick strip afișează fișierul fără cheile specifice wg-quick, și de aceea cele două sunt comparabile.
O diferență în lista de peers înseamnă că fișierul nu a fost niciodată aplicat. O diferență limitată la chei sau puncte finale care te așteptai să se schimbe înseamnă că ceva l-a aplicat parțial. Nicio diferență înseamnă că configurația este actuală și defectul este în altă parte, ceea ce este în sine un rezultat util.
Plătește costul repornirii în mod deliberat
Repornirea interfeței doboară tunelul, iar dacă tunelul transportă sesiunea ta administrativă, repornirea încheie sesiunea care a cerut-o. Pune handler-ul în spatele unei ferestre de modificare, sau rulează playbook-ul dintr-o cale de administrare care nu depinde de repornirea interfeței.
Costul este motivul pentru care oamenii apelează la reload. Este un instinct rezonabil și devine corect odată ce știi ce modificări aplică de fapt un reload. Pentru modificări de peers și chei pe unitatea wg-quick upstream este suficient; pentru adresare, rutare și hook-uri nu. Să lămurești asta o dată este mai ieftin decât să o descoperi în timpul unei ferestre de modificare.
Documentația modulului systemd_service explică diferența dintre started, restarted și reloaded, și merită citită o dată în loc să o deduci dintr-un rezumat verde. Totul în acest ghid decurge din acea singură diferență.