Rzeczywistość Awarii Produkcyjnej o 2:00 w Nocy

Gdy system PagerDuty wyje alertem o krytycznym incydencie na klastrze produkcyjnym, nikt nie ma czasu na przekopywanie się przez chaotyczne wątki na forach. Niezależnie od tego, czy zmagasz się ze szturmem CrashLoopBackOff, kaskadą zabójstw pamięci OOMKilled, czy nagłą utratą całych węzłów przechodzących w stan NotReady przez alert DiskPressure w Kubelecie – kluczem do przetrwania jest metodyczna diagnostyka śledcza.

Niniejszy poradnik stanowi spójne kompendium operacyjne dla środowisk kontenerowych Linux (Docker Engine, containerd, CRI-O) oraz nowoczesnego Kubernetesa (v1.28–v1.31+). Zawiera zwięzłą Matrycę Kodów Wyjścia Kontenerów, interaktywną wyszukiwarkę komend CLI oraz szczegółowe ścieżki dochodzenia przyczyn źródłowych.

💡 Błyskawiczna Nawigacja: Skorzystaj z poniższego panelu, aby natychmiast przefiltrować komendy według platformy lub słowa kluczowego (np. oom, drain, dns, crictl, secret). Kliknij dowolny boks z poleceniem, aby błyskawicznie skopiować je do schowka.

1. Matryca Śledcza Kodów Wyjścia Kontenera

W chwili niespodziewanego zakończenia procesu w kontenerze jądro Linuksa i środowisko uruchomieniowe zapisują numeryczny kod wyjścia (Exit Code). Zrozumienie jego znaczenia od razu wskazuje, czy problem tkwi w kodzie aplikacji, wyczerpaniu pamięci RAM, czy eksmisji infrastrukturalnej:

