სერტიფიკატებს ვადა გრაფიკით გაუვიდა. ალერტი ერთი კვირა ყვიროდა — სიცარიელეში
kubeadm კლასტერმა control plane დაკარგა ინსტალაციიდან ზუსტად ერთი წლის შემდეგ. ალერტი შვიდი დღე იწვოდა, მაგრამ Alertmanager-ს მხოლოდ null მიმღები ჰქონდა.
ერთ დილით Optimacros-ის bare-metal კლასტერზე ყოველი kubectl გამოძახება ერთი და იმავე ხაზით ვარდებოდა:
x509: certificate has expired or is not yet valid: current time ... is after 2026-10-09T04:52:15Z
გაშვებული პოდები ტრაფიკს ისევ ემსახურებოდნენ, ამიტომ გარედან არაფერი ჩანდა გაფუჭებული. შიგნით კი controller-manager და scheduler crash-loop-ში იყვნენ — თითოეულს 28–31 რესტარტი. ახალი არაფერი იგეგმებოდა და არაფერი რეკონსილირდებოდა. CI ჯობები, რომლებსაც ახალი პოდები სჭირდებოდათ, უბრალოდ ვარდებოდნენ.
ზუსტად ერთი წელი
თარიღმა ყველაფერი გასცა. კლასტერი kubespray-ით 2025-10-09-ს დაყენდა და მას შემდეგ არასდროს განახლებულა. kubeadm ფოთლოვან სერტიფიკატებს — API სერვერის, kubelet კლიენტის, front-proxy-ს და admin, controller-manager, scheduler kubeconfig-ებს — ერთი წლით გასცემს. kubeadm upgrade მათ თან ახლავს და აახლებს, ამიტომ რეგულარულად განახლებული კლასტერები ამას ვერ ამჩნევენ. ეს კი არავის შეხებია, kubespray-ის auto_renew_certificates კი გამორთული იყო. ყველას ვადა ერთ წამში გაუვიდა.
შეკეთებისთვის ისიც მნიშვნელოვანია, რა არ დაზარალდა: CA ათი წლით არის, kubespray-ის etcd სერტიფიკატები — ასი წლით, kubelet-ის კლიენტური სერტიფიკატები კი თავად როტირდება. ანუ ეს განახლებაა და არა თავიდან აწყობა.
ალერტი იმუშავა
პირველი ფიქრი იყო „ამაზე ალერტი არ გვქონდა”. აღმოჩნდა, რომ ეს არასწორია, სიმართლე კი უარესია. kube-prometheus-stack ყუთიდანვე შეიცავს KubeClientCertificateExpiration-ს. მისი ისტორია Prometheus-ში ვნახე:
count_over_time(ALERTS{alertname="KubeClientCertificateExpiration",alertstate="firing"}[10d])
დაახლოებით შვიდი დღე warning-ად იწვოდა და ბოლო დღე — critical-ად. შემდეგ Alertmanager-ის დაგენერირებული კონფიგი გავხსენი. ერთადერთი მიმღები იყო "null" — ჩარტის ნაგულისხმევი მნიშვნელობა, რადგან Argo CD Application-ს alertmanager.config არასდროს დაუყენებია. ალერტი იდეალურად მუშაობდა. უბრალოდ წასასვლელი არსად ჰქონდა.
შეკეთება — თითო მასტერი
კლასტერს სამი control-plane ნოდი აქვს, ამიტომ სათითაოდ ვაახლებდი და თითოეულს ვამოწმებდი, სანამ შემდეგს შევეხებოდი:
/etc/kubernetes-ის ბექაპი არქივში.kubeadm certs renew allკლასტერის kubeadm კონფიგით. SAN-ები ინახება.- static pod-ების მანიფესტების გატანა, ლოდინი, სანამ API სერვერი, controller-manager და scheduler გაქრება, მანიფესტების დაბრუნება.
readyz-ის და, რაც მთავარია, რეალურად გაცემული სერტიფიკატის შემოწმება:
echo | openssl s_client -connect <master>:6443 2>/dev/null | openssl x509 -noout -enddate
მე-3 ნაბიჯს ხშირად გამოტოვებენ. kubeadm certs renew მხოლოდ ფაილებს წერს. გაშვებული პროცესები ძველ სერტიფიკატს მეხსიერებაში ინახავენ, სანამ static pod-ები არ გადაიტვირთება, ამიტომ „ფაილები ახალია” არაფერს ამტკიცებს.
ლეპტოპის kubeconfig-იც ახალი admin.conf-ით უნდა შეცვლილიყო. კიდევ ერთი ხაფანგი: kubespray server:-ს 127.0.0.1:6443-ზე წერს, ამიტომ დაკოპირებული ფაილი connection refused-ს იძლევა, სანამ მისამართს არ გადაწერ.
რომ აღარ განმეორდეს
პრევენცია: ყოველთვიური systemd ტაიმერი, რომელიც სერტიფიკატებს აახლებს — იმის კლონი, რასაც kubespray auto_renew_certificates: true-ით დააყენებდა, მასტერებზე გადანაწილებული დროით, რომ ერთდროულად არასდროს გადაიტვირთონ. ერთხელ ხელით გავუშვი და გაცემული სერტიფიკატი ისევ შევამოწმე: ტაიმერი, რომლის წარმატებაც არ გინახავს, იმედია და არა კონტროლი.
ნამდვილი ხვრელი მიწოდებაშია და ის ამ კლასტერზე ფართოა: ალერტი მიმღების გარეშე დეკორაციაა. Alertmanager-ის მიწოდების GitOps-ით მიერთება ცალკე გადაწყვეტილებად ჩაიწერა, საკუთარი ტრიგერით.
დასკვნები
- kubeadm კლასტერი, რომელსაც წელიწადში ერთხელ მაინც არ აახლებენ, control plane-ს ინსტალაციის წლისთავზე დაკარგავს.
- სერტიფიკატების განახლების შემდეგ შეამოწმე, რას გასცემს ენდპოინტი და არა რა დევს დისკზე.
- „ალერტი არ გვქონდა” და „ალერტი არსად წავიდა” ინციდენტის დროს ერთნაირად გამოიყურება. ყველა კლასტერზე შეამოწმე
receivers— მარტოხელაnullნიშნავს, რომ არავინ უსმენს. - სხვა მასტერზე ცალკე admin kubeconfig შეინახე: როცა პირველი გადაიტვირთება, შესასვლელი მაინც გექნება.