Kubernetes jest projektem open source orkiestratora, umożliwiającego uruchamianie skonteneryzowanych aplikacji. Projekt ten na początku tworzony był przez Google, które powołało go do życia, zainspirowane wieloma latami tworzenia i uruchamiania wysoce skalowalnych systemów w kontenerach, poprzez zorientowanie na aplikację API. Jednak Kubernetes to o wiele więcej niż tylko technologia udostępniona przez Google.
W tym momencie to cała społeczność pracująca nad coraz bogatszym ekosystemem, jakim stał się ten projekt. Dzięki temu uwolnieniu oprogramowania spod skrzydeł Google, dla społeczności Open Source Kubernetes stał się platformą spełniającą wymagania nie tylko ogromnych, wysoko skalowalnych infrastruktur internetowych gigantów, ale również umożliwił tworzenie infrastruktury dla aplikacji cloud-native mniejszym graczom, którzy mają zaledwie klika hostów.
Dobra, otrząśnijmy się jednak z tego new-sexy-it bełkotu i przejdźmy do rzeczy. Zacznijmy od wyjaśnienia czym są te opiewane w pieśniach bardów dystrybuowane skalowalne aplikacje i platforma zorientowana na API.Wyobraźmy sobie taką hipotetyczną sytuację, że mamy zadanie uruchomić infrastrukturę pod aplikację na stałe obciążenie generowane przez zdefiniowaną ilość użytkowników, ale (!) obciążenie może się w każdej chwili zmienić na dziesiątki tysięcy, czy też setki tysięcy więcej. Pewnie taka sytuacja nie jest wielu z Was obca – nie ma jak dobrze zdefiniowane wymagania aplikacji… ale tak między bogiem a prawdą, tego nie da się zdefiniować, bo nigdy nie wiadomo, czy aplikacja chwyci i będzie żarła, a w szczególności na samym początku jej działania. Nikt nie zna wówczas schematów zachowań przyszłych użytkowników, błędów w kodzie, kwestii wymagających optymalizacji. Aby przykład stał się bardziej rzeczywisty, weźmy na tapetę znaną i lubianą przez wszystkich stronę umożliwiającą komunikację za pomocą kamer internetowych. Oczywiście nie mówimy o tych stronach, o których właśnie pomyśleliście… oj, nie, nie! Chodzi mi np. o portale do korepetycji. Idźmy zatem dalej. Normalnie na takiej stronie mamy 2-3 tyś. użytkowników, coś tam oglądają, komunikują się itd. Jednakże zdarzają się takie pory roku lub dnia, gdy dopiero co pełnoletnie korepetytorki/korepetytorzy z krajów azjatyckich muszą pouczyć swoich klientów po drugiej stronie globu, gdzie akurat jest wieczór (wiadomo, korepetycje zawsze są po pracy, zajęciach itp.).
Zatem nagle na stronie, która była oparta o 5-10 instancji aplikacji, ma ich być ogromnie dużo i to w sekundę. Standardowa architektura monolityczna aplikacji byłaby tu niewygodna – trzeba by dorzucać procesory do VM’ek, dosypywać RAM itd. Słabo się to skaluje. Wyobraźmy sobie, że jak dotąd jedna VM w konfiguracji 4 vCPU i 64GB RAM obsługiwała około 1000 użytkowników. Aplikacja przetrzymywała dane i generalnie, jak już potencjalny nasz klient wpadł na dany serwer, to na nim siedział (przyczepiony był na przykład za pomocą sesji). Kiedy ilość użytkowników szła w górę, trzeba było szybko, za pomocą wydzierganego ręcznie mechanizmu zbadać, czy już wysyciliśmy serwer, czy może jeszcze ktoś się zmieści, za pomocą load balancera rozrzucić ruch. Jak brakło, biec i instalować nowy serwer. Brzmi to trywialnie na papierze, lecz w rzeczywistości jest trudne i długotrwałe. A to tylko skalowanie w górę. A w dół? A zmiana wersji? A awarie? Masakra.
Pomyślano zatem o nieco innym podejściu. Co, gdy zamiast wielkich VM ma się małe kontenerki (lub małe VM) realizujące bardzo konkretną funkcję – np. jedna robi logowanie, druga kolejkuje wiadomości (np. zapytania wyklinane w GUI, wiadomości między użytkownikami, akcje, które należy zalogować itp.), trzecia odpowiada za komunikację z bazą danych, lub tą bazą danych jest? Wszystkie one porozumiewają się ze sobą za pomocą API – czyli można by powiedzieć, takiego wewnętrznego języka aplikacji przesyłanego w stylu REST, za pomocą JSON, YAML itp. (języki formalne, uniwersalne, niezależne od języka, w którym napisana jest aplikacja). Poza ewentualnymi bazami danych żaden z elementów infrastruktury aplikacji nie przechowuje danych, a odpowiada za przechwycenie wpadających na API danych, przetworzenia zgodnie ze swoją funkcją, przesłania zwrotnego lub przesłania dalej do kolejnych instancji odpowiedzialnych za następne funkcje. Czyli ogólnie rzecz ujmując, zamiast jednej ogromnej binarki i armii bibliotek mieszczącej się na monstrualnej VM’ce, mamy wiele binarek i wiele zestawów bibliotek umieszczonych na wielu VM’kach lub w przypadku Kubernetesa kontenerach, czyli finalnie naszych mikroserwisów.
Na początku może się to zdawać niepotrzebnie skomplikowane, ale pomyślmy, że gdy potraktujemy każdą z tych funkcji jako zdefiniowaną strukturę infrastrukturalną (np. w kodzie), to powoływanie ich, automatycznie okaże się o niebo bardziej naturalne. Mniejsza aplikacja wymaga relatywnie mniej zależności, a co za tym idzie, jej konfiguracja podczas instalacji czy aktualizacji może być prostsza, kończy się mniejszą ilością błędów, a przez to, że nie przetrzymuje danych użytkownika, nie jest z nim związana. Zatem każdy użytkownik, za każdym razem może trafiać na inny węzeł serwerów aplikacji, a to sprawia, że nie musimy się martwić, jak jakiś fragment infry nam padnie… lub będziemy go aktualizować. Taka aplikacja może być napisana w różnych językach (zależnie od modułu), które będą się ze sobą komunikować za pomocą API. Wszystko brzmi cudnie… Tylko gdzie jest haczyk?
Przysłowiowy haczyk tkwi w tym, że takie new-wave-jezzy-funky aplikacje potrzebują platformy infrastrukturalne,j która będzie je wspierać. Dlaczego? Ponieważ czysta blacha z linuxem, lub gołe VM’ki są zbyt surowe, aby zrealizowanie tak skalowalną, samoleczącą się infrastrukturę aplikacji – byłoby to obrzydliwie skomplikowane i pracochłonne. Wymagałoby albo ogromnej ilości godzin pracy polegającej na tworzeniu automatów, albo ogromnego stosu technologicznego, za prawdopodobnie całkiem konkretne pieniądze… A na końcu, po miesiącach trudnej i żmudnej pracy napisalibyście Kubernetesa.
Artykuł opublikowany na łamach IT Professional.