GitHub Actions nedosiahne na vašu VPN: vlastný runner alebo tunel
Hostovaný runner je čerstvý virtuálny stroj mimo vašu sieť. Buď umiestnite runner do tejto siete, alebo z jobu vytvorte tunel a počkajte na skutočnú trasu.
Váš krok nasadenia visí na internom názve hostiteľa, zatiaľ čo ten istý príkaz z notebooku odpovedá okamžite, a build klienta je na oboch strojoch rovnaký. Job beží na runnere hostovanom GitHubom: na virtuálnom stroji vytvorenom pre tento jediný job v cloude GitHubu, bez trasy do vášho privátneho adresného priestoru, bez záznamu resolvera pre internú zónu a bez certifikátu, ktorý by privátny endpoint prijal. Tomuto obmedzeniu zodpovedajú len dva návrhy a ani jeden sa nedá neskôr zapnúť bez prestavby workflow. Vyberte medzi nimi ešte pred prvým riadkom YAML, pretože migrácia dodatočne stojí viac než prvý pokus.
Voľba je medzi runnerom umiestneným tam, kde sieť už končí, a tunelom, ktorý existuje počas jedného jobu. Oba roky vozili produkčné nasadenia a oba zlyhávajú iným spôsobom.
Kde hranica skutočne leží
Všetko, čo nainštalujete na notebook, skončí na notebooku, a všetko, čo nainštalujete počas jobu, zmizne s runnerom. Neexistuje trvalý sieťový namespace, ku ktorému by klient zostal pripojený medzi behmi, takže každý beh začína v rovnakom nedostupnom stave. Azure túto hranicu dokumentuje pri agentoch hostovaných Microsoftom, kde sa pripojenia VPN a ExpressRoute do privátnych sietí nepodporujú, a runnery hostované GitHubom nesú rovnakú formu obmedzenia namiesto samostatného mechanizmu. Čítajte to ako vlastnosť produktu, nie ako vadu, ktorú treba obísť.
Žiadne nastavenie repozitára to nezmierni. Štítok jobu rozhoduje, ktorý pool prácu prevezme, a hostovaný štítok znamená stroj mimo vášho perimetra počas celého behu.
Privátna dosiahnuteľnosť teda musí prísť z niečoho, čo vlastníte. Runner umiestnený tam, kde sieť už končí, alebo tunel, ktorý žije jeden job. Zvyšok článku je o tom, zaplatiť za jednu z týchto možností vedome, namiesto toho, aby ste účet objavili v produkcii.
Rozhodujte podľa frekvencie behov, nie podľa zvyku
Siahnite po vlastnom runnere vo VPC alebo v kancelárskej sieti, keď nasadenia prichádzajú niekoľkokrát denne, keď job siaha na viac než jeden privátny port, alebo keď tím platformy už vlastní patchovanie a rotáciu prihlasovacích údajov. Job na tom stroji resolvuje a routuje ako ktorýkoľvek iný host za firewallom. Sieťová práca sa stane raz, pri inštalácii, namiesto pri každom behu.
Postavte tunel vnútri jobu, keď je prístup občasný a nechcete dlhovekého agenta držiaceho prihlasovací údaj do vašej siete. Job sa na pár minút stane vlastným sieťovým klientom a nič po sebe nenechá, čo je často celý zmysel.
Odhadnite cenu tunela, skôr než ho vyberiete. Každý beh platí za materializáciu profilu, štart klienta, pripravenosť a demontáž. Tunel, ktorý naskočí, ale nikdy sa neoverí, vytvorí nasadenie, ktoré zlyhá v polovici a nechá privátny stav v podobe, ktorú nikto neplánoval. Opakovanie potom je málokedy čisté a druhý neúspech sa zvyčajne zvedie na verziu klienta.
Napísať profil tak, aby krok nemohol spadnúť
Držte profily a prihlasovacie údaje mimo repozitára a materializujte ich z tajomstiev v kroku, ktorý ich potrebuje. Poradie rozhoduje, či job prežije: súbor vytvorený pod sudo patrí rootovi a neprivilegovaný shell kroku doň už nemôže zapisovať.
- 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"Oba detaily v tom bloku existujú pre neskoršie kroky. S umask 077 pristane profil v režime 0600 a patrí používateľovi runnera, sudo ho stále prečíta a klient zapisuje svoj log do súboru, ktorý runner už vlastní, takže slučka pripravenosti môže ten log čítať bez druhého sudo. --writepid zaznamená PID, na ktorý bude demontáž cieliť.
Profil, ktorý sa autentizuje klientskym certifikátom, potrebuje svoj kľúč zapísaný rovnako, a profil so statickou výzvou potrebuje zodpovedajúci režim autentizácie. Profily, ktoré tlačia voľby DNS, potrebujú openvpn-systemd-resolved na Ubuntu a Debiane, pretože samotné vytlačenie na základnom obraze nič nezmení.
Pripravenosť je sonda, nie pauza
Pevný sleep vydrží presne do chvíle, keď koncentrátor spomalí, a potom krok nasadenia beží skôr, než trasa existuje. Zlyhanie sa potom vynorí vnútri nástroja na nasadenie ako timeout proti privátnemu hostu, čo o tuneli nič nehovorí.
- 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 1Slučka sleduje dve veci, pretože ktorákoľvek z nich môže byť tá rozbitá polovica. getent hosts dokazuje, že vytlačený resolver pre ten názov odpovedá, a otvorenie socketu dokazuje, že na porte, ktorý nasadenie použije, niečo počúva; profil len s trasou potrebuje doslovnú adresu a zmazaný riadok getent.
Keď slučka vyprší, log je jediná vec, ktorá oddeľuje tri rôzne závady: odmietnutý certifikát, nesprávny režim autentizácie a trasu, ktorá nikdy nedorazila. Filtrovanie pred tail udrží ten výstup dosť krátky na prečítanie, kým job stále zlyháva. Čítajte prvú chybu, nie posledný riadok, pretože klient, ktorý sa nevie autentizovať, sa opakuje, kým to slučka nevzdá. ip -4 route show dev tun0 odpovedá na jednoduchšiu otázku, či bola trasa vôbec vytlačená, a stojí jeden riadok v tej istej slučke.
Demontáž a otázka artefaktu
Uzavrite job krokom stráženým if: always(), ktorý spustí sudo kill "$(sudo cat "$RUNNER_TEMP/openvpn.pid")" a nič iné. Na zdieľanom vlastnom runnere nikdy nezabíjajte podľa názvu procesu: iný job môže vlastniť klienta s rovnakou binárkou a podobnými argumentmi. Zlyhanie potom padne na job, ktorý bežal druhý, a jeho log ukazuje na workflow, ktoré neurobilo nič zlé.
Poistka má zmysel, pretože neúspešné nasadenie aj tak nechá tunel živý. Bez always() sa upratovací krok preskočí presne vtedy, keď je potrebný, a ďalší beh štartuje proti klientovi, ktorý už je pripojený.
Zostáva jedna otázka, kým prijmete ktorýkoľvek z návrhov: potrebuje fáza buildu vôbec privátnu trasu? Agent nasadenia, ktorý už sedí v sieti, môže stiahnuť schválený artefakt, čo drží bežné buildy mimo privátnej cesty. Menej jobov držiacich tunel znamená menej miest, kde sa môže skryť zastaraná trasa.