Изпълнението на playbook завършва зелено, юнитът на WireGuard е активен, ръкостискането работи, а новият peer все още не достига до нищо. Да гледаш как playbook съобщава за успех, докато сървърът работи с вчерашната конфигурация, е особено дразнещо, защото в изхода няма нищо грешно. Ansible направи точно това, което му беше наредено: увери се, че юнитът е стартиран, а той вече беше стартиран. Прилагането на пренаписан конфигурационен файл е друга задача и се случва само ако нещо каже на услугата да го препрочете.

Вижте какво всъщност съобщава второто изпълнение

Стартирайте playbook два пъти с променената конфигурация на място и сравнете обобщението. Второто изпълнение трябва да покаже задачата за юнита като ok, а не changed, защото вече работеща услуга по дизайн се оставя на мира. Това е идемпотентност, която работи правилно, и същевременно причината новият файл никога да не стигне до ядрото.

Добавете проверочно изпълнение с diff изход, за да видите кои задачи изобщо биха докоснали нещо.

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

Трите времеви маркера разказват историята, преди да прочетете дори един ред от лога. Ако конфигурационният файл е по-нов от момента, в който юнитът е станал активен, работещият интерфейс е изграден от по-стар файл и всеки следващ симптом произтича от това.

Това не е дефект на Ansible. Същото поведение се появява при всеки инструмент за управление на конфигурация, който разделя „увери се, че работи“ от „увери се, че работи точно това“. Разликата изглежда педантична, докато не ви струва един следобед.

Стартиран е състояние, а не презареждане

state: started твърди условие за юнита. То не обещава, че услугата ще препрочете входните си данни, и не може да знае, че файл, който никога не е отваряла, се е променил. При внедряване с wg-quick входните данни включват конфигурацията на интерфейса, адресите, маршрутите, DNS записите и всички post-up куки.

Затова обновен файл може да съдържа нов peer, различен адрес или променена маршрутна директива, докато живият интерфейс продължава да обслужва стария набор. Ръкостискането все още успява, защото заредените ключове и крайни точки са още валидни. Именно това прави повредата трудна за забелязване и обяснява защо хората гонят DNS в продължение на час, преди да проверят времеви маркер.

Две други опции на модула често се приемат за решение. daemon_reload кара systemd да препрочете юнит файловете, което е без значение за конфигурационен файл на WireGuard. state: reloaded иска от юнита да изпълни действието си за презареждане и дали то прави нужното зависи изцяло от юнита. Нито една от двете не замества знанието кои входни данни действително е прочел работещият процес.

Инсталирайте файла, после уведомете манипулатор

Моделът, който запазва идемпотентността и все пак прилага промени, е обикновеният: задачата, която пише файла, уведомява манипулатор и той се изпълнява само когато файлът наистина се е променил. Второ изпълнение без редакции не прави нищо и точно това искате.

- 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

Манипулаторите се изпълняват в края на пиесата, след задачите, които са ги уведомили, затова задача по-нататък в същата пиеса може още да вижда стария интерфейс. Ако редът е важен, изчистете манипулаторите изрично с meta: flush_handlers преди задачата, която зависи от новата конфигурация.

Използвайте restart, а не reload, освен ако не сте проверили действието за презареждане на юнита. Горният юнит wg-quick поддържа такова и синхронизира конфигурацията на WireGuard, но не повтаря настройката на адреси, маршрути, DNS или куки. Затова reload след добавяне на маршрутна директива изглежда успешен и не променя нищо.

Сравнете живото устройство с файла

Проверката, която затваря този клас проблеми, е сравнение между това, което ядрото държи, и това, което казва файлът. Две команди дават сравним изход, а разликата е отклонението.

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

wg showconf отпечатва живото устройство, включително частния ключ, затова третирайте изхода като тайна и не го поставяйте в тикет. wg-quick strip отпечатва файла с премахнати ключове, специфични за wg-quick, и точно затова двата изхода изобщо могат да се сравняват.

Разлика в списъка с peer означава, че файлът никога не е бил приложен. Разлика само в ключове или крайни точки, които сте очаквали да се променят, означава, че нещо го е приложило частично. Липсата на разлика означава, че конфигурацията е актуална и проблемът е другаде, което само по себе си е полезен резултат.

Платете цената на рестарта съзнателно

Рестартирането на интерфейса прекъсва тунела и ако този тунел носи административната ви сесия, рестартът прекратява сесията, която го е поискала. Поставете манипулатора зад прозорец за промени или стартирайте playbook от път за управление, който не зависи от рестартирането на интерфейса.

Цената е причината хората да посягат към reload. Това е разумен инстинкт и става правилен, щом знаете кои промени reload действително прилага. За промени в peer и ключове на горния юнит wg-quick е достатъчно; за адресиране, маршрутизация и куки — не. Да го изясните веднъж е по-евтино, отколкото да го откриете по време на прозорец за промени.

Документацията на модула systemd_service подробно обяснява разликата между started, restarted и reloaded и си струва да се прочете веднъж, вместо да се гадае по зелено обобщение. Всичко в това ръководство произтича от тази една разлика.

Подобни статии