Podurile care rulează un sidecar OpenVPN eșuează rezoluția numelor într-un model recognoscibil: numele clusterului se blochează, numele la distanță răspund până la repornirea podului, iar fișierul de resolver editat revine. Nimic din acea secvență nu e o defecțiune a tunelului. Un pod are un fișier de resolver și două lumi de nume, iar fișierul poate lista servere în ordine dar nu poate exprima zone. Soluția durabilă este un resolver care rulează în pod și deține împărțirea, astfel încât fișierul rămâne simplu și nicio politică nu are motiv să îl rescrie.

De ce modificarea făcută dispare mereu

Fișierul aparține kubelet-ului, nu ție. Sub dnsPolicy: ClusterFirst kubelet-ul îl generează ca să indice DNS-ul clusterului și îl regenerează la fiecare pornire a unui container. Tot ce schimbi prin kubectl exec trăiește în stratul inscriptibil al containerului, așa că repornirea, evacuarea sau rollout-ul îl aruncă. Specificația podului poartă în continuare aceeași politică, de aceea revine același fișier.

Setarea dnsPolicy: None oprește regenerarea și elimină și rezoluția clusterului. Câștigi un fișier pe care îl controlezi și pierzi numele de care aveai nevoie. Acest schimb este toată problema: resolv.conf nu are noțiunea de zone, doar servere încercate în ordine, deci nu poate trimite cluster.local la o adresă și o zonă privată la alta.

Rulează un resolver în pod, pe loopback

Îndrepă podul spre un singur server de nume pe loopback, apoi lasă un container CoreDNS care partajează spațiul de nume al rețelei podului să răspundă pe portul 53. Setează politica pe None, dă podului acea singură adresă și adaugă containerul DNS lângă VPN și aplicație:

spec:
  dnsPolicy: None
  dnsConfig:
    nameservers:
      - 127.0.0.1
    options:
      - name: ndots
        value: "5"
  containers:
    - name: dns
      image: coredns/coredns
      args: ["-conf", "/etc/coredns/Corefile"]
      volumeMounts:
        - {name: corefile, mountPath: /etc/coredns, readOnly: true}
    - name: vpn
      image: your-openvpn-client-image
    - name: app
      image: your-app-image
  volumes:
    - name: corefile
      configMap:
        name: split-dns-corefile

Toate trei containerele partajează un spațiu de nume de rețea, așa că 127.0.0.1:53 din containerul aplicației ajunge la CoreDNS fără serviciu, fără port-forward și fără ocol prin rețeaua clusterului. Montarea Corefile dintr-un ConfigMap îl păstrează ca intrare versionată în loc de fișier editat la fața locului. resolv.conf generat conține apoi un server de nume și nimic altceva, o stare despre care poți raționa.

Două detalii mușcă aici. Imaginea oficială leagă portul 53 ca root, iar unele politici de cluster cer să scrii asta explicit. Fiecare container din pod depinde acum de faptul că acel container unic rulează, așa că adaugă o readiness probe pe un nume inofensiv și lasă aplicația să tolereze eșecurile de pornire.

Dă fiecărei zone private propriul upstream

Un Corefile este o listă de zone, fiecare numind serverul care poate răspunde. Un bloc acoperă zona tunelului, iar blocul catch-all vine ultimul și ia tot ce niciun bloc explicit nu a revendicat. Catch-all trebuie să țintească un upstream real, niciodată înapoi la pod: .:53 { forward . 10.100.0.10 } refolosește resolverul clusterului pentru că acesta deja trimite numele publice la resolverii nodului însuși. Nimic altceva din pod nu trebuie să știe cărei rețele îi aparține un nume.

.:53 {
  errors
  cache 30
  forward . 10.100.0.10
}

svc.acme.internal:53 {
  errors
  cache 30
  forward . 192.168.240.1
}

