Langkah deploy anda tergantung pada nama hos dalaman sedangkan arahan yang sama menjawab serta-merta dari komputer riba, dan build klien pada kedua-dua mesin adalah sama. Job berjalan pada runner yang dihoskan GitHub: mesin maya yang dicipta untuk job itu sahaja di dalam awan GitHub, tanpa laluan ke ruang alamat peribadi anda, tanpa entri resolver untuk zon dalaman dan tanpa sijil yang akan diterima endpoint peribadi. Hanya dua reka bentuk yang sesuai dengan kekangan itu, dan kedua-duanya tidak boleh dihidupkan kemudian tanpa membina semula workflow. Pilih antara keduanya sebelum baris YAML pertama, kerana berhijrah selepas itu lebih mahal daripada percubaan pertama.

Pilihannya antara runner yang diletakkan di tempat rangkaian sudah berakhir dan terowong yang hidup selama satu job. Kedua-duanya telah menyokong deploy produksi bertahun-tahun, dan kedua-duanya gagal dengan cara berbeza.

Di mana sempadan sebenarnya

Apa sahaja yang anda pasang pada komputer riba berhenti pada komputer riba, dan apa sahaja yang anda pasang semasa job hilang bersama runner. Tiada namespace rangkaian kekal tempat klien boleh terus berpaut antara larian, jadi setiap larian bermula dari keadaan tidak dapat dicapai yang sama. Azure mendokumenkan sempadan ini untuk agen yang dihoskan Microsoft, di mana pautan VPN dan ExpressRoute ke rangkaian peribadi tidak disokong, dan runner yang dihoskan GitHub membawa bentuk sekatan yang sama, bukan mekanisme berasingan. Bacalah sebagai sifat produk, bukan kecacatan yang perlu dielakkan.

Tiada tetapan repositori yang melonggarkannya. Label job menentukan pool mana yang mengambil kerja, dan label dihoskan bermakna mesin di luar perimeter anda sepanjang larian.

Jadi kebolehcapaian peribadi mesti datang daripada sesuatu yang anda miliki. Runner yang diletakkan di tempat rangkaian sudah berakhir, atau terowong yang hidup satu job. Selebihnya artikel ini membincangkan membayar salah satunya secara sengaja, bukan menemui bilnya di produksi.

Tentukan mengikut kekerapan larian, bukan mengikut kebiasaan

Gunakan runner sendiri di dalam VPC atau rangkaian pejabat apabila deploy masuk beberapa kali sehari, apabila job menyentuh lebih daripada satu port peribadi, atau apabila pasukan platform sudah mengendalikan patching dan putaran kelayakan. Job pada mesin itu menyelesaikan dan menghalakan seperti mana-mana hos lain di belakang firewall. Kerja rangkaian berlaku sekali, semasa pemasangan, bukan setiap larian.

Bina terowong di dalam job apabila akses jarang berlaku dan anda tidak mahu agen panjang hayat memegang kelayakan ke dalam rangkaian anda. Job menjadi klien rangkaiannya sendiri untuk beberapa minit dan tidak meninggalkan apa-apa, yang selalunya menjadi intinya.

Anggarkan kos terowong sebelum memilihnya. Setiap larian membayar untuk pembentukan profil, permulaan klien, kesediaan dan pembongkaran. Terowong yang naik tetapi tidak pernah disahkan menghasilkan deploy yang gagal separuh jalan dan meninggalkan keadaan peribadi dalam bentuk yang tidak dirancang sesiapa. Percubaan semula selepas itu jarang bersih, dan kegagalan kedua biasanya disalahkan pada versi klien.

Menulis profil supaya langkah tidak boleh terbantut

Simpan profil dan kelayakan di luar repositori dan bentukkannya daripada secret dalam langkah yang memerlukannya. Urutan menentukan sama ada job bertahan: fail yang dicipta di bawah sudo milik root, dan shell langkah tanpa keistimewaan tidak lagi boleh menulis ke dalamnya.

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

Kedua-dua butiran dalam blok itu ada untuk langkah seterusnya. Dengan umask 077 profil mendarat pada mod 0600 milik pengguna runner, sudo masih boleh membacanya, dan klien menulis log ke fail yang sudah dimiliki runner, jadi gelung kesediaan boleh membaca log itu tanpa sudo kedua. --writepid merekod PID yang akan disasarkan oleh pembongkaran.

Profil yang mengesahkan dengan sijil klien perlu kuncinya ditulis dengan cara yang sama, dan profil static-challenge perlu mod auth yang sepadan. Profil yang menolak pilihan DNS perlu openvpn-systemd-resolved pada Ubuntu dan Debian, kerana tolakan itu sahaja tidak mengubah apa-apa pada imej asas.

Kesediaan ialah probe, bukan jeda

Sleep tetap bertahan sehingga concentrator menjadi perlahan, dan ketika itu langkah deploy berjalan sebelum laluan wujud. Kegagalan kemudian muncul di dalam alat deploy sebagai timeout ke hos peribadi, yang tidak memberitahu apa-apa tentang terowong.

- 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

Gelung memerhati dua perkara kerana mana-mana satu boleh menjadi separuh yang rosak. getent hosts membuktikan resolver yang ditolak menjawab untuk nama itu, dan pembukaan socket membuktikan ada sesuatu yang mendengar pada port yang akan digunakan deploy; profil yang hanya ada laluan perlu alamat literal dan baris getent dipadam.

Apabila gelung tamat, log ialah satu-satunya perkara yang memisahkan tiga kegagalan berbeza: sijil ditolak, mod auth salah dan laluan yang tidak pernah tiba. Menapis sebelum tail mengekalkan output itu cukup pendek untuk dibaca semasa job masih gagal. Baca ralat pertama bukan baris terakhir, kerana klien yang tidak boleh mengesahkan mengulangi dirinya sehingga gelung menyerah. ip -4 route show dev tun0 menjawab soalan yang lebih mudah sama ada laluan pernah ditolak, dan kosnya satu baris dalam gelung yang sama.

Pembongkaran dan persoalan artifak

Tutup job dengan langkah yang dijaga if: always() yang menjalankan sudo kill "$(sudo cat "$RUNNER_TEMP/openvpn.pid")" dan tidak lain. Pada runner sendiri yang dikongsi, jangan sekali-kali bunuh mengikut nama proses: job lain mungkin memiliki klien dengan binari dan hujah yang serupa. Kegagalan kemudian jatuh pada job yang berjalan kedua, dan lognya menunjuk kepada workflow yang tidak melakukan kesalahan.

Perlindungan itu penting kerana deploy yang gagal tetap meninggalkan terowong hidup. Tanpa always() langkah pembersihan dilangkau tepat ketika ia diperlukan, dan larian seterusnya bermula terhadap klien yang sudah bersambung.

Tinggal satu soalan sebelum menerima mana-mana reka bentuk: adakah peringkat build benar-benar memerlukan laluan peribadi? Agen deployment yang sudah berada di dalam rangkaian boleh menarik artifak yang diluluskan, dan itu menjauhkan build biasa daripada laluan peribadi. Lebih sedikit job yang memegang terowong bermakna lebih sedikit tempat laluan lapuk boleh bersembunyi.

Artikel berkaitan