GitHub Actions сіздің VPN-ге жетпейді: өз раннеріңіз немесе туннель
Хостингтегі раннер — желіңізден тыс жаңа виртуалды машина. Раннерді сол желіге қойыңыз, немесе жұмыстан туннель ашып, нақты маршрутты күтіңіз.
Deploy қадамыңыз ішкі хост атауында ілініп тұр, ал сол команда ноутбугіңізден бірден жауап береді және екі машинадағы клиент жинағы бірдей. Жұмыс GitHub хостингіндегі раннерде орындалады: дәл осы бір жұмыс үшін GitHub бұлтында жасалған виртуалды машина; оның жеке мекенжай кеңістігіңізге маршруты жоқ, ішкі аймақ үшін резолвер жазбасы жоқ және жеке эндпоинт қабылдайтын сертификат та жоқ. Бұл шектеуге тек екі жоба сыйып келеді және ешқайсысын жұмыс ағынын қайта құрмай кейін қосу мүмкін емес. Бірінші YAML жолының алдында таңдаңыз, өйткені кейін көшу алғашқы әрекеттен қымбат.
Таңдау желі қазірдің өзінде бітетін жерге қойылған раннер мен бір ғана жұмыс өмір сүретін туннель арасында. Екеуі де жылдар бойы өндірістік деплойларды көтеріп келеді және әртүрлі жолмен сәтсіз болады.
Шекара шын мәнінде қайда
Ноутбукке орнатқанның бәрі ноутбукте тоқтайды, ал жұмыс кезінде орнатқанның бәрі раннермен бірге жоғалады. Клиент жүгірістер арасында байланып тұратын тұрақты желілік кеңістік жоқ, сондықтан әр жүгіріс сол қолжетімсіз күйден басталады. Azure бұл шекараны Microsoft хостингіндегі агенттер үшін құжаттайды: жеке желілерге VPN және ExpressRoute қосылымдары сонда қолдау таппайды, ал GitHub хостингіндегі раннерлер бөлек механизм емес, дәл осы шектеу пішінін алып жүреді. Мұны өнімнің қасиеті деп оқыңыз, айналып өту керек ақау деп емес.
Ешбір репозиторий параметрі мұны босаңсытпайды. Жұмыс белгісі қай пул жұмысты алатынын шешеді, ал хостингтегі белгі бүкіл жүгіріс бойы периметріңізден тыс машинаны білдіреді.
Сондықтан жеке қолжетімділік өзіңізге тиесілі нәрседен келуі керек. Желі қазірдің өзінде бітетін жерге қойылған раннер немесе бір жұмыс өмір сүретін туннель. Мақаланың қалғаны өндірісте шотты табу орнына осы екеуінің біріне әдейі төлеу туралы.
Жүгіріс жиілігі бойынша шешіңіз, әдет бойынша емес
Деплойлар күніне бірнеше рет келсе, жұмыс бірнеше жеке портты қозғаса немесе платформа командасы патчтау мен тіркелгі деректерін айналдыруды өз мойнына алса, VPC немесе кеңсе желісінің ішінде өз раннеріңізді пайдаланыңыз. Сол машинадағы жұмыс брандмауэр артындағы кез келген хост сияқты атауды шешіп, маршруттайды. Желі жұмысы орнату кезінде бір рет жасалады, әр жүгірісте емес.
Қатынас сирек болса және желіңізге тіркелгі дерегін ұстап тұратын ұзақ өмірлі агент қаламасаңыз, туннельді жұмыстың ішінде құрыңыз. Жұмыс бірнеше минут өзінің желілік клиентіне айналады және артында ештеңе қалдырмайды, бұл көбінесе бүкіл мақсат.
Туннельді таңдамас бұрын оның құнын бағалаңыз. Әр жүгіріс профильді материалдандыруға, клиентті іске қосуға, дайындыққа және бұзуға төлейді. Көтерілген, бірақ ешқашан тексерілмеген туннель жарты жолда сәтсіз болатын деплой жасайды және жеке күйді ешкім жоспарламаған пішінде қалдырады. Кейінгі қайта әрекет сирек таза болады, ал екінші сәтсіздік әдетте клиент нұсқасына жабылады.
Профильді қадам үзілмейтіндей жазу
Профильдер мен тіркелгі деректерін репозиторийден тыс ұстаңыз және оларды қажет қадамда секреттерден жасаңыз. Реттілік жұмыстың аман қалуын шешеді: sudo астында жасалған файл root-қа тиесілі, ал қадамның артықшылығы жоқ қабығы оған енді жаза алмайды.
- 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 режимінде раннер пайдаланушысының меншігінде болады, sudo әлі де оқи алады, ал клиент журналын раннер әлдеқашан иеленетін файлға жазады, сондықтан дайындық циклі бұл журналды екінші сұдосыз оқи алады. --writepid бұзу көздейтін PID-ді жазып қояды.
Клиент сертификатымен аутентификацияланатын профиль өз кілтін дәл солай жазылған қажет етеді, ал static-challenge профиліне сәйкес auth режимі керек. DNS опцияларын push ететін профильдерге Ubuntu мен Debian-да openvpn-systemd-resolved қажет, өйткені push өзі базалық бейнеде ештеңені өзгертпейді.
Дайындық — бұл зонд, үзіліс емес
Тұрақты sleep концентратор баяулаған сәтке дейін ғана шыдайды, содан кейін деплой қадамы маршрут пайда болмай тұрып орындалады. Қате содан кейін деплой құралының ішінде жеке хостқа қарсы 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 push етілген резолвер сол атауға жауап беретінін дәлелдейді, socket-тің ашылуы деплой қолданатын портта біреу тыңдап тұрғанын дәлелдейді; тек маршруты бар профильге тура мекенжай және өшірілген getent жолы қажет.
Цикл біткенде, үш түрлі ақауды ажырататын жалғыз нәрсе — журнал: қабылданбаған сертификат, дұрыс емес auth режимі және ешқашан келмеген маршрут. tail алдында сүзу бұл шығысты жұмыс әлі сәтсіз болып жатқанда оқуға жарамдыдай қысқа ұстайды. Соңғы жолды емес, бірінші қатені оқыңыз, өйткені аутентификациялана алмайтын клиент цикл берілгенше өзін қайталайды. ip -4 route show dev tun0 маршруттың мүлдем push етілген-етілмегені туралы қарапайым сұраққа жауап береді және сол циклдің ішінде бір жолды құрайды.
Бұзу және артефакт сұрағы
Жұмысты if: always() қорғайтын және тек sudo kill "$(sudo cat "$RUNNER_TEMP/openvpn.pid")" орындайтын қадаммен жабыңыз. Ортақ өз раннеріңізде ешқашан процестің атымен өлтірмеңіз: басқа жұмыста сол бинармен және ұқсас аргументтермен клиент болуы мүмкін. Сонда қате екінші болып жүгірген жұмысқа түседі, ал оның журналы ештеңе дұрыс емес жасамаған жұмыс ағынын көрсетеді.
Қорғаныс маңызды, өйткені сәтсіз деплой бәрібір тірі туннель қалдырады. always() болмаса, тазалау қадамы дәл ол қажет кезде өткізіліп кетеді, ал келесі жүгіріс әлдеқашан қосылған клиентке қарсы басталады.
Екі жобаның кез келгенін қабылдамас бұрын бір сұрақ қалады: құрастыру кезеңіне шынымен жеке маршрут керек пе? Желінің ішінде отырған деплой агенті бекітілген артефактіні тарта алады, бұл қарапайым құрастыруларды жеке жолдан алыс ұстайды. Туннель ұстайтын жұмыс неғұрлым аз болса, ескі маршрут жасырына алатын орын да соғұрлым аз.