നിങ്ങളുടെ deploy ഘട്ടം ഒരു ആന്തരിക hostname-ൽ തൂങ്ങിക്കിടക്കുന്നു, അതേ കമാൻഡ് നിങ്ങളുടെ ലാപ്ടോപ്പിൽ നിന്ന് ഉടൻ ഉത്തരം നൽകുന്നു, രണ്ട് മെഷീനുകളിലും client build ഒന്നുതന്നെ. job GitHub-ഹോസ്റ്റ് ചെയ്ത runner-ൽ പ്രവർത്തിക്കുന്നു: ആ ഒരു job-നായി GitHub-ന്റെ ക്ലൗഡിൽ സൃഷ്ടിച്ച വെർച്വൽ മെഷീൻ, നിങ്ങളുടെ സ്വകാര്യ വിലാസ മേഖലയിലേക്ക് റൂട്ടില്ല, ആന്തരിക സോണിന് resolver എൻട്രിയില്ല, സ്വകാര്യ endpoint സ്വീകരിക്കുന്ന സർട്ടിഫിക്കറ്റുമില്ല. ഈ പരിധിയിൽ രണ്ട് ഡിസൈനുകൾ മാത്രം ഒതുങ്ങുന്നു, workflow വീണ്ടും നിർമ്മിക്കാതെ ഒന്നും പിന്നീട് ഓണാക്കാനാവില്ല. YAML-ന്റെ ആദ്യ വരിക്ക് മുമ്പേ ഇവയിൽ നിന്ന് തിരഞ്ഞെടുക്കുക, കാരണം പിന്നീടുള്ള കുടിയേറ്റം ആദ്യ ശ്രമത്തേക്കാൾ ചെലവേറിയതാണ്.

തിരഞ്ഞെടുപ്പ് നെറ്റ്വർക്ക് ഇതിനകം അവസാനിക്കുന്നിടത്ത് വയ്ക്കുന്ന runner-നും ഒരു job മാത്രം ജീവിക്കുന്ന ടണലിനും ഇടയിലാണ്. രണ്ടും വർഷങ്ങളായി production deploy വഹിക്കുന്നു, വ്യത്യസ്ത രീതികളിൽ പരാജയപ്പെടുന്നു.

അതിർത്തി യഥാർത്ഥത്തിൽ എവിടെയാണ്

നിങ്ങൾ ലാപ്ടോപ്പിൽ ഇൻസ്റ്റാൾ ചെയ്യുന്നതെല്ലാം ലാപ്ടോപ്പിൽത്തന്നെ നിൽക്കുന്നു, job സമയത്ത് ഇൻസ്റ്റാൾ ചെയ്യുന്നത് runner-നൊപ്പം മായുന്നു. റണുകൾക്കിടയിൽ client പറ്റിപ്പിടിച്ചിരിക്കുന്ന ശാശ്വത നെറ്റ്വർക്ക് namespace ഇല്ല, അതിനാൽ ഓരോ റണ്ണും അതേ എത്തിച്ചേരാനാവാത്ത അവസ്ഥയിൽ നിന്ന് ആരംഭിക്കുന്നു. Azure ഈ അതിർത്തി Microsoft-ഹോസ്റ്റ് ചെയ്ത agents-നായി രേഖപ്പെടുത്തുന്നു, അവിടെ സ്വകാര്യ നെറ്റ്വർക്കുകളിലേക്കുള്ള VPN, ExpressRoute ലിങ്കുകൾ പിന്തുണയ്ക്കുന്നില്ല, GitHub-ഹോസ്റ്റ് ചെയ്ത runners അതേ തരത്തിലുള്ള നിയന്ത്രണം വഹിക്കുന്നു, വേറൊരു സംവിധാനമല്ല. ഇത് ഉൽപ്പന്നത്തിന്റെ സ്വഭാവമായി വായിക്കുക, ഒഴിവാക്കേണ്ട തകരാറായി അല്ല.

repository-യുടെ ഒരു സെറ്റിംഗും ഇത് അയച്ചുവിടുന്നില്ല. job-ന്റെ ലേബൽ ഏത് pool ജോലി ഏൽക്കുമെന്ന് തീരുമാനിക്കുന്നു, ഹോസ്റ്റ് ചെയ്ത ലേബൽ എന്നാൽ മുഴുവൻ റണ്ണിനും നിങ്ങളുടെ പരിധിക്ക് പുറത്തുള്ള ഒരു മെഷീൻ.

അതിനാൽ സ്വകാര്യ എത്തിച്ചേരൽ നിങ്ങളുടെ ഉടമസ്ഥതയിലുള്ള എന്തിൽ നിന്നോ വരണം. നെറ്റ്വർക്ക് ഇതിനകം അവസാനിക്കുന്നിടത്ത് വച്ച runner, അല്ലെങ്കിൽ ഒരു job ജീവിക്കുന്ന ടണൽ. ബാക്കി ലേഖനം ഇവയിൽ ഒന്നിന് ബോധപൂർവം പണം നൽകുന്നതിനെക്കുറിച്ചാണ്, production-ൽ ബിൽ കണ്ടെത്തുന്നതിന് പകരം.

