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 کا آؤٹ پٹ ٹکٹ میں رکھیں، کیوںکہ یہی وہ شی ہے جو نام کے مسئلے کو راستے کے مسئلے سے الگ کرتی ہے۔