Deploy-steget ditt heng på eit internt vertsnamn medan den same kommandoen svarar med ein gong frå laptoppen, og klientbygget på begge maskinene er identisk. Jobben køyrer på ein runner som GitHub hostar: ein virtuell maskin som vart laga for nettopp denne eine jobben i skya til GitHub, utan rute inn i det private adresserommet ditt, utan resolver-oppføring for den interne sona og utan sertifikat som den private endepunktet vil godta. Berre to design passar til denne avgrensinga, og ingen av dei kan slåast på seinare utan å byggje workflowen om. Vel mellom dei før den første YAML-linja, fordi å flytte i ettertid kostar meir enn det første forsøket.

Valet står mellom ein runner som er plassert der nettet alt sluttar, og ein tunnel som berre lever éin jobb. Begge har bore produksjonsdeploy i årevis, og dei feilar på ulike måtar.

Kvar grensa faktisk ligg

Alt du installerer på laptoppen stoppar på laptoppen, og alt du installerer i ein jobb forsvinn saman med runneren. Det finst ikkje eit varig nettnammarområde som klienten kan henge på mellom køyringar, så kvar køyring startar i den same utilgjengelege tilstanden. Azure dokumenterer denne grensa for agentar som Microsoft hostar, der VPN- og ExpressRoute-lenkjer inn i private nett ikkje er støtta, og runnerar som GitHub hostar ber den same forma for avgrensing i staden for ein eigen mekanisme. Les dette som ein eigenskap ved produktet, ikkje som ein feil som skal omgåast.

Ingen repository-innstilling mjukar opp dette. Etiketten på jobben avgjer kva pool som tek arbeidet, og ein hosta etikett tyder ei maskin utanfor perimeteren din heile køyringa.

Privat tilgjenge må difor kome frå noko du eig. Ein runner plassert der nettet alt sluttar, eller ein tunnel som lever éin jobb. Resten av artikkelen handlar om å betale for ein av desse med vilje i staden for å oppdage rekninga i produksjon.

Avgjer etter køyringsfrekvens, ikkje etter vane

Bruk eigen runner i VPC-en eller kontornettet når deploy kjem fleire gonger om dagen, når jobben rører meir enn éin privat port, eller når eit plattformteam alt har ansvar for patching og rotasjon av innloggingsdetaljar. Ein jobb på den maskina løyser og rutar som kvar annan vert bak brannmuren. Nettarbeidet skjer éin gong, ved installasjon, ikkje ved kvar køyring.

Bygg tunnelen inne i jobben når tilgangen er sporadisk og du ikkje vil ha ein langliva agent som held eit innloggingsdetalj inn i nettet ditt. Jobben blir sin eigen nettklient i nokre minutt og lèt ingenting att, noko som ofte er heile poenget.

Rekn ut kostnaden for tunnelen før du vel han. Kvar køyring betaler for materialisering av profilen, start av klienten, klargjering og riving. Ein tunnel som kjem opp men aldri blir stadfesta, gjev eit deploy som feilar halvvegs og lèt den private tilstanden att i ei form som ingen planla. Det nye forsøket etterpå er sjeldan reint, og den andre feilen blir vanlegvis lagd på klientversjonen.

Skrive profilen slik at steget ikkje kan avbrytast

Hald profilar og innloggingsdetaljar utanfor repositoryet og materialiser dei frå secret i steget som treng dei. Rekkjefølgja avgjer om jobben overlever: ei fil som er laga under sudo høyrer til root, og skalet til steget utan privilegium kan då ikkje skrive i ho.

- 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"

Begge detaljane i den blokka er for seinare steg. Med umask 077 landar profilen i modus 0600 og høyrer til runner-brukaren, sudo kan framleis lese han, og klienten skriv loggen sin til ei fil som runneren alt eig, så klargjeringsløkka kan lese den loggen utan ein andre sudo. --writepid registrerer PID-en som rivinga skal peike på.

Ein profil som autentiserer med klient-sertifikat treng nøkkelen sin skriven på same måten, og ein static-challenge-profil treng den samsvarande auth-modusen. Profilar som pushar DNS-val tek openvpn-systemd-resolved på Ubuntu og Debian, fordi pushinga åleine ikkje endrar noko på eit grunnbilete.

Klargjering er ein sondering, ikkje ei pause

Ein fast sleep held akkurat til konsentratoren blir treg, og då køyrer deploy-steget før ruta finst. Feilen kjem då opp inne i deploy-verktøyet som ein timeout mot den private verten, noko som ikkje seier noko om tunnelen.

- 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

Løkka følgjer med på to ting fordi kvar av dei kan vere den øydelagde halvdelen. getent hosts provar at den pusha resolveren svarar for det namnet, og opninga av socketen provar at noko lyttar på porten som deployet skal bruke; ein profil med berre rute treng den bokstavelege adressa og den sletta lina getent.

Når løkka går ut, er loggen det einaste som skil tre ulike feil: eit avvist sertifikat, ein galen auth-modus og ei rute som aldri kom. Filtrering før tail held den utskrifta kort nok til å lesast medan jobben framleis feilar. Les den første feilen i staden for den siste lina, fordi ein klient som ikkje kan autentisere seg repeterer seg til løkka gjev opp. ip -4 route show dev tun0 svarar på det enklare spørsmålet om ei rute vart pusha i det heile, og det kostar éi line i den same løkka.

Riving og spørsmålet om artefakten

Lukk jobben med eit steg som er verna av if: always() og som køyrer sudo kill "$(sudo cat "$RUNNER_TEMP/openvpn.pid")" og ingenting anna. På ein delt eigen runner drep aldri etter prosessnamn: ein annan jobb kan eige ein klient med same binærfila og liknande argument. Feilen landar då på den jobben som køyrde sist, og loggen hans peikar på ein workflow som ikkje gjorde noko gale.

Vernet er viktig fordi eit mislukka deploy likevel lèt ein levande tunnel att. Utan always() blir oppryddingssteget hoppa over nettopp når det trengst, og neste køyring startar mot ein klient som alt er tilkopla.

Eitt spørsmål står att før du tek til med eitt av designa: treng byggjesteget i det heile ei privat rute? Ein deployment-agent som alt sit inne i nettet kan hente ein godkjend artefakt, og det held vanlege bygg unna den private vegen. Færre jobbar som held ein tunnel tyder færre stader der ei gammal rute kan gøyme seg.

Relaterte artiklar