OpenVPN সাইডকার চালানো পড়গুলো নাম সমাধানে চেনা যায় এমন ধরণে ব্যর্থ হয়: ক্লাস্টারের নাম আটকে পড়ে, দূরের নাম পড় পুনরায় চালু হওয়া পর্যন্ত উত্তর দেয়, এবং আপনার সম্পাদিত resolver ফাইল ফিরে আসে। এই ক্রমের কিছুই টানেলের ত্রুটি নয়। একটি পড়ের একটি resolver ফাইল এবং দুটি নামের জগত থাকে, এবং ফাইল সার্ভারগুলো ক্রমানুসারে তালিকা করতে পারে, কিন্তু জোন প্রকাশ করতে পারে না। টেকসই সমাধান হলো পড়ের ভিতরে চলা এবং ভাগের মালিক একটি resolver, তাই ফাইল সহজ থাকে এবং কোনো নীতির তা পুনরায় লেখার কোনো কারণ থাকে না।

আপনার করা পরিবর্তন কেন প্রতিবার হারিয়ে যায়

ফাইলটি kubelet-এর, আপনার নয়। dnsPolicy: ClusterFirst অধীনে kubelet এটি ক্লাস্টার DNS-এ নির্দেশ করতে তৈরি করে এবং প্রতিবার কনটেইনার শুরু হলে আবার তৈরি করে। kubectl exec দিয়ে আপনি যা ইন্না বদলান, তা কনটেইনারের লেখাযোগ্য স্তরে থাকে, তাই পুনরায় চালু, বহিষ্কার বা rollout তা ফেলে দেয়। পড়ের স্পেশিফিকেশন এখনও একই নীতি বহন করে, সেজন্য একই ফাইল ফিরে আসে।

dnsPolicy: None সেট করলে পুনর্নির্মাণ বন্ধ হয় এবং ক্লাস্টার সমাধানও সরিয়ে যায়। আপনি একটি নিয়ন্ত্রিত ফাইল পান এবং প্রয়োজনীয় নামগুলো হারান। এই বিনিময়ই পুরো সমস্যা: resolv.conf জোনের ধারণা জানে না, কেবল ক্রমানুসারে চেষ্টা করা সার্ভার, তাই cluster.local কে একটি ঠিকানায় এবং ব্যক্তিগত জোনকে আরেকটির কাছে পাঠাতে পারে না।

পড়ের মধ্যে একটি resolver চালান, loopback-এ

পড়কে loopback-এর একটি নামসর্ভারের দিকে নির্দেশ করুন, তারপর পড়ের নেটওয়ার্ক নামস্থান ভাগ করা একটি 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 probe যোগ করুন এবং অ্যাপ্লিকেশনকে শুরুর ব্যর্থতা সহ্য করতে দিন।

প্রতিটি ব্যক্তিগত জোনকে নিজস্ব upstream দিন

Corefile হলো জোনের তালিকা, প্রত্যেকটি সেই সার্ভারের নাম দেয় যা উত্তর দিতে পারে। একটি ব্লক টানেল জোন ঢেকে, এবং সব ধরার ব্লক শেষে আসে এবং যা কোনো স্পষ্ট ব্লক দাবি করেনি তা নিয়ে নেয়। সব ধরার ব্লককে প্রকৃত upstream-এর দিকে নির্দেশ করতে হবে, কখনোই পড়ের দিকে ফিরে নয়: .:53 { forward . 10.100.0.10 } ক্লাস্টার resolver পুনরায় ব্যবহার করে কারন এটি ইতিমধ্যে সাধারণ নামগুলোকে নোডের নিজস্ব resolverগুলোর কাছে পাঠায়। পড়ের অন্য কিছুকে জানতে হবে না একটি নাম কোন নেটওয়ার্কের।

.: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 মান পাঠায় তা থেকে, বা সেই জোনের কর্তৃত্বপ্রাপ্ত সার্ভার থেকে। আপনার ক্লাস্টার resolver সাধারণ নামে উত্তর না দিলে, নোডের resolver ঠিকানা সব ধরার ব্লকে রাখুন, যা নোডে পড়া হয়, পড়ের ভিতরে নয়।

