Jak rozdělit DNS mezi Kubernetes a sidecar OpenVPN
Pod se sidecarem potřebuje dva světy jmen. Namiřte jeden loopback resolver na cluster i tunel a přestaňte spoléhat na upravený resolv.conf.
Pody, které spouštějí OpenVPN sidecar, selhávají při překladu jmen podle rozpoznatelného vzorce: jména clusteru visí, vzdálená jména odpovídají, dokud se pod nerestartuje, a vámi upravený soubor resolveru se vrací zpět. Nic v této posloupnosti není závada tunelu. Pod má jeden soubor resolveru a dva světy jmen a soubor může vyjmenovat servery v pořadí, ale nemůže vyjádřit zóny. Trvalým řešením je resolver, který běží uvnitř podu a vlastní rozdělení, takže soubor zůstává triviální a žádná politika nemá důvod ho přepisovat.
Proč úprava, kterou jste provedli, neustále mizí
Soubor patří kubeletu, ne vám. Pod dnsPolicy: ClusterFirst ho kubelet generuje tak, aby ukazoval na clusterový DNS, a regeneruje ho při každém startu kontejneru. Cokoli změníte přes kubectl exec, žije v zapisovatelné vrstvě kontejneru, takže restart, vyhození nebo rollout to zahodí. Specifikace podu stále nese stejnou politiku, a proto se stejný soubor vrací.
Nastavení dnsPolicy: None zastaví regeneraci a také odstraní překlad v clusteru. Získáte soubor, který ovládáte, a ztratíte jména, která jste potřebovali. Tato výměna je celý problém: resolv.conf nezná zóny, pouze servery, které má zkoušet v pořadí, takže nemůže poslat cluster.local na jednu adresu a privátní zónu na jinou.
Spusťte jeden resolver v podu, na loopbacku
Namiřte pod na jediný jmenný server na loopbacku, potom nechte kontejner CoreDNS, který sdílí síťový namespace podu, odpovídat na portu 53. Nastavte politiku na None, dejte podu tuto jedinou adresu a přidejte DNS kontejner vedle VPN a aplikace:
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-corefileVšechny tři kontejnery sdílejí jeden síťový namespace, takže 127.0.0.1:53 z kontejneru aplikace dosáhne CoreDNS bez služby, bez port-forwardu a bez objížďky přes síť clusteru. Montování Corefile z ConfigMap ho udržuje jako verzovaný vstup místo souboru upravovaného na místě. Vygenerovaný resolv.conf pak drží jediný jmenný server a nic jiného, což je stav, o kterém můžete uvažovat.
Dva detaily tu kousnou. Oficiální image váže port 53 jako root a některé politiky clusteru vyžadují, abyste to výslovně uvedli. Každý kontejner v podu teď závisí na tom, že tento jediný kontejner běží, takže přidejte readiness sondu proti neškodnému jménu a nechte aplikaci tolerovat selhání při startu.
Dejte každé privátní zóně vlastní upstream
Corefile je seznam zón, každá pojmenovává server, který na ni může odpovědět. Jeden blok pokrývá tunelovou zónu a blok, který chytá vše, jde poslední a bere vše, co žádný explicitní blok nezabral. Blok, který chytá vše, musí mířit na skutečný upstream, nikdy zpět na pod: .:53 { forward . 10.100.0.10 } znovu používá clusterový resolver, protože ten už předává veřejná jména resolverům samotného uzlu. Nic jiného v podu nemusí vědět, ke které síti jméno patří.
.:53 {
errors
cache 30
forward . 10.100.0.10
}
svc.acme.internal:53 {
errors
cache 30
forward . 192.168.240.1
}Přečtěte adresu clusteru ze služby kube-dns v kube-system, místo abyste ji kopírovali z článku, protože CIDR služeb se liší. Adresa tunelu pochází z hodnoty dhcp-option DNS, kterou posílá server OpenVPN, nebo z autoritativního serveru pro danou zónu. Pokud váš clusterový resolver neodpovídá na veřejná jména, dejte adresu resolveru uzlu do bloku, který chytá vše, přečtenou na uzlu, ne uvnitř podu.
Nemířte blok, který chytá vše, na /etc/resolv.conf, to je lákavá jednřádková varianta a past právě v tomto zapojení. Pod dnsPolicy: None obsahuje soubor samotného podu jediný jmenný server 127.0.0.1, takže tím cílem je samotný CoreDNS a každý neodpovídající dotaz rekurzuje, dokud nevyprší. Blok pojmenovaný svc.acme.internal odpovídá tomuto jménu a každému jménu pod ním, což pokrývá db.svc.acme.internal a vylučuje svc.acme.internal.example.net. Koncová tečka je kosmetická, protože názvy zón se normalizují do plně kvalifikované podoby; hranice sufixu rozhoduje, kam dotaz dopadne.
Rozhodněte, zda předávání patří clusterovému resolveru
Pokud každá zátěž v namespace potřebuje tunelovou zónu, je blok předávání v CoreDNS ConfigMap pod kube-system levnější než sidecar na pod. Tato změna je v rozsahu clusteru: vyžaduje administrátorská práva a restart deploymentu, na kterém všichni závisí. Omezte ji na tuto jednu zónu, nikdy ne na kořen. Tunelová adresa jedné zátěže se pak stane resolverem každého podu pro zónu a v den, kdy tunel spadne, celý cluster ztratí jméno.
Sidecar drží rádius výbuchu uvnitř jednoho podu, což je lepší výchozí volba, když vzdálenou síť potřebuje jen několik služeb. Ať zvolíte cokoli, zapište, který resolver zónu vlastní, protože příští člověk, který bude ladit timeout, se to zeptá.
Jména, která se překládají, zatímco spojení stále selhávají
Překlad je jedna ze dvou věcí, které tunel musí nést; tou druhou je cesta zpět a síť podu ji dobře skrývá. Pokud samotný server OpenVPN běží jako pod, pravidla, která přidáte v tomto kontejneru, neřídí provoz, který odchází přes uzel. Tato závada je úzká: odpovědi dostávaly jen pody na uzlu, který server také spouštěl, a vše ostatní vypršelo.
Spuštění serveru s hostNetwork: true ho vrací do namespace uzlu, kde pravidlo FORWARD a překlad zdroje působí. Přeložte klientský pool na odchodu, jinak žádný vzdálený uzel nemá cestu zpět na tunelovou adresu, jako je 10.8.0.6. Ověřte oba směry, než znovu sáhnete na Corefile. Tunel, který nese dotaz a ne odpověď, dává přesně stejný timeout jako resolver, který dotaz nikdy nedostal.
Ověřte z nového podu, ne ze session, kterou jste opravili
Zeptejte se výslovně na obě zóny a potom dotaz zopakujte po výměně podu. Konfigurace, která existuje jen v běžícím kontejneru, není konfigurace:
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 +shortPokud první dvojice odpovídá a dvojice po výměně ne, Corefile je v pořádku a specifikace podu ne. Pokud odpovídají obě a aplikace se stále nemůže připojit, přestaňte ladit DNS a otestujte TCP cestu pomocí nc -vz db.svc.acme.internal 5432 zevnitř kontejneru. Uložte výstup dig do tiketu, protože je to artefakt, který odděluje problém se jmény od problému s routingem.