Kubernetes और OpenVPN साइडकार के बीच DNS को कैसे विभाजित करें
साइडकार पॉड को दो नाम-संसार चाहिए। एक लूपबैक रिज़ॉल्वर को क्लस्टर और टनल की ओर इंगित करें, और संपादित resolv.conf पर निर्भरता छोड़ें।
OpenVPN साइडकार चलाने वाले पॉड नाम-विभेदन में एक पहचाने जाने योग्य ढंग से विफल होते हैं: क्लस्टर के नाम अटक जाते हैं, दूर के नाम तब तक उत्तर देते हैं जब तक पॉड पुनः आरंभ न हो, और आपकी संपादित रिज़ॉल्वर फ़ाइल वापस पुरानी हो जाती है। उस क्रम में कुछ भी टनल की खराबी नहीं है। एक पॉड में एक रिज़ॉल्वर फ़ाइल और दो नाम-संसार होते हैं, और फ़ाइल सर्वरों को क्रम में सूचीबद्ध कर सकती है पर ज़ोन नहीं बता सकती। टिकाऊ उपाय वह रिज़ॉल्वर है जो पॉड के भीतर चलता है और विभाजन का स्वामी है, इसलिए फ़ाइल सरल रहती है और किसी नीति के पास उसे फिर से लिखने का कारण नहीं होता।
आपका किया हुआ संपादन बार-बार क्यों गायब होता है
फ़ाइल kubelet की है, आपकी नहीं। dnsPolicy: ClusterFirst के अंतर्गत kubelet इसे क्लस्टर DNS की ओर इंगित करने के लिए बनाता है और हर बार कंटेनर शुरू होने पर इसे फिर बनाता है। kubectl exec से आप जो भी बदलते हैं वह कंटेनर की लिखने योग्य परत में रहता है, इसलिए पुनः आरंभ, बेदखली या रोलआउट उसे फेंक देते हैं। पॉड स्पेक अब भी वही नीति रखता है, इसीलिए वही फ़ाइल लौट आती है।
dnsPolicy: None सेट करने पर पुनर्निर्माण रुक जाता है और क्लस्टर विभेदन भी हट जाता है। आपको नियंत्रित फ़ाइल मिलती है और ज़रूरी नाम खो जाते हैं। यही अदला-बदली पूरी समस्या है: resolv.conf को ज़ोन की कोई धारणा नहीं, केवल क्रम में आज़माने वाले सर्वरों की, इसलिए वह cluster.local को एक पते पर और एक निजी ज़ोन को दूसरे पर नहीं भेज सकता।
पॉड में एक रिज़ॉल्वर चलाएँ, लूपबैक पर
पॉड को लूपबैक पर एक ही नेमसर्वर की ओर इंगित करें, फिर पॉड का नेटवर्क नामस्थान साझा करने वाले CoreDNS कंटेनर को पोर्ट 53 पर उत्तर देने दें। नीति को None पर सेट करें, पॉड को वह एक पता दें, और VPN तथा एप्लिकेशन के बगल में DNS कंटेनर जोड़ें:
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तीनों कंटेनर एक ही नेटवर्क नामस्थान साझा करते हैं, इसलिए एप्लिकेशन कंटेनर से 127.0.0.1:53 बिना सेवा, बिना पोर्ट-फ़ॉरवर्ड और क्लस्टर नेटवर्क से घूमे बिना CoreDNS तक पहुंचता है। ConfigMap से Corefile माउंट करना उसे जगह पर संपादित फ़ाइल के बजाय संस्करणित इनपुट रखता है। फिर उत्पन्न resolv.conf में एक नेमसर्वर और कुछ नहीं रहता, जो ऐसी स्थिति है जिस पर आप तर्क कर सकते हैं।
यहाँ दो बारीकियाँ काटती हैं। आधिकारिक इमेज पोर्ट 53 को root के रूप में बाँधती है, और कुछ क्लस्टर नीतियाँ आपको यह स्पष्ट लिखने को बाध्य करती हैं। पॉड का हर कंटेनर अब उस एक कंटेनर के चालू होने पर निर्भर है, इसलिए एक हानिरहित नाम के विरुद्ध readiness प्रोब जोड़ें और एप्लिकेशन को शुरुआती विफलताएँ सहने दें।
हर निजी ज़ोन को उसका अपना upstream दें
Corefile ज़ोनों की सूची है, हर एक उस सर्वर का नाम देता है जो उसका उत्तर दे सकता है। एक ब्लॉक टनल ज़ोन को कवर करता है, और सब कुछ पकड़ने वाला ब्लॉक अंत में आता है और वह सब लेता है जिस पर किसी स्पष्ट ब्लॉक ने दावा नहीं किया। सब कुछ पकड़ने वाले ब्लॉक को वास्तविक upstream पर निशाना लगाना चाहिए, कभी पॉड की ओर वापस नहीं: .:53 { forward . 10.100.0.10 } क्लस्टर रिज़ॉल्वर का पुनः उपयोग करता है क्योंकि वह रिज़ॉल्वर पहले से सार्वजनिक नामों को नोड के अपने रिज़ॉल्वरों तक भेजता है। पॉड में किसी और को यह जानने की ज़रूरत नहीं कि नाम किस नेटवर्क का है।
.:53 {
errors
cache 30
forward . 10.100.0.10
}
svc.acme.internal:53 {
errors
cache 30
forward . 192.168.240.1
}क्लस्टर का पता kube-system में kube-dns सेवा से पढ़ें, किसी लेख से नकल करने के बजाय, क्योंकि सेवा CIDR अलग होते हैं। टनल का पता OpenVPN सर्वर द्वारा भेजे गए dhcp-option DNS मान से आता है, या उस ज़ोन के आधिकारिक सर्वर से। यदि आपका क्लस्टर रिज़ॉल्वर सार्वजनिक नामों का उत्तर नहीं देता, तो नोड के रिज़ॉल्वर का पता सब कुछ पकड़ने वाले ब्लॉक में रखें, जो नोड पर पढ़ा गया हो, पॉड के भीतर नहीं।
सब कुछ पकड़ने वाले ब्लॉक को /etc/resolv.conf की ओर इंगित न करें, जो लुभावनी एक-पंक्ति है और इस ठीक सेटअप में जाल है। dnsPolicy: None के अंतर्गत पॉड की अपनी फ़ाइल में एकमात्र नेमसर्वर 127.0.0.1 है, इसलिए वह लक्ष्य स्वयं CoreDNS है और हर बेमेल क्वेरी समय-सीमा तक दोहराई जाती है। svc.acme.internal नाम का ब्लॉक उस नाम और उसके नीचे के हर नाम से मेल खाता है, जो db.svc.acme.internal को कवर करता है और svc.acme.internal.example.net को बाहर रखता है। अंतिम बिंदु दिखावटी है, क्योंकि ज़ोन नाम पूर्णतः योग्य रूप में सामान्यीकृत होते हैं; प्रत्यय की सीमा तय करती है कि क्वेरी कहाँ उतरती है।
तय करें कि फ़ॉरवर्ड क्लस्टर रिज़ॉल्वर में होना चाहिए या नहीं
यदि नामस्थान का हर वर्कलोड टनल ज़ोन चाहता है, तो kube-system के अंतर्गत CoreDNS ConfigMap में फ़ॉरवर्ड ब्लॉक प्रति पॉड साइडकार से सस्ता है। वह बदलाव क्लस्टर-स्तरीय है: उसे प्रशासक अधिकार और ऐसे डिप्लॉयमेंट का पुनः आरंभ चाहिए जिस पर सभी निर्भर हैं। उसे उसी एक ज़ोन तक सीमित रखें, कभी मूल तक नहीं। एक वर्कलोड का टनल पता फिर ज़ोन के लिए हर पॉड का रिज़ॉल्वर बन जाता है, और जिस दिन टनल गिरता है उस दिन पूरा क्लस्टर नाम खो देता है।
साइडकार विस्फोट-त्रिज्या को एक पॉड के भीतर रखता है, जो तब बेहतर डिफ़ॉल्ट है जब केवल कुछ सेवाओं को दूर का नेटवर्क चाहिए। आप जो भी चुनें, लिख लें कि ज़ोन का स्वामी कौन-सा रिज़ॉल्वर है, क्योंकि अगला व्यक्ति जो टाइमआउट डीबग करेगा वह पूछेगा।
ऐसे नाम जो तब हल होते हैं जब कनेक्शन अभी विफल होते हैं
विभेदन उन दो चीज़ों में से एक है जो टनल को ढोनी होती है; दूसरी है वापसी का रास्ता, और पॉड नेटवर्क उसे अच्छी तरह छिपाता है। यदि OpenVPN सर्वर स्वयं पॉड के रूप में चलता है, तो उस कंटेनर में जोड़े गए नियम नोड से बाहर जाने वाले ट्रैफ़िक को नियंत्रित नहीं करते। वह विफलता संकरी है: केवल उस नोड के पॉड जिन्होंने सर्वर भी चलाया था, उत्तर पाते थे, और बाकी सब समय-सीमा पर चला गया।
सर्वर को hostNetwork: true के साथ चलाना उसे नोड के नामस्थान में वापस लाता है, जहाँ FORWARD नियम और स्रोत अनुवाद प्रभावी होते हैं। बाहर जाते समय क्लाइंट पूल का अनुवाद करें, वरना किसी दूर के नोड के पास 10.8.0.6 जैसे टनल पते तक वापसी का मार्ग नहीं होगा। Corefile को फिर स्पर्श करने से पहले दोनों दिशाएँ जाँचें। जो टनल क्वेरी ढोता है पर उत्तर नहीं, वह ठीक वही टाइमआउट पैदा करता है जो ऐसे रिज़ॉल्वर का होता है जिसे क्वेरी कभी मिली ही नहीं।
नए पॉड से सत्यापित करें, उस सत्र से नहीं जिसे आपने ठीक किया
दोनों ज़ोनों से स्पष्ट रूप से पूछें, फिर पॉड बदलने के बाद क्वेरी दोहराएं। केवल चल रहे कंटेनर में मौजूद कॉन्फ़िगरेशन कॉन्फ़िगरेशन नहीं है:
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यदि पहली जोड़ी उत्तर देती है और बदलाव के बाद की जोड़ी नहीं, तो Corefile ठीक है और पॉड स्पेक नहीं। यदि दोनों उत्तर देते हैं और एप्लिकेशन फिर भी कनेक्ट नहीं हो पाता, तो DNS डीबग करना बंद करें और कंटेनर के भीतर से nc -vz db.svc.acme.internal 5432 के साथ TCP पथ जाँचें। dig का आउटपुट टिकट में रखें, क्योंकि वही वह कलाकृति है जो नाम की समस्या को राउटिंग की समस्या से अलग करती है।