ერთმა დავიწყებულმა DHCP ოფციამ მთელი Kubernetes კლასტერი გათიშა
ჰოსტის გადატვირთვის შემდეგ ორმოცდაათამდე პოდი CrashLoop-ში წავიდა, თუმცა ყველა ნოდა Ready იყო. მიზეზი დავიწყებული DHCP classless routes ოფცია იყო, რომელმაც ნაგულისხმევი შლუზი ჩუმად წაშალა.
ჩემს სახლის ლაბორატორიაში ერთ Proxmox ჰოსტზე შვიდნოდიანი kubeadm კლასტერი მუშაობს. ჰოსტის გადატვირთვის შემდეგ კლასტერი ყველაზე ცუდ მდგომარეობაში დაბრუნდა: ორმოცდაათამდე პოდი CrashLoopBackOff-ში ან ImagePullBackOff-ში მთელ კლასტერში. CoreDNS API სერვერს ვერ უკავშირდებოდა — connect: no route to host. GitLab runner ვერაფერს ხსნიდა. იმიჯები არსად იტვირთებოდა.
ამასთან, შვიდივე ნოდა Ready იყო. calico-node და kube-proxy მუშაობდნენ, ხოლო IPVS ცხრილი API სერვერის ClusterIP-სთვის სამივე control-plane ნოდაზე მიუთითებდა — ზუსტად ისე, როგორც საჭიროა.
მცდარი პირველი ვარაუდი
ყველაფერი ყვიროდა: „CNI გაფუჭებულია“. პოდები ვერაფერს უკავშირდებოდნენ, Calico აშკარა ეჭვმიტანილი იყო, kube-proxy — მის შემდეგ. პირველი დრო იმის დადასტურებას მოვანდომე, რომ ორივე სწორად იყო დაპროგრამებული. ასეც იყო.
მინიშნება
პრობლემა მარტივმა შედარებამ გაყო: hostNetwork პოდი მუშაობდა, ჩვეულებრივი — არა. ესე იგი, ნოდის საკუთარი ქსელური namespace წესრიგში იყო და მხოლოდ პოდების გასასვლელი გარეთ იყო გაფუჭებული.
გაფუჭებული პოდის შიგნიდან ip route get API სერვერამდე იხსნებოდა, მაგრამ TCP EHOSTUNREACH-ით ვარდებოდა. ip neigh-მა კი მთავარი სამხილი აჩვენა: Calico-ს link-local შლუზი 169.254.1.1 იყო INCOMPLETE. პოდს საკუთარი შლუზის ARP პასუხის მიღებაც არ შეეძლო.
ჰოსტზე ip route show default ცარიელი იყო. ნაგულისხმევი მარშრუტი საერთოდ არ არსებობდა.
ძირეული მიზეზი
169.254.1.1-ზე ARP მოთხოვნებს Calico proxy-ARP-ით პასუხობს, proxy-ARP კი მხოლოდ იმ მისამართზე პასუხობს, სადამდეც ჰოსტს მარშრუტი აქვს. არ არის ნაგულისხმევი მარშრუტი — არ არის პასუხი — პოდებს გასასვლელი არსად აქვთ.
რატომ ჩაიტვირთა ყველა VM ნაგულისხმევი მარშრუტის გარეშე? ჩემი როუტერი DHCP-ით 121-ე ოფციას (classless static routes) არიგებს. ოდესღაც მასში რამდენიმე მარშრუტი ძველი შლუზით დავაყენე, LAN-ის გადანომრვის შემდეგ კი არავინ განაახლა. RFC 3442 პირდაპირ ამბობს: კლიენტი, რომელმაც 121-ე ოფცია მიიღო, ვალდებულია უგულებელყოს მე-3 ოფცია — ნაგულისხმევი შლუზი. ამიტომ ყველა კლიენტმა მხოლოდ მოძველებული classless მარშრუტები დააყენა და default gateway ჩუმად გადააგდო.
კასკადი ასე გამოიყურებოდა: არ არის ნაგულისხმევი მარშრუტი → არ არის proxy-ARP → პოდები API-ს ვერ ხედავენ → CoreDNS CrashLoop-შია → კლასტერის DNS არ არის → ყველაფერი, რაც სახელებს ხსნის, ასევე CrashLoop-შია. ზემოდან ნოდებზე გაჭედილი ლოკალური რეზოლვერიც დაემატა — აქედან იმიჯების პრობლემაც.
გამოსწორება
სწრაფად თითოეულ ნოდაზე ნაგულისხმევი მარშრუტი დავაბრუნე ip route replace default via <შლუზი>-ით. პოდები იმ წამს გაცოცხლდნენ, როცა 169.254.1.1 REACHABLE გახდა.
მუდმივი გამოსწორება როუტერზე გაკეთდა: 121-ე ოფცია (და მისი Microsoft-ის ტყუპისცალი, 249-ე) ისე გადავწერე, რომ ნაგულისხმევ მარშრუტს ატარებდეს — ნულოვანი სიგრძის პრეფიქსი და სწორი შლუზი. ამ როუტერის ნაგულისხმევ ქსელზე ოფციის მთლიანად წაშლა შეუძლებელი იყო, ამიტომ საიმედო გზა მნიშვნელობის ადგილზე გასწორება იყო. ორი ნამდვილი გადატვირთვის შემდეგ კლასტერი თავად აეწყო, ხელით დახმარების გარეშე.
დასკვნები
- თუ 121-ე ოფცია არის, მე-3 უგულებელყოფილია. მოძველებულ classless მარშრუტებს შეუძლიათ მთელი ქვექსელიდან ნაგულისხმევი მარშრუტი მოხსნან. შლუზის ან ქვექსელის ნებისმიერი ცვლილების შემდეგ DHCP ოფციები შეამოწმეთ.
169.254.1.1 INCOMPLETEპოდისip neigh-ში Calico-სთვის მთავარი სამხილია. CNI გამართულია, უბრალოდ ჰოსტს შლუზამდე მარშრუტი არ აქვს.hostNetworkდა ჩვეულებრივი პოდი რაც შეიძლება ადრე შეადარეთ. ეს ერთი ნაბიჯით ძებნის არეს ორჯერ ამცირებს.- „ყველა ნოდა Ready“ პოდების ქსელზე არაფერს ამბობს. ნოდის მზადყოფნა და პოდების ქსელი ერთმანეთისგან დამოუკიდებლად ფუჭდება.