Docker & Kubernetes: Triage Awarii Produkcyjnych, CrashLoopBackOff i SRE Runbook
Kompletny poradnik ratunkowy dla dowódców incydentów i inżynierów DevOps. Od analizy kodów wyjścia i limitów RAM w cgroups po Kubelet DiskPressure, awarie DNS w CNI i debugowanie efemeryczne na żywo.
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.
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:
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.
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.
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.