সব ধরার ব্লককে /etc/resolv.conf-এর দিকে নির্দেশ করবেন না, এটি লোভনীয় এক-লাইন এবং এই নির্দিষ্ট সেটআপে একটি ফাঁদ। dnsPolicy: None-এর অধীনে পড়ের নিজস্ব ফাইলে একটিমাত্র নামসর্ভার 127.0.0.1 থাকে, তাই এই লক্ষ্য CoreDNS নিজেই এবং প্রতিটি অমিল কুয়েরি সময় শেষ হওয়া পর্যন্ত পুনরাবৃত্তি হয়। svc.acme.internal নামের ব্লক সেই নাম এবং তার নিচের প্রতিটি নামের সাথে মিলে, যা db.svc.acme.internal অন্তর্ভুক্ত করে এবং svc.acme.internal.example.net বাদ দেয়। শেষের বিন্দু কেবল দৃশ্যমান, কারন জোনের নাম সম্পূর্ণ যোগ্য আকারে স্বাভাবিক করা হয়; প্রত্যযের সীমা নির্ধারণ করে কুয়েরি কোথায় পড়বে।

ফরোয়ার্ডিং ক্লাস্টার resolver-এর কিনা তা সিদ্ধান্ত করুন

নামস্থানের প্রতিটি ওয়ার্কলোডকে টানেল জোন প্রয়োজন হলে, kube-system-এর অধীনে CoreDNS ConfigMap-এ একটি ফরোয়ার্ডিং ব্লক প্রতিটি পড়ের সাইডকারের থেকে সস্তা। এই পরিবর্তন ক্লাস্টার স্তরের: এর জন্য প্রশাসকের অধিকার এবং সবাই যার উপরে নির্ভরশীল এমন একটি ডিপ্লয়মেন্ট পুনরায় চালু করা প্রয়োজন। এটি সেই একটি জোনে সীমাবদ্ধ রাখুন, কখনোই মূলে নয়। একটি ওয়ার্কলোডের টানেল ঠিকানা তখন জোনটির জন্য প্রতিটি পড়ের resolver হয়ে যায়, এবং যে দিন টানেল পড়ে যায় সেই দিন পুরো ক্লাস্টার নাম হারায়।

সাইডকার বিস্ফোরণের ব্যাসার্ধ একটি পড়ের ভিতরে রাখে, যা সাধারণত ভালো ডিফল্ট যখন কেবল কয়েকটি সেবার দূরের নেটওয়ার্ক প্রয়োজন। আপনি যাই বেছে নিন, কোন resolver জোনটির মালিক তা লেখে রাখুন, কারন পরবর্তী ব্যক্তি যিনি টাইমআউট ডিবাগ করবেন তিনি জিজ্ঞাসা করবেন।

যে নামগুলো সংযোগ ব্যর্থ হওয়া সত্ত্বেও সমাধান হয়

সমাধান টানেলকে বহন করতে হবে এমন দুটির একটি; অন্যটি হলো ফিরে আসার পথ, এবং পড়ের নেটওয়ার্ক এটিকে ভালোভাবে লুকায়। OpenVPN সার্ভার নিজেই পড়ে হিসেবে চললে, সেই কনটেইনারে আপনি যোগ করা নিয়মগুলো নোডের মধ্য দিয়ে বেরিয়ে যাওয়া ট্রাফিক নিয়ন্ত্রণ করে না। এই ব্যর্থতা সংকীর্ণ: শুধুমাত্র যে নোডে সার্ভারও চলায় সেই নোডের পড়গুলো উত্তর পেয়েছিল, বাকিগুলোর সময় শেষ হয়েছিল।

hostNetwork: true দিয়ে সার্ভার চালালে এটি নোডের নামস্থানে ফিরে আসে, যেখানে FORWARD নিয়ম এবং উৎসের অনুবাদ কাজ করে। বেরিয়ে যাওয়ার সময় ক্লায়েন্ট পুল অনুবাদ করুন, নহলে 10.8.0.6-এর মতো টানেল ঠিকানায় ফিরে যাওয়ার পথ কোনো দূরের নোডের থাকবে না। Corefile-এ আবার হাত দেয়ার আগে উভয় দিক যাঞ্চ করুন। যে টানেল কুয়েরি বহন করে কিন্তু উত্তর নয়, তা ঐ ঠিক সেই টাইমআউট তৈরি করে যা একটি resolver তৈরি করে যা কখনোই কুয়েরি পায়নি।

আপনি সারানো সেশন থেকে নয়, নতুন পড়ে থেকে যাঞ্চ করুন

উভয় জোনকে স্পষ্টভাবে জিজ্ঞাসা করুন, তারপর পড় প্রতিস্থাপিত হওয়ার পর কুয়েরি পুনরায় করুন। শুধুমাত্র চলমান কনটেইনারে যে কনফিগারেশন আছে তা কনফিগারেশন নয়:

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-এর আউটপুট টিকেটে রাখুন, কারন এটিই নামের সমস্যাকে রাউটিং সমস্যা থেকে আলাদা করে।

সম্পর্কিত নিবন্ধ