Slik deler du DNS mellom Kubernetes og en OpenVPN-sidecar
En sidecar-pod trenger to navneverdener. Pek én loopback-resolver mot klyngen og tunnelen, og slutt å stole på en redigert resolv.conf.
Pod-er som kjører en OpenVPN-sidecar feiler i navneoppslag med et gjenkjennelig mønster: klyngenavn henger, fjernnavn svarer til pod-en startes på nytt, og resolver-filen du redigerte går tilbake. Ingenting i den sekvensen er en tunnelfeil. En pod har én resolver-fil og to navneverdener, og filen kan liste servere i rekkefølge men ikke uttrykke soner. Den varige løsningen er en resolver som kjører inne i pod-en og eier delingen, slik at filen forblir enkel og ingen policy har grunn til å skrive den på nytt.
Hvorfor endringen du gjorde stadig forsvinner
Filen tilhører kubelet, ikke deg. Under dnsPolicy: ClusterFirst genererer kubelet den for å peke på klynge-DNS, og genererer den på nytt hver gang en container starter. Alt du endrer via kubectl exec lever i containerens skrivbare lag, så omstart, utkastelse eller rollout kaster det. Pod-spesifikasjonen bærer fortsatt samme policy, og derfor kommer samme fil tilbake.
Å sette dnsPolicy: None stopper regenereringen og fjerner også klyngeoppslaget. Du får en fil du kontrollerer og mister navnene du trengte. Den byttet er hele problemet: resolv.conf har ikke begrep om soner, bare servere som prøves i rekkefølge, så den kan ikke sende cluster.local til én adresse og en privat sone til en annen.
Kjør én resolver i pod-en, på loopback
Pek pod-en mot én navneserver på loopback, og la deretter en CoreDNS-container som deler pod-ens nettverksnavnerom svare på port 53. Sett policyen til None, gi pod-en den ene adressen, og legg til DNS-containeren ved siden av VPN-en og applikasjonen:
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-corefileAlle tre containerne deler ett nettverksnavnerom, så 127.0.0.1:53 fra applikasjonscontaineren når CoreDNS uten tjeneste, uten port-forward og uten omvei gjennom klyngenettet. Å montere Corefile fra en ConfigMap holder den som versjonert input i stedet for en fil som redigeres på stedet. Den genererte resolv.conf holder da én navneserver og ingenting annet, en tilstand du kan resonnere om.
To detaljer biter her. Det offisielle imaget binder port 53 som root, og enkelte klyngepolicyer krever at du skriver det eksplisitt. Hver container i pod-en avhenger nå av at den ene containeren kjører, så legg til en readiness-probe mot et ufarlig navn og la applikasjonen tåle oppstartsfeil.
Gi hver privat sone sin egen upstream
En Corefile er en liste over soner, hver navngir serveren som kan svare på den. Én blokk dekker tunnel-sonen, og catch-all-blokken kommer sist og tar alt ingen eksplisitt blokk har gjort krav på. Catch-all må peke på en ekte upstream, aldri tilbake til pod-en: .:53 { forward . 10.100.0.10 } gjenbruker klynge-resolveren fordi den allerede videresender offentlige navn til nodens egne resolvere. Ingenting annet i pod-en trenger å vite hvilket nettverk et navn tilhører.
.:53 {
errors
cache 30
forward . 10.100.0.10
}
svc.acme.internal:53 {
errors
cache 30
forward . 192.168.240.1
}Les klyngeadressen fra kube-dns-tjenesten i kube-system i stedet for å kopiere en fra en artikkel, fordi tjeneste-CIDR-ene varierer. Tunneladressen kommer fra dhcp-option DNS-verdien OpenVPN-serveren sender, eller fra den autoritative serveren for sonen. Hvis klynge-resolveren din ikke svarer på offentlige navn, legg nodens resolveradresse i catch-all-blokken, lest på noden og ikke inne i pod-en.
Ikke pek catch-all mot /etc/resolv.conf, som er den fristende enlinjeren og en felle i akkurat dette oppsettet. Under dnsPolicy: None inneholder pod-ens egen fil den eneste navneserveren 127.0.0.1, så målet er CoreDNS selv og hver ikke-matchene spørring gjentas til den utløper. En blokk kalt svc.acme.internal matcher det navnet og hvert navn under det, som dekker db.svc.acme.internal og utelukker svc.acme.internal.example.net. Punktumet til slutt er kosmetisk, fordi sonenavn normaliseres til fullt kvalifisert form; suffiksgrensen avgjør hvor en spørring lander.
Avgjør om videresendingen hører til klynge-resolveren
Hvis hver arbeidsbelastning i navnerommet trenger tunnel-sonen, er en videresendingsblokk i CoreDNS ConfigMap under kube-system billigere enn en sidecar per pod. Den endringen er på klyngenivå: den krever administratortilgang og omstart av en deployment alle er avhengige av. Begrens den til den ene sonen, aldri til roten. Tunneladressen til én arbeidsbelastning blir da resolveren for hver pod for sonen, og dagen tunnelen faller mister hele klyngen navnet.
Sidecaren holder eksplosjonsradiusen inne i én pod, som er en bedre standard når bare noen få tjenester trenger fjernnettet. Uansett hva du velger, noter hvilken resolver som eier sonen, fordi neste person som feilsøker en timeout vil spørre.
Navn som løses mens tilkoblinger fortsatt feiler
Oppslag er én av to ting tunnelen må bære; den andre er returveien, og pod-nettet skjuler den godt. Hvis OpenVPN-serveren selv kjører som en pod, styrer ikke reglene du legger til i den containeren trafikken som går ut via noden. Feilen er smal: bare pod-ene på noden som også kjørte serveren fikk svar, og alt annet gikk ut på tid.
Å kjøre serveren med hostNetwork: true setter den tilbake i nodens navnerom, der en FORWARD-regel og kildeoversettelse virker. Oversett klientpoolen på vei ut, ellers har ingen ekstern node en rute tilbake til en tunneladresse som 10.8.0.6. Sjekk begge retninger før du berører Corefile igjen. En tunnel som bærer spørringen men ikke svaret gir nøyaktig samme timeout som en resolver som aldri fikk spørringen.
Verifiser fra en ny pod, ikke fra økten du reparerte
Spør begge sonene eksplisitt, og gjenta deretter spørringen etter at pod-en er byttet ut. En konfigurasjon som bare finnes i en kjørende container er ikke en konfigurasjon:
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 +shortHvis det første paret svarer og paret etter utskiftingen ikke gjør det, er Corefile riktig og pod-spesifikasjonen ikke. Hvis begge svarer og applikasjonen fortsatt ikke får forbindelse, slutt å feilsøke DNS og test TCP-veien med nc -vz db.svc.acme.internal 5432 fra innsiden av containeren. Ta vare på dig-utdataene i saken, fordi det er artefakten som skiller et navneproblem fra et rutingproblem.