Задание развёртывания подключается, копирует свой артефакт и сообщает об успехе. Открытый им туннель может всё ещё работать, когда начинается следующее задание, а изменённый маршрут принадлежит всему хосту. Результат сборки описывает команду, а не состояние, которое она оставила после себя. Относитесь к VPN как к ресурсу со сроком жизни, а не как к одной строке в начале этапа.

Что ещё работает на этом хосте

Узел Jenkins может запускать несколько исполнителей одновременно, а задание, которое меняет маршруты хоста, настройки резолвера или общесистемное соединение, меняет их для всех. Заметит ли это другое задание, зависит от политики маршрутов и фильтрации, а не от общего правила о VPN. Доступ к репозиторию, доступ к артефактам и канал управления — это отдельные требования, которые раннеру по-прежнему нужны. Добавьте их в список назначений развёртывания, прежде чем выбирать полный туннель.

Если канал управления будет проходить через туннель, проект должен сказать это осознанно. Обнаружить это во время отката — не план. Запишите два списка: чего задание должно достигать приватно и чего раннер должен достигать в любом случае.

Нужен ли этому заданию приватный доступ вообще?

Спросите до добавления туннеля, нужен ли он этапу сборки. Приватный агент развёртывания может получить одобренный артефакт и выполнить развёртывание, что держит общий этап сборки вне приватной сети. Такое разделение обычно дешевле, чем учить каждый шаг сборки маршрутизации через туннель.

Выбирайте границу из рабочего процесса, а не из привычки. Если ответ нет, остаток этой страницы не нужен, и это лучший доступный результат.

Состояние, которое наследует следующее задание

Опишите, что должно быть верно до задания, пока оно имеет приватный доступ, и после его завершения, включая отмену. Именно конечное состояние чаще всего остаётся невысказанным, и именно его наследует следующее задание. Запишите его рядом с pipeline, а не оставляйте в чьей-то памяти.

MomentWhat proves itWhat leaks if it is skipped
Job start: pre-flight route checkThe route table shows no tunnel from an earlier job, and the profile list is emptyA stale route sends deployment traffic into a dead tunnel
Job end: disconnect and shredThe profile is down and the temporary key file is goneThe next job inherits an open tunnel and a usable credential
Cancelled job: reboot or disposalThe host is replaced or rebooted before the next job startsA killed process leaves the tunnel up with no owner

Выделенный или одноразовый агент делает эти границы проще для соблюдения. Контейнер или пространство имён помогает только если его сетевая и привилегированная конфигурация действительно изолирует изменение.

Остановите соединение, а не программу

Используйте путь завершения pipeline, чтобы закрыть соединение, начатое этим заданием, и удалить его временные учётные данные. Не сопоставляйте процессы по имени программы на хосте, который используют другие задания; остановите конкретное соединение. Две команды ниже — это вся очистка, и ни одна из них не зависит от поиска процесса.

vpn-cli disconnect --profile "$PROFILE"
rm -f "$RUNNER_TEMP/client.key"

Завершение — не изоляция: раннер, который умирает, сохраняет открытый туннель, а процесс, остановленный принудительно, полностью пропускает блок. Поэтому одной команды очистки не может быть достаточно для всего проекта. Вот как это отказывает на практике: задание развёртывания отменяют на шаге копирования, блок завершения никогда не выполняется, и следующее задание на том же хосте начинается с живого туннеля и маршрута, указывающего на сеть, до которой оно не может добраться. Сбой выглядит как проблема с 'DNS' в следующей сборке, спустя часы после завершения задания, которое его вызвало.

Записывайте имя профиля и путь к учётным данным в вывод задания. Голая команда отключения без идентификатора плохо поддаётся аудиту потом. Строка лога также доказывает, что блок выполнился, когда об этом спросит более позднее расследование.

Дайте заданию хост, который не использует никто другой

Одноразовая инфраструктура устраняет проблему наследования, а не управляет ею. Новый агент на каждое задание начинается без маршрута, без профиля и без чужих учётных данных, а его уничтожение убирает всё, что задание оставило. Это дороже на каждую сборку, и это честная цена границы, которая не зависит от кода очистки. Для заданий, которые касаются производственных сетей, это обычно более дешёвый вариант, если посчитать инциденты.

Там, где общий раннер должен остаться, проверяйте отказ и отмену так же тщательно, как успешное копирование. Тест должен показать, что увидело бы следующее задание, если бы это отменили на полпути. Задание завершено, когда закончились его доступ и временное состояние, а не когда команда копирования возвращает ноль.

Похожие статьи