Deploy qadamingiz ichki hostname'da osilib qoladi, holbuki xuddi shu buyruq noutbukingizdan bir zumda javob beradi va ikkala mashinada client build bir xil. Job GitHub hostingidagi runner'da ishlaydi: aynan shu job uchun GitHub bulutida yaratilgan virtual mashina; xususiy manzil fazongizga marshrut yo'q, ichki zona uchun resolver yozuvi yo'q va xususiy endpoint qabul qiladigan sertifikat yo'q. Bu cheklovga faqat ikkita dizayn sig'adi va hech birini workflow'ni qayta qurmasdan keyin yoqib bo'lmaydi. Birinchi YAML satridan oldin tanlang, chunki keyin ko'chirish birinchi urinishdan qimmatroq.

Tanlov tarmoq allaqachon tugaydigan joyga qo'yilgan runner bilan faqat bitta job yashaydigan tunnel o'rtasida. Ikkalasi ham yillar davomida production deploy'larni ko'tarib kelgan va turli yo'llar bilan yiqiladi.

Chegara aslida qayerda

Noutbukingizga o'rnatgan hamma narsa noutbukda to'xtaydi, job davomida o'rnatgan narsa runner bilan birga yo'qoladi. Client ishga tushishlar orasida bog'lanib turadigan doimiy tarmoq namespace'i yo'q, shuning uchun har bir ishga tushish bir xil yetib bo'lmaydigan holatdan boshlanadi. Azure bu chegarani Microsoft hostingidagi agentlar uchun hujjatlashtiradi: xususiy tarmoqlarga VPN va ExpressRoute ulanishlari u yerda qo'llab-quvvatlanmaydi, GitHub hostingidagi runner'lar esa alohida mexanizm emas, aynan shu shakldagi cheklovni olib yuradi. Buni mahsulot xossasi deb o'qing, aylanib o'tiladigan nuqson deb emas.

Hech qanday repozitoriy sozlamasi buni yumshatmaydi. Job yorlig'i qaysi pool ishni olishini hal qiladi va hostingdagi yorliq butun ishga tushish davomida perimetringizdan tashqaridagi mashinani bildiradi.

Shuning uchun xususiy yetib borish o'zingizga tegishli narsadan kelishi kerak. Tarmoq allaqachon tugaydigan joyga qo'yilgan runner yoki bitta job yashaydigan tunnel. Maqolaning qolgan qismi production'da hisobni topish o'rniga shu ikkisidan birini ataylab to'lash haqida.

Chastotaga qarab qaror qiling, o'rganib qolishga qarab emas

Deploy'lar kuniga bir necha marta tushsa, job birdan ortiq xususiy portga tegsa yoki platforma jamoasi yamoqlash va hisob ma'lumotlarini almashtirishni allaqachon o'z ustiga olgan bo'lsa, VPC yoki ofis tarmog'i ichida o'z runner'ingizdan foydalaning. O'sha mashinadagi job xuddi firewall ortidagi boshqa host kabi nomni hal qiladi va marshrutlaydi. Tarmoq ishi o'rnatish paytida bir marta bo'ladi, har ishga tushishda emas.

Kirish kamdan-kam bo'lsa va tarmog'ingizga hisob ma'lumotini ushlab turadigan uzoq umrli agent kerak bo'lmasa, tunnelni job ichida quring. Job bir necha daqiqaga o'zining tarmoq client'iga aylanadi va orqasida hech narsa qoldirmaydi; ko'pincha butun maqsad shu.

Tunnelni tanlashdan oldin uning narxini baholang. Har ishga tushish profil yaratish, client ishga tushirish, tayyorlik va demontaj uchun to'laydi. Ko'tarilgan, lekin hech qachon tekshirilmagan tunnel yarim yo'lda yiqiladigan deploy keltiradi va xususiy holatni hech kim rejalashtirmagan shaklda qoldiradi. Keyingi qayta urinish kamdan-kam toza bo'ladi va ikkinchi muvaffaqiyatsizlik odatda client versiyasiga yuklanadi.

Profilni qadam uzilib qolmaydigan qilib yozish

