ერთი წუთი მუშაობდა, მერე ტაიმაუტები: 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-ს მოითხოვს.
შეკეთება და როგორ შევამოწმე
kube-proxyConfigMap-ის ბექაპი.strictARP: trueდა kube-proxy DaemonSet-ის გადატვირთვა. kube-proxy დააყენებსarp_ignore=1-ს დაarp_announce=2-ს და ARP-ს მხოლოდ მაცხადებელი speaker უპასუხებს.- HAProxy-ის VM-ზე მოძველებული neighbour ჩანაწერის წაშლა.
- მთელი წუთი შემოწმება და არა ერთი მოთხოვნისადმი ნდობა:
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-რბოლაში ერთი წარმატებული მოთხოვნა არაფერს ამტკიცებს. შეამოწმე დროში და ყოველ ცვლილებას დააკვირდი.
- ფარული ქსელური ბაგი ხშირად სეგმენტის პირველ ახალ კლიენტს ელოდება. მიგრაცია სწორედ ის მომენტია, როცა ის ჩნდება.