Ваш корак за deploy виси на интерном имену хоста, док иста наредба одговара одмах са вашег лаптопа, а build клијента на оба рачунара је идентичан. Job се извршава на GitHub-хостованом runner-у: виртуелној машини направљеној за тај један job унутар GitHub-овог облака, без руте у ваш приватни адресни простор, без resolver записа за интерну зону и без сертификата који би приватни endpoint прихватио. Само два дизајна се уклапају у то ограничење, и ниједан не може да се укључи касније без поновне изградње workflow-а. Изаберите између њих пре прве линије YAML-а, јер миграција накнадно кошта више од првог покушаја.

Избор је између runner-а постављеног тамо где мрежа већ престаје и тунела који постоји за време трајања једног job-а. Оба годинама носе продукцијске deploy-е, и падају на различите начине.

Где граница заправо лежи

Све што инсталирате на лаптоп зауставља се на лаптопу, а све што инсталирате током job-а нестаје са runner-ом. Не постоји трајни мрежни namespace за који би клијент остао везан између покретања, па свако покретање почиње у истом недостижном стању. Azure документује ту границу за агенте које хостује Microsoft, где VPN и ExpressRoute везе у приватне мреже нису подржане, а GitHub-хостовани runner-и носе исти облик ограничења уместо засебног механизма. Читајте то као особину производа, не као дефект који треба обилазити.

Ниједна поставка репозиторијума то не ублажава. Ознака job-а одлучује који pool преузима посао, а хостована ознака значи машину изван вашег периметра за цело покретање.

Приватна достижност зато мора доћи из нечега што поседујете. Runner постављен тамо где мрежа већ престаје, или тунел који живи један job. Остатак чланка говори о томе да свесно платите једно од тога уместо да рачун откријете у продукцији.

Одлучујте по фреквенцији покретања, не по познатости

Посегните за сопственим runner-ом у VPC-у или канцеларијској мрежи када deploy-и стижу неколико пута дневно, када job дира више од једног приватног порта, или када тим за платформу већ води patching и ротацију акредитива. Job на тој машини resolvuje и рутира као било који други хост иза firewall-а. Мрежни посао се дешава једном, при инсталацији, уместо при сваком покретању.

Направите тунел унутар job-а када је приступ повремен и не желите дуговечног агента који држи акредитив у вашу мрежу. Job постаје сопствени мрежни клијент на неколико минута и не оставља ништа за собом, што је често цела поента.

Процените цену тунела пре него што га одаберете. Свако покретање плаћа материјализацију профила, покретање клијента, спремност и демонтажу. Тунел који се подигне али никада не верификује производи deploy који падне на пола пута и оставља приватно стање у облику који нико није планирао. Поновни покушај после тога ретко је чист, а други неуспех се обично припише верзији клијента.

Писање профила тако да корак не може да абортира

Држите профиле и акредитиве изван репозиторијума и материјализујте их из secrete-а у кораку којем требају. Редослед одлучује да ли job преживљава: фајл направљен под sudo припада root-у, а непривилеговани shell корака онда не може да пише у њега.

- name: Bring up OpenVPN
  run: |
    umask 077
    profile="$RUNNER_TEMP/client.ovpn"
    printf '%s\n' "$VPN_PROFILE" > "$profile"
    : > "$RUNNER_TEMP/openvpn.log"
    printf '%s\n' "$VPN_CREDENTIALS" > "$RUNNER_TEMP/credentials.txt"
    sudo openvpn --daemon openvpn-job \
      --config "$profile" \
      --auth-user-pass "$RUNNER_TEMP/credentials.txt" \
      --writepid "$RUNNER_TEMP/openvpn.pid" \
      --log "$RUNNER_TEMP/openvpn.log"

Оба детаља у том блоку постоје за касније кораке. Са umask 077 профил стиже у модусу 0600 и власништву корисника runner-а, sudo га још може читати, а клијент пише свој лог у фајл који runner већ поседује, па петља спремности може да чита тај лог без другог sudo. --writepid бележи PID на који ће демонтажа циљати.

Профил који се аутентификује клијентским сертификатом треба свој кључ записан на исти начин, а профил са статичким изазовом треба одговарајући auth мод. Профили који гурају DNS опције требају openvpn-systemd-resolved на Ubuntu и Debian-у, јер само гурање ништа не мења на основној слици.

Спремност је сонда, не пауза

Фиксни sleep држи тачно до тренутка када концентратор постане спор, а тада корак deploy-а креће пре него рута постоји. Неуспех се онда појави унутар deploy алата као timeout према приватном хосту, што ништа не говори о тунелу.

- name: Await private endpoint
  run: |
    for attempt in $(seq 1 30); do
      if getent hosts private.example.internal > /dev/null && \
         timeout 3 bash -c 'exec 3<>/dev/tcp/private.example.internal/8443' 2>/dev/null; then
        echo "endpoint answered after $attempt attempts"
        exit 0
      fi
      sleep 2
    done
    grep -Ei 'error|verify|auth' "$RUNNER_TEMP/openvpn.log" | tail -40
    exit 1

Петља посматра две ствари јер било која од њих може бити покварена половина. getent hosts доказује да гурнути resolver одговара за то име, а отварање socket-а доказује да нешто слуша на порту који ће deploy користити; профил само са рутом треба дословну адресу и обрисану линију getent.

Када петља истекне, лог је једина ствар која раздваја три различита квара: одбијен сертификат, погрешан auth мод и руту која никада није стигла. Филтрирање пре tail-а држи тај излаз довољно кратким за читање док job још пада. Читајте прву грешку уместо задње линије, јер клијент који не може да се аутентификује понавља се док петља не одустане. ip -4 route show dev tun0 одговара на једноставније питање да ли је рута уопште гурнута, и кошта једну линију унутар исте петље.

Демонтажа и питање артефакта

Затворите job кораком заштићеним са if: always() који извршава sudo kill "$(sudo cat "$RUNNER_TEMP/openvpn.pid")" и ништа друго. На дељеном сопственом runner-у никада не убијајте по имену процеса: други job може поседовати клијента са истим бинарним фајлом и сличним аргументима. Неуспех онда падне на job који је радио други, а његов лог показује на workflow који није ништа погрешио.

Заштита је битна јер неуспели deploy ипак оставља жив тунел. Без always() корак чишћења се прескаче тачно када је потребан, а следеће покретање креће према клијенту који је већ повезан.

Остаје једно питање пре него што усвојите било који дизајн: да ли build фази уопште треба приватна рута? Deployment агент који већ седи у мрежи може да повуче одобрени артефакт, што држи обичне build-ове даље од приватне стазе. Мање job-ова који држе тунел значи мање места где се застарела рута може сакрити.

Повезани чланци