pod-ები, რომლებიც უშვებენ OpenVPN sidecar-ს, სახელების გარჩევაში მარცხდებიან ამოცნობადი ნიმუშით: კლასტერის სახელები იკიდება, დისტანციური სახელები პასუხობენ მანამ, სანამ pod ხელახლა ჩაიტვირთება, და თქვენ მიერ რედაქტირებული resolver-ის ფაილი უკან ბრუნდება. ამ თანმიმდევრობაში არაფერია გვირაბის ხარვეზი. pod-ს აქვს ერთი resolver-ის ფაილი და ორი სახელების სამყარო, და ფაილს შეუძლია სერვერების რიგით ჩამოთვლა, მაგრამ ზონების გამოხატვა არ შეუძლია. გამძლევ გადაწყვეტაა resolver, რომელიც pod-ის შიგნით მუშაობს და ფლობს გაყოფას, ამიტომ ფაილი მარტივი რჩება და არცერთ პოლიტიკას მისი გადაწერის მიზეზი არ აქვს.

რატომ ქრება თქვენ მიერ გაკეთებული ცვლილება გამუდმებით

ფაილი kubelet-ს ეკუთვნის და არა თქვენ. dnsPolicy: ClusterFirst-ის ქვეშ kubelet ქმნის მას კლასტერის DNS-ზე მისასვლელად და ხელახლა ქმნის ყოველ ჯერზში, როცა კონტეინერი იწყება. ყველაფერს, რასაც kubectl exec-ით ცვლით, კონტეინერის ჩაწერად ფენაში ცხოვრობს, ამიტომ გადატვირთვა, გამოდევნა ან rollout მას სრულად ქრის. pod-ის სპეციფიკაცია კვლავ იმავე პოლიტიკას ატარებს, ამიტომ იგივე ფაილი ბრუნდება.

dnsPolicy: None-ის დაყენება აჩერებს ხელახლა შექმნას და ასევე აშორებს კლასტერის გარჩევას. იღებთ ფაილს, რომელსაც აკონტროლებთ, და კარგავთ სახელებს, რომელიც გყირდებოდათ. ეს გაცვლა მთელი პრობლემაა: resolv.conf-ს ზონების ცნება არ აქვს, მხოლოდ სერვერები, რომლებიც რიგით უნდა სცადოს, ამიტომ cluster.local-ს ერთ მისამართზე და კერძო ზონას სხვა მისამართზე ვერ გაგზავნის.

გაუშვით ერთი resolver pod-ში, loopback-ზე

მიმართეთ pod loopback-ზე მდებარე ერთ სახელების სერვერზე, შემდეგ მიეცთ CoreDNS კონტეინერს, რომელიც pod-ის ქსელურ სახელთა სივრცეს იზიარებს, 53 პორტზე პასუხის გაცემის უფლება. დააყენეთ პოლიტიკა None-ზე, მიეცით pod-ს ეს ერთი მისამართი და დაამატეთ DNS კონტეინერი VPN-ისა და აპლიკაციის გვერდით:

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-ს აწყევს სერვისის, port-forward-ისა და კლასტერის ქსელში შემოვლის გარეშე. Corefile-ის ConfigMap-იდან მონტაჟი მას ინახავს ვერსირებულ შესასვლელად და არა ადგილზე რედაქტირებულ ფაილად. წარმოებული resolv.conf შემდეგ მხოლოდ ერთ სახელების სერვერს შეიცავს და მეტს არაფერს, რაც ისეთი მდგომარეობაა, რომელზეც მსჯელობა შეიძლება.

ორი დეტალი აქ წევს. ოფიციალური იმიჯი 53 პორტს root-ად აბამს, და ჩამი კლასტერის პოლიტიკები მოითხოვენ, რომ ეს ცხადად დაწერთ. pod-ის ყველა კონტეინერი ახლა დამოკიდებულია იმაზე, რომ ეს ერთი კონტეინერი მუშაობს, ამიტომ დაამატეთ readiness probe უვნებელი სახელის მიმართ და მიეცთ აპლიკაციას გაშვების შეცდომების ატანა.

მიეცით თითოეულ კერძო ზონას საკუთარი upstream

Corefile ზონების სიაა, თითოეული ასახელებს სერვერს, რომელსაც პასუხის გაცემა შეუძლია. ერთი ბლოკი ფარავს გვირაბის ზონას, ხოლო ყველაფრის დამჭერ ბლოკი ბოლოს მოდის და იღებს ყველაფერს, რაზეც არცერთ ცხად ბლოკს პრეტენზია არ გეუთქმია. ყველაფერის მდებარე ბლოკმა უნდა მიმართოს ნამდვივ upstream-ს, არასოდეს დაბრუნდეს pod-ს: .:53 { forward . 10.100.0.10 } კლასტერის resolver-ს ხელახლა იყენებს, რადგან ის უკვე საჯარო სახელებს თავად node-ის resolver-ებზე გადასენდის. pod-ში სხვა არაფერს არ სწირდება იცოდეს, რომელ ქსელს ეკუთვნის სახელი.

.:53 {
  errors
  cache 30
  forward . 10.100.0.10
}

svc.acme.internal:53 {
  errors
  cache 30
  forward . 192.168.240.1
}