Kod Wyjścia Status / Nazwa Mechanizm Wyzwolenia Natychmiastowe Działanie SRE
0 Sukces / Zakończono Proces zakończył zadanie naturalnie (np. batch job, init-container, migracja bazy). Normalny stan dla Jobs/CronJobs. Jeśli wystąpił w usłudze ciągłej, sprawdź pętlę startową i argumenty wejściowe.
1 Błąd Aplikacji Nieobsłużony wyjątek w kodzie, błąd składni, brakujący plik konfiguracyjny lub zmienna środowiskowa. Sprawdź kubectl logs <pod> --previous. Zweryfikuj ciąg połączenia z bazą lub poprawność zamontowanych sekretów.
137 OOMKilled (128 + 9 SIGKILL) Kernelowy mechanizm OOM Killer ubił proces za przekroczenie limitu cgroup resources.limits.memory. Wywołaj kubectl describe pod | grep OOMKilled. Zwiększ limit RAM, dostosuj heap (np. -XX:MaxRAMPercentage) lub napraw wyciek.
139 Naruszenie Pamięci (SIGSEGV) Natywny program próbował uzyskać dostęp do nieprzydzielonego lub zabronionego obszaru pamięci RAM. Przebuduj obraz kontenera z odpowiednią biblioteką glibc/musl. Sprawdź rozszerzenia C, sterowniki lub uszkodzone biblioteki.
143 Łagodne Zatrzymanie (SIGTERM) Kubelet zainicjował wygaszenie poda w trakcie aktualizacji, procedury drain węzła lub skalowania w dół. Upewnij się, że aplikacja poprawnie obsługuje SIGTERM. Zwiększ terminationGracePeriodSeconds, jeśli urywa aktywne sesje.
255 Błąd Entrypointa Runtime kontenera nie mógł uruchomić skryptu wejściowego (brak uprawnień lub błąd ścieżki). Sprawdź uprawnienia do wykonywania w Dockerfile (chmod +x /entrypoint.sh) oraz poprawny nagłówek shebang (#!/bin/sh).

2. Interaktywny Panel Komend Awaryjnych SRE

Błyskawiczne filtrowanie sprawdzonych w boju poleceń dla Docker Engine i klastrów Kubernetes:

Lista Wszystkich Padających Podów Kubernetes
Wypisz pody we wszystkich przestrzeniach nazw (namespaces), które nie są w stanie Running lub Completed.
kubectl get pods -A --field-selector status.phase!=Running | grep -v Completed
Diagnoza OOMKilled & Kodów Wyjścia Kubernetes
Szczegółowa inspekcja przyczyny zgonu kontenera, kodu wyjścia i osi czasu ostatnich restartów.
kubectl describe pod <pod> -n <namespace> | grep -E "State:|Reason:|Exit Code:|Last State:"
Logi z Ubitej Poprzedniej Instancji Kubernetes
Pobierz strumień błędów stderr i zrzut stosu z poprzedniej instancji kontenera tuż przed restartem.
kubectl logs <pod> -n <namespace> -c <container> --previous --tail=100
Audyt Kondycji Węzła (Conditions) Kubernetes
Wykrywanie alertów sprzętowych jądra: DiskPressure, MemoryPressure, NetworkUnavailable i wyczerpania PID.
kubectl describe node <node> | grep -A 6 "Conditions:"
Bezpieczny Cordon & Drain Węzła Kubernetes
Wyłączenie węzła z planowania i bezpieczna ewakuacja podów przed pilnym restartem serwera.
kubectl cordon <node> && kubectl drain <node> --ignore-daemonsets --delete-emptydir-data --force
Czyszczenie Obrazów w containerd (crictl) containerd
Natychmiastowe usunięcie nieużywanych obrazów i martwych kontenerów w celu wygaszenia Kubelet DiskPressure.
crictl rmi --prune && crictl rm $(crictl ps -a -q --state Exited)
Awaryjne Czyszczenie Środowiska Docker Docker
Usunięcie osieroconych obrazów, martwych kontenerów, cache budowania oraz anonimowych wolumenów.
docker system prune -af --volumes
Kontrola Wyczerpania i-Węzłów (Inodes) Storage
Wykrywanie awarii braku miejsca, w których df -h pokazuje wolne GB, ale wyczerpały się i-węzły w overlay2.
df -h / /var/lib/kubelet /var/lib/docker && df -i /var/lib/docker
Logi i Dystrybucja Podów CoreDNS CNI & DNS
Weryfikacja dostępności replik CoreDNS, adresacji IP i logów błędów rozwiązywania zapytań DNS w klastrze.
kubectl logs -n kube-system -l k8s-app=kube-dns --tail=50
Test DNS wewnątrz Klastra (Ad-Hoc) CNI & DNS
Uruchomienie tymczasowego poda busybox w celu bezpośredniego testu opóźnień i działania CoreDNS.
kubectl run dns-test -it --rm --image=busybox:1.28 --restart=Never -- nslookup kubernetes.default
Wstrzyknięcie Debugera Netshoot w Poda Kubernetes
Wstrzyknięcie kontenera z narzędziami sieciowymi (curl, dig, tcpdump) bezpośrednio w przestrzeń PID/sieci poda.
kubectl debug -it <pod> -n <namespace> --image=nicolaka/netshoot --target=<container>
Ekstrakcja i Dekodowanie Sekretów Base64 RBAC & Konfiguracja
Błyskawiczne odszyfrowanie wszystkich wartości klucz-wartość w sekrecie k8s jednym potokiem w terminalu.
kubectl get secret <secret> -n <ns> -o jsonpath="{.data}" | jq 'map_values(@base64d)'
Audyt Uprawnień RBAC (auth can-i) RBAC & Bezpieczeństwo
Weryfikacja, czy konkretne konto ServiceAccount posiada uprawnienia do wykonania operacji API.
kubectl auth can-i create deployments --as=system:serviceaccount:<ns>:<sa> -n <ns>
Kontrola i Odnowienie Certyfikatów TLS Control Plane
Weryfikacja dat ważności certyfikatów control-plane i ich odnowienie przed paraliżem klastra.
kubeadm certs check-expiration && kubeadm certs renew all && systemctl restart kubelet

3. Głęboka Analiza: Przyczyny Źródłowe Awarii

Dlaczego Pody Zabijane są przez OOMKilled (cgroups v1 vs v2)

W środowisku Kubernetes limity pamięci (resources.limits.memory) egzekwowane są bezpośrednio przez jądro Linuksa za pośrednictwem grup kontrolnych (cgroups). Gdy proces w kontenerze zażąda większej ilości pamięci fizycznej RSS niż zdefiniowany próg, jądro nie buforuje ani nie przerzuca do swapu: natychmiast wysyła nieprzechwytywalny sygnał SIGKILL (Sygnał 9).

W przypadku aplikacji Java (JVM) lub Node.js zjawisko to występuje najczęściej, gdy środowisko wykonawcze nie rozpoznaje granic kontenera. Przykładowo, domyślna konfiguracja pamięci sterty w Javie na 64-rdzeniowej maszynie fizycznej może zażądać 25% z dostępnych 256 GB RAM serwera, co w 2-gigabajtowym kontenerze kończy się błyskawicznym OOMKilled kod 137. Zawsze pamiętaj o przekazaniu flagi -XX:MaxRAMPercentage=75.0.

⚠️ Uwaga na Limity Pamięci vs CPU: Ustawienie resources.limits.memory bez odpowiedniego bufora bezpieczeństwa prowadzi do natychmiastowego uśmiercenia poda. Z kolei limity procesora (resources.limits.cpu) powodują jedynie tzw. throttling CFS, spowalniając przetwarzanie bez wywoływania awarii.

Sekwencja Postępowania przy Kubelet DiskPressure

Gdy węzeł klastra zgłasza stan DiskPressure: True, Kubelet wstrzymuje przyjmowanie nowych podów i rozpoczyna eksmisję aplikacji o najniższej klasie jakości (BestEffort). Trzy najczęstsze powody to:

  • Gwałtowny przyrost logów w /var/log/pods/: Aplikacje wypisujące niebuforowany JSON na standardowe wyjście potrafią zapełnić dziesiątki gigabajtów na godzinę.
  • Osierocone warstwy obrazów: Wewnętrzny mechanizm zbierania śmieci (image GC) włącza się dopiero po przekroczeniu progu imageGCHighThresholdPercent (domyślnie 85%).
  • Martwe wolumeny i cache Docker/Containerd: Automatyzacje CI/CD tworzące dziesiątki tymczasowych kontenerów bez flagi --rm.
Złota Zasada SRE: Zawsze wykonuj df -i równolegle z df -h. Systemy plików z milionami drobnych plików tymczasowych mogą całkowicie wyczerpać pulę i-węzłów, mimo że dysk raportuje jeszcze dziesiątki wolnych gigabajtów.
Projekt SpecInfo.org jest rozwijany jako niezależny standard inżynieryjny. Jeśli to kompendium usprawniło Twoją pracę, wesprzyj projekt.
☕ Wesprzyj Projekt ↗