Прагон 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 ці хукаў. Таму перазагрузка пасля дадання дырэктывы маршруту выглядае паспяховай і нічога не змяняе.

Параўнайце жывую прыладу з файлам

Праверка, якая закрывае гэты клас памылак, — гэта параўнанне таго, што трымае ядро, з тым, што кажа файл. Дзве каманды даюць супастаўны вывад, а розніца — гэта дрыфт.

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, і яе варта прачытаць аднойчы, а не здагадвацца па зялёнай зводцы. Усё ў гэтым разборы вынікае з гэтай адной розніцы.

Падобныя артыкулы