კლასტერის მისამართს წაიკითხეთ kube-dns სერვისიდან kube-system-ში, სტატიიდან კოპირების ნაცვლად, რადგან სერვისების CIDR-ები განსხვავდება. გვირაბის მისამართი მოდის OpenVPN სერვერის მიერ გაგზავნილი dhcp-option DNS მნიშნელობიდან, ან ამ ზონის ავტორიტეტული სერვერიდან. თქვენი კლასტერის resolver საჯარო სახელებს არ პასუხობდება, ჩადეთ node-ის resolver-ის მისამართი ყველაფერის მდებარე ბლოკში, წაიკითხული node-ზე და არა pod-ის შიგნით.

არ მიმართოთ ყველაფრის დამჭერ ბლოკი /etc/resolv.conf-ზე, რაც მაცდური ერთსტრიქონიანი გადაწყვეტაა და ხაფანგი ზუსტად ამ კონფიგურაციაში. dnsPolicy: None-ის ქვეშ pod-ის საუკეთესო ფაილი შეიცავს ერთადერთ სახელების სერვერს 127.0.0.1, ამიტომ ეს მიზანი თავად CoreDNS-ია და ყოველი შეუსაბამო მოთხოვნა რეკურსიულად მეორება ვადის ამოწურებამდე. svc.acme.internal სახელის ბლოკი ემთხვევა ამ სახელს და მის ქვეშ ყოველ სახელს, რაც ფარავს db.svc.acme.internal-ს და გამორიცხავს svc.acme.internal.example.net-ს. ბოლოს წერტილი კოსმეტიკურია, რადგან ზონების სახელები ნორმალიზდება სრულად კვალიფიცირებულ ფორმამდე; სუფიქსის საზღვარი წყვეტა, სად დაეშევა მოთხოვნა.

გადაწყვიტეთ, ეკუთვნის გადაგზავნა კლასტერის resolver-ს თე არა

თუ სახელთა სივრცის ყოველ workload-ს სწირდება გვირაბის ზონა, გადაგზავნის ბლოკი CoreDNS ConfigMap-ში kube-system-ის ქვეშ იაფია, ვიდრე pod-ზე თითოეული sidecar-ზე. ეს ცვლილება კლასტერის მაშტაბისაა: სწირდება ადმინისტრატორის უფლებები და დეპლოიმენტის გადატვირთვა, რომელზეც ყველა დამოკიდებულია. შეთავაზეთ ის მხოლოდ ამ ერთ ზონაზე, არასოდეს ძრისზე. ერთი workload-ის გვირაბის მისამართი შემდეგ ზონისთვის ყოველი pod-ის resolver-ი ხდება, და იმ დღესაც, როცა გვირაბი ვედება, მთელი კლასტერი იკარგავს სახელს.

sidecar აფთრების რადიუსს ერთ pod-ში ინახავს, რაც ურყლესი ნაგულისხმევი გილია, როცა დისტანციური ქსელი მხოლოდ რამდენიმე სერვისს სწირდება. რასაც არ არჩიეთ, დაწერთ, რომელი resolver ფლობს ზონას, რადგან შემდეგი ადამიანი, რომელიც timeout-ს გაანალიზებს, იკითხებს.

სახელები, რომლებიც იხსნებიან, სანამ კავშირები ჯერ იშლება

გარჩევა ერთია იმ ორიდან, რაც გვირაბმა უნდა აგთაგოს; მეორე არის უკუ გზა, და pod-ის ქსელი კარგად პათავს მას. თუ თავად OpenVPN სერვერი pod-ად მუშაობს, ამ კონტეინერში დამატებული წესები node-იდან გამავალ ტრაფიკს არ მართავენ. ეს ხარვეზი ვიწროა: პასუხებს მხოლოდ იმ node-ის pod-ები იღებდნენ, რომელიც სერვერსაც უშვებდნენ, და დანარჩენი ყველა ვადას ამოწურდა.

სერვერის hostNetwork: true-ით გაშვება მას უკან აბრუნებს node-ის სახელთა სივრცეში, სადაც FORWARD წესი და წყაროს ტრანსლირება მუშაობენ. თარგმნით კლიენტების pool გასვლისას, თორეთ არცერთ დისტანციურ node-ს არ აქვს უკუ მარშრუტი გვირაბის მისამართზე, როგორიცაა 10.8.0.6. შეამოწმეთ ორივე მიმართულება, სანამ Corefile-ს კვლავ შეეხებით. გვირაბი, რომელიც მოთხოვნას გიზეგთ და პასუხს არა, ზუსტად იმავე timeout-ს შექმნის, რამეც resolver-მა, რომელმაც მოთხოვნა არასოდეს მიღია.

შეამოწმეთ ახალი pod-იდან და არა იმ სესიიდან, რომელიც გაასწორეთ

ჰკითხეთ ორივე ზონას ცხადად, შემდეგ გაიმეორეთ მოთხოვნა pod-ის ჩანაცვლების შემდეგ. კონფიგურაცია, რომელიც მხოლოდ მუშაობ კონტეინერში არსებობს, კონფიგურაცია არ არის:

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 სწორია და pod-ის სპეციფიკაცია არა. თუ ორივე პასუხს იძლევა და აპლიკაცია მაინც ვერ უკავშირდება, შეწყვიტეთ DNS-ის დიაგნოსტიკა და შეამოწმეთ TCP გზა nc -vz db.svc.acme.internal 5432-ით კონტეინერის შიგნით. შეინახეთ dig-ის გამოსავლი ბილეთში, რადგან ის არტეფაქტია, რომელიც სახელის პრობლემას მარშრუტიზაციის პრობლემისგან ყოფს.

დაკავშირებული სტატიები