Citește adresa clusterului din serviciul kube-dns în kube-system în loc să copiezi una dintr-un articol, pentru că CIDR-urile serviciilor diferă. Adresa tunelului vine din valoarea dhcp-option DNS trimisă de serverul OpenVPN sau de la serverul autoritativ al zonei. Dacă resolverul clusterului nu răspunde la nume publice, pune adresa resolverului nodului în blocul catch-all, citită pe nod și nu în pod.

Nu îndrepți catch-all spre /etc/resolv.conf, care este linia unică tentantă și o capcană în exact această configurație. Sub dnsPolicy: None fișierul podului însuși conține singurul server de nume 127.0.0.1, deci acea țintă este CoreDNS însuși și fiecare interogare nepotrivită se repetă până expiră. Un bloc numit svc.acme.internal se potrivește cu acel nume și cu fiecare nume de sub el, ceea ce acoperă db.svc.acme.internal și exclude svc.acme.internal.example.net. Punctul final este cosmetic, pentru că numele de zonă sunt normalizate la forma complet calificată; granița sufixului decide unde aterizează o interogare.

Decide dacă redirecționarea aparține resolverului clusterului

Dacă fiecare sarcină din spațiul de nume are nevoie de zona tunelului, un bloc de redirecționare în ConfigMap-ul CoreDNS sub kube-system costă mai puțin decât un sidecar pe pod. Schimbarea este la nivel de cluster: cere drepturi de administrator și repornirea unui deployment de care depind toți. Limiteaz-o la acea singură zonă, niciodată la rădăcină. Adresa tunelului unei singure sarcini devine atunci resolverul fiecărui pod pentru zonă, iar în ziua în care tunelul cade tot clusterul pierde numele.

Sidecarul ține raza de explozie într-un singur pod, care este valoarea implicită mai bună când doar câteva servicii au nevoie de rețeaua la distanță. Orice ai alege, notează ce resolver deține zona, pentru că următoarea persoană care depanează un timeout va întreba.

Nume care se rezolvă în timp ce conexiunile încă eșuează

Rezoluția este unul dintre cele două lucruri pe care tunelul trebuie să le ducă; celălalt este calea de întoarcere, iar rețeaua podului o ascunde bine. Dacă serverul OpenVPN rulează el însuși ca pod, regulile adăugate în acel container nu guvernează traficul care iese prin nod. Eșecul este îngust: doar podurile de pe nodul care rula și serverul primeau răspunsuri, iar restul a expirat.

Rularea serverului cu hostNetwork: true îl pune înapoi în spațiul de nume al nodului, unde o regulă FORWARD și traducerea sursei funcționează. Tradu pool-ul de clienți la ieșire, altfel niciun nod la distanță nu are rută înapoi la o adresă de tunel ca 10.8.0.6. Verifică ambele direcții înainte de a atinge din nou Corefile. Un tunel care duce interogarea dar nu răspunsul produce exact același timeout ca un resolver care nu a primit niciodată interogarea.

Verifică dintr-un pod nou, nu din sesiunea pe care ai reparat-o

Întreabă ambele zone explicit, apoi repetă interogarea după ce podul este înlocuit. O configurație care există doar într-un container aflat în execuție nu este configurație:

kubectl exec -it deploy/app -- dig @127.0.0.1 kubernetes.default.svc.cluster.local +short
kubectl exec -it deploy/app -- dig @127.0.0.1 db.svc.acme.internal +short
kubectl delete pod -l app=your-app
kubectl wait --for=condition=Ready pod -l app=your-app --timeout=90s
kubectl exec -it deploy/app -- dig @127.0.0.1 db.svc.acme.internal +short

Dacă prima pereche răspunde și perechea de după înlocuire nu, Corefile este corect și specificația podului nu. Dacă ambele răspund și aplicația tot nu se conectează, oprește depanarea DNS și testează calea TCP cu nc -vz db.svc.acme.internal 5432 din interiorul containerului. Păstrează ieșirea dig în tichet, pentru că este artefactul care separă o problemă de nume de una de rutare.

Articole similare