GitHub Actions VPN-inizə çatmır: öz hostinqinizdə runner və ya tunel
Hostinqdəki runner şəbəkənizdən kənarda yeni VM-dir. Ya runner-i həmin şəbəkənin içinə qoyun, ya da işdən tunel açıb real marşrutu gözləyin.
Yerləşdirmə addımınız daxili host adında asılı qalır, halbuki eyni əmr noutbukdan dərhal cavab verir və hər iki maşındakı klient quruluşu eynidir. İş GitHub tərəfindən hostinq edilən runner-də çalışır: yalnız həmin iş üçün GitHub-ın buludunda yaradılmış virtual maşın; şəxsi ünvan məkanınıza marşrut yoxdur, daxili zona üçün resolver qeydi yoxdur və şəxsi son nöqtənin qəbul edəcəyi sertifikat yoxdur. Bu məhdudiyyətə yalnız iki dizayn uyğun gəlir və heç biri iş axınını yenidən qurmadan sonradan işə salına bilməz. YAML-ın ilk sətrindən əvvəl onların arasında seçim edin, çünki sonradan miqrasiya ilk cəhddən baha başa gəlir.
Seçim şəbəkənin artıq bitdiyi yerə yerləşdirilən runner ilə bir işin müddəti qədər mövcud olan tunel arasındadır. Hər ikisi illərlə istehsalat yerləşdirmələri daşıyıb və fərqli şəkildə uğursuz olur.
Sərhəd əslində harada yerləşir
Noutbukunuza quraşdırdığınız hər şey noutbukunuzda dayanır və iş zamanı quraşdırdığınız hər şey runner ilə birlikdə yox olur. Çalışmalar arasında klientin bağlı qala biləcəyi daimi şəbəkə ad məkanı yoxdur, ona görə hər çalışma eyni əlçatmaz vəziyyətdən başlayır. Azure bu sərhədi Microsoft tərəfindən hostinq edilən agentlər üçün sənədləşdirir; orada şəxsi şəbəkələrə VPN və ExpressRoute bağlantıları dəstəklənmir və GitHub tərəfindən hostinq edilən runner-lər ayrı mexanizm deyil, həmin məhdudiyyət formasını daşıyır. Bunu məhsul xassəsi kimi oxuyun, yanından keçilməli qüsur kimi deyil.
Heç bir repozitoriya parametri bunu yumşaltmır. İş etiketi işi hansı hovuzun götürəcəyini müəyyən edir və hostinq edilmiş etiket bütün çalışma boyu perimetrinizdən kənarda olan maşın deməkdir.
Şəxsi əlçatanlıq buna görə sahib olduğunuz bir şeydən gəlməlidir. Şəbəkənin artıq bitdiyi yerə qoyulan runner, və ya bir iş üçün yaşayan tunel. Bu məqalənin qalan hissəsi istehsalatda hesabı kəşf etmək əvəzinə bu ikisindən birini qəsdən ödəməkdən bəhs edir.
Tanışlığa görə deyil, iş tezliyinə görə qərar verin
Yerləşdirmələr gündə bir neçə dəfə baş verəndə, iş birdən çox şəxsi porta toxunanda və ya platforma komandası artıq yamaq və etimadnamə rotasiyasına sahib olduqda VPC və ya ofis şəbəkəsi daxilində öz hostinqinizdə runner-ə müraciət edin. Həmin maşındakı iş qoruyucu divarın arxasındakı hər hansı digər host kimi həll edir və marşrutlaşdırır. Şəbəkə işi hər çalışmada deyil, quraşdırma zamanı bir dəfə görülür.
Giriş təsadüfi olduqda və şəbəkənizə etimadnamə saxlayan uzunömürlü agent istəmədikdə tuneli işin içində qurun. İş bir neçə dəqiqə öz şəbəkə klienti olur və arxasında heç nə qoymur, bu da çox vaxt bütün məsələdir.
Tuneli seçməzdən əvvəl onun xərcini təxmin edin. Hər çalışma profil maddiləşdirməsi, klient başlanğıcı, hazırlıq və sökmə üçün ödəyir. Qalxan amma heç vaxt yoxlanılmayan tunel yarıda uğursuz olan və şəxsi vəziyyəti heç kimin planlaşdırmadığı formada qoyan yerləşdirmə yaradır. Bundan sonrakı təkrar cəhd nadir hallarda təmiz olur və ikinci uğursuzluq adətən klient versiyasının üstünə atılır.
Profili elə yazın ki, addım dayana bilməsin
Profilləri və etimadnamələri repozitoriyadan kənarda saxlayın və onları ehtiyac duyan addımda sirlərdən maddiləşdirin. Sıra işin sağ qalıb-qalmayacağını həll edir: sudo altında yaradılan fayl root-a aiddir və imtiyazsız addım qabığı bundan sonra ona yaza bilmir.
- 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"Həmin blokdakı hər iki detal sonrakı addımlar üçün mövcuddur. umask 077 ilə profil runner istifadəçisinə məxsus 0600 rejimində qalır, sudo onu hələ də oxuya bilir və klient öz jurnalını runner-in artıq sahib olduğu fayla yazır, beləliklə hazırlıq dövrəsi həmin jurnalı ikinci sudo olmadan oxuya bilir. --writepid sökülmənin hədəfləyəcəyi PID-i qeyd edir.
Klient sertifikatı ilə autentifikasiya edən profilin açarı eyni şəkildə yazılmalıdır və statik çağırış profili uyğun autentifikasiya rejiminə ehtiyac duyur. DNS seçimlərini itələyən profillər openvpn-systemd-resolved Ubuntu və Debian-da lazımdır, çünki itələmə özü baza obrazında heç nəyi dəyişmir.
Hazırlıq fasilə deyil, yoxlamadır
Sabit yatma mərhələsi konsentrator yavaşlayana qədər işləyir və sonra yerləşdirmə addımı marşrut yaranmadan çalışır. Uğursuzluq sonra yerləşdirmə alətinin içində şəxsi hosta qarşı fasilə kimi üzə çıxır və bu, tunel haqqında heç nə demir.
- 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 1Dövrə iki müşahidəyə baxır, çünki onlardan hər hansı biri sınmış yarım ola bilər. getent hosts itələnmiş resolver-in həmin ad üçün cavab verdiyini sübut edir və soketin açılması yerləşdirmənin istifadə edəcəyi portda nəyinsə dinlədiyini sübut edir; yalnız marşruta əsaslanan profil hərfi ünvana ehtiyac duyur və getent sətri silinməlidir.
Dövrə bitdikdə jurnal üç fərqli nasazlığı ayıran yeganə şeydir: rədd edilmiş sertifikat, səhv autentifikasiya rejimi və heç vaxt gəlməyən marşrut. Quyruqdan əvvəl filtrləmə iş hələ uğursuz olarkən həmin çıxışı oxuna biləcək qədər qısa saxlayır. Son sətir əvəzinə ilk xətanı oxuyun, çünki autentifikasiya edə bilməyən klient dövrə təslim olana qədər özünü təkrarlayır. ip -4 route show dev tun0 marşrutun ümumiyyətlə itələnib-itələnmədiyi ilə bağlı daha sadə suala cavab verir və eyni dövrənin içində bir sətirə başa gəlir.
Sökmə və artefakt məsələsi
İşi if: always() ilə qorunan və yalnız sudo kill "$(sudo cat "$RUNNER_TEMP/openvpn.pid")" icra edən addımla bağlayın. Paylaşılan öz hostinqli runner-də heç vaxt proses adına görə öldürməyin: başqa iş eyni binar və oxşar arqumentlərə malik klientə sahib ola bilər. Uğursuzluq sonra ikinci işləyən işin üstünə düşür və onun jurnalı heç bir səhv etməyən iş axınına işarə edir.
Qoruma vacibdir, çünki uğursuz yerləşdirmə hələ də canlı tunel qoyub gedir. always() olmadan təmizləmə addımı məhz lazım olduğu anda atlanır və növbəti çalışma artıq qoşulmuş klientə qarşı başlayır.
Hər iki dizaynı qəbul etməzdən əvvəl bir sual qalır: qurma mərhələsinə ümumiyyətlə şəxsi marşrut lazımdırmı? Artıq şəbəkənin içində oturan yerləşdirmə agenti təsdiqlənmiş artefaktı çəkə bilər və bu, adi quruluşları şəxsi yoldan uzaq saxlayır. Tunel saxlayan daha az iş, köhnə marşrutun gizlənə biləcəyi daha az yer deməkdir.