Wdrożenie pojedynczego kontenera jest proste. Wdrożenie dziesięciu jest do opanowania. Ale gdy zarządzasz setkami kontenerów na dziesiątkach maszyn, ręczne zarządzanie przestaje być trudne, a staje się niemożliwe. Tracisz kontrolę nad tym, gdzie znajduje się dany kontener. Serwer pada, a Twoja aplikacja znika, dopóki ktoś się nie obudzi, aby ją zrestartować. Nagłe skoki ruchu przytłaczają Twoją infrastrukturę, zanim zdążysz uruchomić nowe instancje. Właśnie tutaj pojawia się Kubernetes. To nie jest po prostu kolejne narzędzie DevOps. To warstwa orkiestracji, która traktuje zarządzanie kontenerami jako problem kontrolny, a nie ćwiczenie ze skryptowania.
Dlaczego skrypty w końcu zawodzą
Większość zespołów zaczyna od skryptów powłoki (shell) lub podstawowej automatyzacji. Piszą komendy do pobierania obrazów, uruchamiania kontenerów, monitorowania logów i restartowania nieudanych procesów. Takie podejście sprawdza się przy prototypach (proof of concept), ale załamuje się pod realnym obciążeniem. Mikroserwisy komunikują się ze sobą między różnymi hostami, polegają na konkretnych zmiennych środowiskowych, potrzebują trwałej pamięci masowej, która przetrwa restarty kontenerów, i oczekują spójnej sieci między wersjami. Skrypt nie potrafi automatycznie zmienić harmonogramu obciążenia, gdy maszyna wirtualna zniknie. Nie potrafi rozdzielić ruchu sieciowego między sprawne instancje, omijając te, które utknęły w pętli awarii (crash loop). Kubernetes rozwiązuje ten problem, sprawiając, że to sam klaster odpowiada za te decyzje. Opisujesz, czego chcesz, a system stale wymusza ten stan.
Trzy rzeczy, które otrzymujesz
Kubernetes zapewnia trzy kluczowe możliwości, które zastępują ręczne gaszenie pożarów zautomatyzowaną niezawodnością.
Wysoka dostępność (High availability) oznacza, że Twoje aplikacje pozostają online, nawet gdy części Twojej infrastruktury ulegną awarii. Jeśli kontener ulegnie awarii, Kubernetes zastąpi go w ciągu kilku sekund. Jeśli cały węzeł roboczy (worker node) przestanie działać, scheduler zauważy brak sygnału heartbeat i przeniesie dotknięte obciążenia na sprawne maszyny w innym miejscu klastra. System stale monitoruje zdefiniowany przez Ciebie pożądany stan, korygując odchylenia bez ingerencji człowieka.
Skalowalność (Scalability) oznacza, że Twoje aplikacje rosną wraz z liczbą użytkowników. Zamiast przygotowywać dwadzieścia serwerów tylko po to, by przetrwać dwugodzinny szczyt ruchu, definiujesz istotne metryki, takie jak użycie CPU lub opóźnienie żądań, i pozwalasz klastrowi dodawać więcej instancji kontenerów po przekroczeniu progów. Gdy zapotrzebowanie spada, liczba replik ponownie maleje. Płacisz za to, czego potrzebujesz i kiedy tego potrzebujesz.
Odzyskiwanie po awarii (Disaster recovery) oznacza, że Twoje dane i konfiguracja wracają po awarii. Kubernetes przechowuje cały stan klastra w rozproszonej bazie klucz-wartość. Jeśli katastrofalna awaria usunie węzły robocze lub nawet część control plane, ten zapisany stan pozwoli systemowi odbudować Twoje obciążenia dokładnie tak, jak zostały skonfigurowane. Twoje dane wracają, ponieważ orkiestrator pamięta, jak powinny wyglądać.
Konfiguracja: Mózg i Mięśnie
Klaster Kubernetes posiada dwie fundamentalne role, które w opisie przedstawiono jako mózg i mięśnie – ta analogia dobrze sprawdza się w praktyce.
Master Node to mózg. Nie uruchamia on Twoich aplikacji skierowanych do klientów. Zamiast tego hostuje komponenty control plane, które planują zadania, zarządzają stanem klastra i reagują na zmiany. Gdy wydajesz polecenie lub przesyłasz plik konfiguracyjny, węzeł master decyduje, gdzie powinno znajdować się obciążenie, czy jest ono sprawne i co zrobić, gdy nie jest.
Worker Nodes to mięśnie. Każdy worker uruchamia lekki agent, który komunikuje się z masterem i używa środowiska uruchomieniowego kontenerów (container runtime) do wykonywania właściwych podów. To na tych węzłach kod Twojej aplikacji zużywa CPU i pamięć. Dodaj więcej węzłów roboczych, a Twój klaster zyska surową moc obliczeniową. Dodaj więcej węzłów master skonfigurowanych pod kątem redundancji, a Twój control plane stanie się odporny na pojedyncze awarie sprzętowe.
Pody, kontenery i usługi
Aby pracować z Kubernetes, musisz zrozumieć trzy terminy, które definiują sposób pakowania i uzyskiwania dostępu do oprogramowania.
Kontenery (Containers) to pakiety, które łączą Twoją aplikację z jej zależnościami, bibliotekami i konfiguracją. Izolują oprogramowanie od hosta, na którym działają, dzięki czemu działa ono w ten sam sposób w środowiskach development, staging i production.
Pody to najmniejsza jednostka wdrażalna w Kubernetes. Pod obejmuje jeden lub więcej kontenerów, które muszą współdzielić zasoby. Współdzielą tę samą przestrzeń nazw sieci (network namespace) i mogą mieć dostęp do tych samych lokalnych wolumenów pamięci masowej. To ważne: nie wdraża się gołego kontenera bezpośrednio. Wdraża się pod, który go zawiera. Pody są również celowo efemeryczne. Są tworzone, niszczone i zastępowane w miarę zmieniających się warunków. Ich cykl życia jest z założenia dynamiczny.
Usługi (Services) istnieją dlatego, że pody są przejściowe. Za każdym razem, gdy pod zostanie zrestartowany, prawdopodobnie otrzyma nowy wewnętrzny adres IP. Gdyby inne części Twojej aplikacji próbowały łączyć się bezpośrednio z tymi zmieniającymi się adresami, stale by ulegały awarii. Usługa zapewnia Twoim podom stały adres IP i nazwę DNS. Działa jak stabilne wejście, rozkładając obciążenie (load-balancing) przychodzących żądań pomiędzy wszystkie sprawne pody, które pasują do jej selektora. To oddziela Twoich klientów od chaosu cykli życia poszczególnych kontenerów.
Kubernetes w skali: Przykład Netflix
Netflix używa Kubernetes do zarządzania swoją siecią dostarczania treści (CDN). Ta infrastruktura przesyła strumienie wideo do milionów widzów jednocześnie na całym świecie. Gdy pojawia się popularny serial i popyt gwałtownie rośnie, klaster skaluje w górę węzły cache, które przechowują segmenty wideo bliżej użytkowników. Jeśli węzeł regionalny ulegnie awarii, ruch jest automatycznie przekierowywany. Rezultatem jest to, że filmy są nadal odtwarzane przez miliony ludzi bez konieczności ręcznego wzywania inżyniera w trybie awaryjnym. Orkiestrator zarządza skalą i awariami, dzięki czemu usługa działa nieprzerwanie.
Na początek: YAML, JSON i API Server
Rozpoczęcie pracy z Kubernetes oznacza porzucenie imperatywnego modelu „click-ops” na rzecz konfiguracji deklaratywnej. Opisujesz to, czego chcesz, w plikach YAML lub JSON. Te manifesty opisują wszystko: od obrazu kontenera, przez liczbę replik, wystawione porty, zmienne środowiskowe, aż po montowanie pamięci masowej. Gdy plik jest gotowy, wysyłasz go do API servera na węźle master. Control plane przyjmuje tę deklarację, przechowuje ją w bazie danych stanu klastra, a następnie przystępuje do pracy, aby rzeczywistość odpowiadała Twojemu opisowi. Nie mówisz Kubernetesowi dokładnie, jak ma wykonać swoją pracę. Mówisz mu, jaki ma być efekt końcowy, a on sam ustala kroki niezbędne do jego osiągnięcia.
Najważniejszy wniosek
Kubernetes wiąże się z krzywą uczenia się. Terminologia na początku wydaje się gęsta. Jest wiele ruchomych części, a debugowanie systemu rozproszonego jest z natury trudniejsze niż debugowanie pojedynczego serwera. Ale nagrodą jest spokój operacyjny. Przestajesz pilnować pojedynczych maszyn. Przestajesz modlić się, aby skrypty startowe zadziałały podczas awarii o 3 nad ranem. Zaczynasz projektować system z myślą o awariach (design for failure) domyślnie, zakładając, że węzły będą padać, i ufając orkiestratorowi, że utrzyma Twoją aplikację w całości. Ta zmiana nastawienia – od nadziei, że nic się nie zepsuje, do wiedzy, że system poradzi sobie z awarią – sprawia, że cały ten wysiłek jest tego wart.
Źródło: Co to jest Kubernetes? Wyjaśnienie Kubernetes w 15 minut
Opcjonalna społeczność edukacyjna: GyaanSetu AI na Telegramie