Profillarni va hisob ma'lumotlarini repozitoriydan tashqarida saqlang va ularni kerak bo'lgan qadamda secret'lardan yarating. Tartib job omon qolishini hal qiladi: sudo ostida yaratilgan fayl root'ga tegishli va qadamning imtiyozsiz shell'i endi unga yoza olmaydi.

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

O'sha blokdagi ikkala tafsilot ham keyingi qadamlar uchun. umask 077 bilan profil 0600 rejimida runner foydalanuvchisiga tegishli bo'lib tushadi, sudo hali ham o'qiy oladi va client log'ini runner allaqachon egalik qiladigan faylga yozadi, shuning uchun tayyorlik sikli o'sha log'ni ikkinchi sudo'siz o'qiy oladi. --writepid demontaj nishonga oladigan PID'ni yozib qo'yadi.

Client sertifikati bilan autentifikatsiya qiladigan profil kalitining ham xuddi shunday yozilishini talab qiladi, static-challenge profili esa mos auth rejimini talab qiladi. DNS opsiyalarini push qiladigan profillar Ubuntu va Debian'da openvpn-systemd-resolved talab qiladi, chunki push o'zi bazaviy imejda hech narsani o'zgartirmaydi.

Tayyorlik — bu zond, pauza emas

Qat'iy sleep aynan konsentrator sekinlashguncha chidaydi, keyin deploy qadami marshrut paydo bo'lishidan oldin ishlaydi. Xato keyin deploy vositasining ichida xususiy hostga qarshi timeout bo'lib chiqadi va bu tunnel haqida hech narsa demaydi.

- 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

Sikl ikki narsani kuzatadi, chunki ularning har biri buzilgan yarim bo'lishi mumkin. getent hosts push qilingan resolver o'sha nom uchun javob berishini isbotlaydi, socket'ning ochilishi esa deploy ishlatadigan portda kimdir tinglayotganini isbotlaydi; faqat marshrutli profilga so'zma-so'z manzil va o'chirilgan getent satri kerak.

Sikl tugaganda uch xil nosozlikni ajratadigan yagona narsa — log: rad etilgan sertifikat, noto'g'ri auth rejimi va hech qachon yetib kelmagan marshrut. tail'dan oldin filtrlash o'sha chiqishni job hali yiqilib turganda o'qib bo'ladigan darajada qisqa tutadi. Oxirgi satrni emas, birinchi xatoni o'qing, chunki autentifikatsiya qila olmaydigan client sikl taslim bo'lguncha o'zini takrorlaydi. ip -4 route show dev tun0 marshrut umuman push qilinganmi degan oddiy savolga javob beradi va xuddi shu sikl ichida bir satr turadi.

Demontaj va artefakt savoli

Job'ni if: always() bilan himoyalangan va faqat sudo kill "$(sudo cat "$RUNNER_TEMP/openvpn.pid")" ishlatadigan qadam bilan yoping. Umumiy o'z runner'ingizda hech qachon jarayon nomi bo'yicha o'ldirmang: boshqa job bir xil binary va o'xshash argumentlarga ega client'ga ega bo'lishi mumkin. Keyin xato ikkinchi ishlagan job'ga tushadi va uning log'i hech qanday xato qilmagan workflow'ni ko'rsatadi.

Himoya muhim, chunki muvaffaqiyatsiz deploy baribir tirik tunnel qoldiradi. always() bo'lmasa tozalash qadami aynan kerak bo'lgan paytda tashlab ketiladi va keyingi ishga tushish allaqachon ulangan client'ga qarshi boshlanadi.

Ikkala dizayndan birini qabul qilishdan oldin bitta savol qoladi: build bosqichiga haqiqatan xususiy marshrut kerakmi? Tarmoq ichida allaqachon o'tirgan deployment agent tasdiqlangan artefaktni tortib olishi mumkin va bu oddiy build'larni xususiy yo'ldan uzoq tutadi. Tunnel ushlab turgan job qancha kam bo'lsa, eski marshrut yashirinadigan joy shuncha kam.

O'xshash maqolalar