റൺ ആവൃത്തി നോക്കി തീരുമാനിക്കുക, പരിചയം നോക്കി അല്ല

deploy-കൾ ദിവസത്തിൽ പലതവണ വരുമ്പോൾ, job ഒന്നിൽ കൂടുതൽ സ്വകാര്യ പോർട്ടുകൾ തൊടുമ്പോൾ, അല്ലെങ്കിൽ പ്ലാറ്റ്ഫോം ടീം ഇതിനകം patching-ഉം credential rotation-ഉം നോക്കുമ്പോൾ, VPC-യിലോ ഓഫീസ് നെറ്റ്വർക്കിലോ സ്വന്തം runner ഉപയോഗിക്കുക. ആ മെഷീനിൽ job മറ്റേതൊരു host പോലെയും firewall-ന് പിന്നിൽ resolve ചെയ്ത് route ചെയ്യുന്നു. നെറ്റ്വർക്ക് ജോലി ഒരിക്കൽ, ഇൻസ്റ്റാളേഷൻ സമയത്ത് നടക്കുന്നു, ഓരോ റണ്ണിലും അല്ല.

പ്രവേശനം ഇടയ്ക്കിടെ മാത്രമാകുമ്പോൾ, നിങ്ങളുടെ നെറ്റ്വർക്കിലേക്ക് credential പിടിച്ചിരിക്കുന്ന ദീർഘായുസ്സ് agent വേണ്ടെന്ന് തോന്നുമ്പോൾ, ടണൽ job-നുള്ളിൽ നിർമ്മിക്കുക. job കുറച്ച് മിനിറ്റ് സ്വന്തം നെറ്റ്വർക്ക് client ആകുന്നു, പിന്നിൽ ഒന്നും വിടുന്നില്ല, അതാണ് പലപ്പോഴും മുഴുവൻ ഉദ്ദേശ്യം.

ടണൽ തിരഞ്ഞെടുക്കുന്നതിന് മുമ്പ് അതിന്റെ ചെലവ് കണക്കാക്കുക. ഓരോ റണ്ണും profile നിർമ്മാണം, client തുടക്കം, തയ്യാറെടുപ്പ്, പൊളിക്കൽ എന്നിവയ്ക്ക് പണം നൽകുന്നു. കയറുന്നതും എന്നും പരിശോധിക്കാത്തതുമായ ടണൽ, പകുതിയിൽ പരാജയപ്പെടുന്ന deploy ഉണ്ടാക്കി ആരും ആസൂത്രണം ചെയ്യാത്ത രൂപത്തിൽ സ്വകാര്യ അവസ്ഥ വിടുന്നു. അതിന് ശേഷമുള്ള വീണ്ടും ശ്രമം അപൂർവമായേ വ്യക്തമാകൂ, രണ്ടാം പരാജയം സാധാരണയായി client പതിപ്പിന് മേൽ ചുമത്തപ്പെടുന്നു.

ഘട്ടം നിൽക്കാതിരിക്കാൻ profile എഴുതുക

profiles-ഉം credentials-ഉം repository-ക്ക് പുറത്ത് വയ്ക്കുക, അവ ആവശ്യമുള്ള ഘട്ടത്തിൽത്തന്നെ secrets-ൽ നിന്ന് നിർമ്മിക്കുക. ക്രമം job അതിജീവിക്കുമോ എന്ന് തീരുമാനിക്കുന്നു: sudo-യുടെ കീഴിൽ സൃഷ്ടിച്ച ഫയൽ root-ന്റതാണ്, ഘട്ടത്തിന്റെ പ്രത്യേകാവകാശമില്ലാത്ത shell-ന് അതിൽ എഴുതാനാവില്ല.

- 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 ഉപയോഗിച്ച് profile 0600 മോഡിൽ runner ഉപയോക്താവിന്റെ ഉടമസ്ഥതയിൽ എത്തുന്നു, sudo ഇപ്പോഴും വായിക്കാം, client തന്റെ log runner ഇതിനകം സ്വന്തമാക്കിയ ഫയലിൽ എഴുതുന്നു, അതിനാൽ തയ്യാറെടുപ്പ് ലൂപ്പിന് രണ്ടാം sudo ഇല്ലാതെ ആ log വായിക്കാം. --writepid പൊളിക്കൽ ലക്ഷ്യമിടുന്ന PID രേഖപ്പെടുത്തുന്നു.

client സർട്ടിഫിക്കറ്റ് ഉപയോഗിച്ച് പ്രാമാണീകരിക്കുന്ന profile-ന് അതിന്റെ കീ അതേ രീതിയിൽ എഴുതിയിരിക്കണം, static-challenge profile-ന് യോജിക്കുന്ന auth മോഡ് വേണം. DNS ഓപ്ഷനുകൾ push ചെയ്യുന്ന profiles-ന് Ubuntu-യിലും Debian-ലും openvpn-systemd-resolved വേണം, കാരണം push മാത്രം ബേസ് ഇമേജിൽ ഒന്നും മാറ്റുന്നില്ല.

