← ყველა სტატია

ერთი წუთი მუშაობდა, მერე ტაიმაუტები: MetalLB L2 და kube-proxy ipvs strictARP-ის გარეშე

ჰოსტების ახალ LoadBalancer IP-ზე გადაყვანა ცოტა ხანს მუშაობდა, მერე გარე ბალანსერმა L4 ტაიმაუტები დაინახა. ერთსა და იმავე IP-ზე ARP-ს ყველა ნოდი პასუხობდა.

Optimacros-ის bare-metal კლასტერზე ingress-nginx-ის ექსპლუატაციიდან გაყვანის ნაწილი იყო ჰოსტების სათითაოდ გადაყვანა ძველი ingress-იდან Envoy Gateway-ის LoadBalancer IP-ზე. კლასტერის წინ დგას გარე HAProxy სხვა ქვექსელში, მაგრამ იმავე L2 სეგმენტში. პირველი SNI ჰოსტი ახალ IP-ზე გადავიყვანე და მან სწორად უპასუხა.

დაახლოებით ერთი წუთის შემდეგ იქ გადაყვანილი ყველა ჰოსტი ტაიმაუტში წავიდა. HAProxy წერდა Layer4 timeout-ს და ბექენდს ჩავარდნილად ნიშნავდა. ჩემი ლეპტოპიდან იგივე IP მუშაობდა. MetalLB აჩვენებდა, რომ IP ზუსტად სწორი ნოდიდან ცხადდებოდა — იქიდან, სადაც Envoy-ის პოდი იყო. HAProxy-ში ცვლილება დავაბრუნე და სერვისი აღდგა — დაახლოებით ერთწუთიანი გავლენა ოთხ ჰოსტზე.

არასწორი MAC მისამართი

პირველი სასარგებლო შემოწმება თავად HAProxy-ის VM-იდან იყო: ip neigh show <lb-ip>. ქეშირებული იყო იმ ვორკერის MAC, რომელზეც Envoy-ის პოდი არ იყო. MetalLB ერთი ნოდიდან აცხადებდა, HAProxy კი მეორესთან დადიოდა.

Service-ს ჰქონდა externalTrafficPolicy: Local — სწორი არჩევანი კლიენტის IP-ის შესანარჩუნებლად, და ეს ნიშნავს, რომ ნოდი ლოკალური ენდპოინტის გარეშე ტრაფიკს აგდებს. SYN-ები არასწორ ნოდზე მიდიოდა და ქრებოდა.

რატომ პასუხობდა ARP-ს ყველა

kube-proxy ipvs რეჟიმში ყველა LoadBalancer IP-ს ყველა ნოდზე dummy ინტერფეისს kube-ipvs0 ამაგრებს. ამ კლასტერში — 306 მისამართი თითო ნოდზე. strictARP: false-ით — kubespray-ისა და kubeadm-ის ნაგულისხმევი, ინსტალაციიდან დაყენებული — ბირთვი arp_ignore=0-ს ინახავს და ამ IP-ებზე ARP-ს ყველა ნოდი სიამოვნებით პასუხობს და არა მხოლოდ MetalLB-ის speaker, რომელიც ანონსს ფლობს.

რომელ MAC-ს დაიქეშავს კლიენტი, რბოლაა. აქედან „მუშაობდა, მერე შეწყვიტა”: პირველი პასუხი შემთხვევით სწორი ნოდიდან მოვიდა, შემდეგი — არა. როუტერის მიღმა მყოფ კლიენტებს მისი ქეში უმართლებდა, ამიტომ პრობლემა დიდხანს უხილავი იყო. გარე HAProxy ადრე მხოლოდ მასტერების NodePort-ებზე დადიოდა; მიგრაცია პირველი შემთხვევა იყო, როცა ამ სეგმენტში ვინმემ LB IP თავად დაარეზოლვა.

MetalLB ამაზე პირდაპირ წერს: L2 რეჟიმი kube-proxy ipvs-თან ერთად strictARP: true-ს მოითხოვს.

შეკეთება და როგორ შევამოწმე

  1. kube-proxy ConfigMap-ის ბექაპი.
  2. strictARP: true და kube-proxy DaemonSet-ის გადატვირთვა. kube-proxy დააყენებს arp_ignore=1-ს და arp_announce=2-ს და ARP-ს მხოლოდ მაცხადებელი speaker უპასუხებს.
  3. HAProxy-ის VM-ზე მოძველებული neighbour ჩანაწერის წაშლა.
  4. მთელი წუთი შემოწმება და არა ერთი მოთხოვნისადმი ნდობა:
for i in $(seq 1 60); do timeout 2 bash -c "</dev/tcp/<lb-ip>/443" && echo ok || echo FAIL; sleep 1; done | sort | uniq -c

შემდეგ ჰოსტები თავიდან სათითაოდ გადავიყვანე, ყოველის შემდეგ დაკვირვების პერიოდით. kubeadm განახლებისას KubeProxyConfiguration-ს იმავე ConfigMap-იდან კითხულობს, ამიტომ პარამეტრმა იმავე დღეს გავლილ Kubernetes-ის ჰოპებსაც გაუძლო.

დასკვნები

  • MetalLB L2-სა და kube-proxy ipvs-თან პირველ რიგში strictARP შეამოწმე. თუ false-ია, ყოველი ნოდი ყოველ LoadBalancer IP-ზე პასუხის კანდიდატია.
  • externalTrafficPolicy: Local არასწორ ARP პასუხს ჩუმ დროპად აქცევს.
  • ARP-რბოლაში ერთი წარმატებული მოთხოვნა არაფერს ამტკიცებს. შეამოწმე დროში და ყოველ ცვლილებას დააკვირდი.
  • ფარული ქსელური ბაგი ხშირად სეგმენტის პირველ ახალ კლიენტს ელოდება. მიგრაცია სწორედ ის მომენტია, როცა ის ჩნდება.