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 सेवाविना, port-forward बिना र क्लस्टर नेटवर्कबाट घुम्ती नलिई 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 को आउटपुट टिकटमा राख्नुहोस्, किनभने त्यही नामको समस्या राउटिङको समस्याबाट छुट्याउने कलाकृति हो।