തയ്യാറെടുപ്പ് ഒരു പരിശോധനയാണ്, ഇടവേളയല്ല

നിശ്ചിത sleep concentrator മന്ദഗതിയിലാകുന്നതുവരെ മാത്രം നിലനിൽക്കും, പിന്നീട് deploy ഘട്ടം റൂട്ട് ഉണ്ടാകുന്നതിന് മുമ്പേ പ്രവർത്തിക്കുന്നു. പരാജയം പിന്നീട് deploy ഉപകരണത്തിനുള്ളിൽ സ്വകാര്യ host-നെതിരെ 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 ചെയ്ത resolver ആ പേരിന് ഉത്തരം നൽകുന്നു എന്ന് തെളിയിക്കുന്നു, socket തുറക്കുന്നത് deploy ഉപയോഗിക്കുന്ന പോർട്ടിൽ എന്തോ കേൾക്കുന്നു എന്ന് തെളിയിക്കുന്നു; റൂട്ട് മാത്രമുള്ള profile-ന് അക്ഷരാർത്ഥ വിലാസവും മായ്ച്ച getent വരിയും വേണം.

ലൂപ്പ് അവസാനിക്കുമ്പോൾ, മൂന്ന് വ്യത്യസ്ത തകരാറുകളെ വേർതിരിക്കുന്നത് log മാത്രമാണ്: നിരസിച്ച സർട്ടിഫിക്കറ്റ്, തെറ്റായ auth മോഡ്, ഒരിക്കലും വരാത്ത റൂട്ട്. tail-ന് മുമ്പ് ഫിൽട്ടർ ചെയ്യുന്നത് ആ ഔട്ട്പുട്ട് job ഇപ്പോഴും പരാജയപ്പെടുമ്പോൾ വായിക്കാവുന്നത്ര ചെറുതായി നിർത്തുന്നു. ആദ്യ പിശക് വായിക്കുക, അവസാന വരിയല്ല, കാരണം പ്രാമാണീകരിക്കാനാവാത്ത client ലൂപ്പ് കീഴടങ്ങുന്നതുവരെ സ്വയം ആവർത്തിക്കുന്നു. ip -4 route show dev tun0 റൂട്ട് എങ്കിലും push ചെയ്തോ എന്ന ലളിത ചോദ്യത്തിന് ഉത്തരം നൽകുന്നു, അതേ ലൂപ്പിൽ ഒരു വരിയുടെ ചെലവ്.

പൊളിക്കലും artifact ചോദ്യവും

job അവസാനിപ്പിക്കുന്നത് if: always() കാത്തുസൂക്ഷിക്കുന്ന ഘട്ടത്തോടെയാകട്ടെ, അത് sudo kill "$(sudo cat "$RUNNER_TEMP/openvpn.pid")" മാത്രം പ്രവർത്തിപ്പിക്കുന്നു. പങ്കിട്ട സ്വന്തം runner-ൽ ഒരിക്കലും പ്രക്രിയയുടെ പേരിൽ കൊല്ലരുത്: മറ്റൊരു job-ന് അതേ binary-യും സമാന argument-കളുമുള്ള client ഉണ്ടാകാം. അപ്പോൾ പരാജയം രണ്ടാമത് ഓടിയ job-ന്റെ മേൽ വീഴുന്നു, അതിന്റെ log ഒന്നും തെറ്റ് ചെയ്യാത്ത workflow-ലേക്ക് ചൂണ്ടുന്നു.

സംരക്ഷണം പ്രധാനമാണ്, കാരണം പരാജയപ്പെട്ട deploy എങ്കിലും ജീവനുള്ള ടണൽ വിടുന്നു. always() ഇല്ലാതെ വൃത്തിയാക്കൽ ഘട്ടം ആവശ്യമുള്ള സമയത്തുതന്നെ ഒഴിവാക്കപ്പെടുന്നു, അടുത്ത റൺ ഇതിനകം ബന്ധിപ്പിച്ച client-ന് എതിരെ ആരംഭിക്കുന്നു.

ഏതെങ്കിലും ഡിസൈൻ സ്വീകരിക്കുന്നതിന് മുമ്പ് ഒരു ചോദ്യം ബാക്കിയുണ്ട്: build ഘട്ടത്തിന് യഥാർത്ഥത്തിൽ സ്വകാര്യ റൂട്ട് വേണോ? ഇതിനകം നെറ്റ്വർക്കിനുള്ളിൽ ഇരിക്കുന്ന deployment agent അംഗീകൃത artifact വലിച്ചെടുക്കാം, ഇത് സാധാരണ builds-നെ സ്വകാര്യ പാതയിൽ നിന്ന് അകറ്റി നിർത്തുന്നു. കുറച്ച് job ടണൽ പിടിക്കുന്നു എന്നാൽ പഴയ റൂട്ട് ഒളിക്കാനാകുന്ന കുറച്ച് സ്ഥലങ്ങൾ.

അനുബന്ധ ലേഖനങ്ങൾ