Wymagania dotyczące tworzenia aplikacji w Kubernetesie

Dzisiaj planuję porozmawiać o tym jak pisać aplikacje i jakie są wymagania aby Twoja aplikacja działała dobrze w Kubernetesie. Żeby nie było problemów z aplikacją, żeby nie trzeba było wymyślać i budować wokół niej żadnych „scratków” – i wszystko działało tak, jak zamierzył sam Kubernetes.

Wykład ten jest częścią „Szkoła Nocna Slurm na Kubernetesie" Można obejrzeć otwarte wykłady teoretyczne Szkoły Wieczorowej na Youtube, pogrupowane w playlistę. Dla tych, którzy wolą tekst niż wideo, przygotowaliśmy ten artykuł.

Nazywam się Pavel Selivanov, obecnie jestem wiodącym inżynierem DevOps w Mail.ru Cloud Solutions, tworzymy chmury, zarządzamy Kubernetes i tak dalej. Do moich zadań należy teraz pomoc w rozwoju, wdrażanie tych chmur, wdrażanie napisanych przez nas aplikacji i bezpośredni rozwój narzędzi, które udostępniamy naszym użytkownikom.

Wymagania dotyczące tworzenia aplikacji w Kubernetesie

DevOps zajmuję się chyba od trzech lat. Ale w zasadzie tym, czym zajmuje się DevOps, zajmuję się już chyba od pięciu lat. Wcześniej zajmowałem się głównie sprawami administracyjnymi. Pracę z Kubernetesem zacząłem dawno temu - minęło już chyba jakieś cztery lata odkąd zacząłem z nim pracować.

Generalnie zaczynałem gdy Kubernetes był w wersji 1.3 prawdopodobnie, a może 1.2 - gdy był jeszcze w powijakach. Teraz nie jest to już w powijakach – a oczywiste jest, że na rynku jest ogromne zapotrzebowanie na inżynierów, którzy chcieliby umieć robić Kubernetesa. A firmy mają bardzo duże zapotrzebowanie na takich ludzi. Dlatego faktycznie pojawił się ten wykład.

Jeśli mówimy o planie tego, o czym będę mówił, wygląda to tak, w nawiasach jest napisane (TL;DR) - „za długi; nie czytaj”. Moja dzisiejsza prezentacja będzie składać się z niekończących się list.

Wymagania dotyczące tworzenia aplikacji w Kubernetesie

Tak naprawdę sam nie lubię takich prezentacji, kiedy się je robi, ale jest to taki temat, że przygotowując tę ​​prezentację, po prostu nie bardzo wiedziałem, jak inaczej zorganizować te informacje.

Bo w zasadzie ta informacja to „ctrl+c, ctrl+v”, z między innymi naszej Wiki w dziale DevOps, gdzie napisaliśmy wymagania dla programistów: „Kochani, abyśmy uruchomili waszą aplikację w Kubernetes, to. Tak powinno być.”

Dlatego prezentacja okazała się tak dużą listą. Przepraszam. Postaram się opowiedzieć jak najwięcej, żeby w miarę możliwości nie było nudno.

Czym się teraz zajmiemy:

  • są to przede wszystkim logi (logi aplikacji?), co z nimi zrobić w Kubernetesie, co z nimi zrobić, jakie powinny być;
  • co zrobić z konfiguracjami w Kubernetesie, jakie są najlepsze i najgorsze sposoby konfiguracji aplikacji dla Kubernetesa;
  • Porozmawiajmy o tym, czym w ogóle są kontrole dostępności, jak powinny wyglądać;
  • porozmawiajmy o tym, czym jest łagodne zamknięcie;
  • porozmawiajmy jeszcze raz o zasobach;
  • Poruszmy jeszcze raz temat przechowywania danych;
  • i na koniec zdradzę Wam, jak nazywa się ta tajemnicza, natywna dla chmury aplikacja. Cloudnativeness, jako przymiotnik tego terminu.

Dzienniki

Sugeruję zacząć od dzienników - od miejsca, w którym te dzienniki należy umieścić w Kubernetesie. Teraz uruchomiłeś aplikację w Kubernetesie. Według klasyków, wcześniej aplikacje zawsze zapisywały logi gdzieś w pliku. Złe aplikacje zapisywały dzienniki w pliku w katalogu domowym programisty, który uruchomił aplikację. Dobre aplikacje zapisywały logi do pliku gdzieś w /var/log.

Wymagania dotyczące tworzenia aplikacji w Kubernetesie

W związku z tym dobrzy administratorzy mieli w swojej infrastrukturze skonfigurowane pewne rzeczy, które umożliwiały rotację tych dzienników - ten sam rsyslog, który przegląda te logi i gdy coś im się stanie, jest ich dużo, tworzy kopie zapasowe, umieszcza tam logi , usuwa stare pliki, ponad tydzień, sześć miesięcy i trochę więcej. Teoretycznie powinniśmy mieć postanowienia, żeby po prostu dlatego, że aplikacja zapisuje logi, nie zabrakło miejsca na serwerach produkcyjnych (serwerach bojowych?). I odpowiednio cała produkcja nie została zatrzymana z powodu kłód.

Kiedy przenosimy się do świata Kubernetesa i uruchamiamy tam to samo, pierwszą rzeczą, na którą można zwrócić uwagę, jest fakt, że ludzie, jak zapisali logi w pliku, tak dalej je piszą.

Okazuje się, że jeśli mówimy o Kubernetesie, to właściwym miejscem do zapisania logów gdzieś z kontenera dockera jest po prostu zapisanie ich z aplikacji na tzw. Stdout/Stderr, czyli standardowe strumienie wyjściowe systemu operacyjnego, standardowe wyjście błędów. Jest to najbardziej poprawny, najprostszy i najbardziej logiczny sposób umieszczania logów w zasadzie w Dockerze, a konkretnie w Kubernetisie. Ponieważ jeśli Twoja aplikacja zapisuje logi na Stdout/Stderr, to Docker i dodatek Kubernetes decydują, co zrobić z tymi logami. Docker domyślnie zbuduje swoje specjalne pliki w formacie JSON.

Tutaj pojawia się pytanie, co dalej zrobisz z tymi logami? Najłatwiejszy sposób jest jasny, mamy możliwość to zrobić kubectl logs i spójrz na logi tych „strąków”. Ale prawdopodobnie nie jest to zbyt dobra opcja - z dziennikami trzeba zrobić coś innego.

Na razie porozmawiajmy przy okazji, skoro już poruszyliśmy temat logów, czyli o tym, jak powinny wyglądać logi. Oznacza to, że nie dotyczy to bezpośrednio Kubernetesa, jednak gdy zaczniemy zastanawiać się, co zrobić z logami, dobrze byłoby pomyśleć także o tym.

Potrzebujemy jakiegoś narzędzia, które w przyjazny sposób pobierze te logi, które nasz doker umieszcza w swoich plikach i gdzieś je wyśle. Ogólnie rzecz biorąc, zwykle uruchamiamy wewnątrz Kubernetesa jakiegoś agenta w postaci DaemonSet - modułu zbierającego logi, któremu po prostu mówi się, gdzie znajdują się logi zbierane przez Dockera. A ten podmiot zbierający po prostu je zabiera, być może nawet w jakiś sposób analizuje po drodze, być może wzbogaca je o dodatkowe metainformacje i ostatecznie wysyła je gdzieś do przechowywania. Tam już możliwe są zmiany. Najpopularniejszym jest prawdopodobnie Elasticsearch, w którym można przechowywać logi i wygodnie je stamtąd pobierać. Następnie za pomocą żądania, używając np. Kibany, buduj na ich podstawie wykresy, buduj na ich podstawie alerty i tak dalej.

Najważniejszą ideą, chcę to jeszcze raz powtórzyć, jest to, że w Dockerze, w szczególności w Kubernetesie, przechowywanie logów w pliku jest bardzo złym pomysłem.

Ponieważ po pierwsze, trudno jest umieścić logi w kontenerze w pliku. Najpierw musisz wejść do kontenera, wykonać tam operację, a następnie przejrzeć logi. Kolejna kwestia jest taka, że ​​jeśli masz logi w pliku, to kontenery zazwyczaj mają minimalistyczne środowisko i nie ma w nich żadnych narzędzi, które są zwykle potrzebne do normalnej pracy z logami. Zakop je, obejrzyj, otwórz w edytorze tekstu. Następny moment ma miejsce, gdy mamy logi w pliku w kontenerze, jeśli ten kontener zostanie usunięty, rozumiesz, logi umrą wraz z nim. W związku z tym każde ponowne uruchomienie kontenera oznacza, że ​​nie ma już więcej dzienników. Znowu zła opcja.

I ostatnia kwestia jest taka, że ​​wewnątrz kontenerów zazwyczaj masz swoją aplikację i tyle – zazwyczaj jest to jedyny działający proces. Nie ma w ogóle mowy o jakimkolwiek procesie, który miałby obracać pliki z logami. Gdy tylko logi zaczną być zapisywane do pliku, oznacza to, że, przepraszam, zaczniemy tracić serwer produkcyjny. Ponieważ, po pierwsze, trudno je znaleźć, nikt ich nie śledzi i nikt ich nie kontroluje - w związku z tym plik rośnie w nieskończoność, aż do wyczerpania się miejsca na serwerze. Dlatego jeszcze raz powtarzam, że logowanie się w Dockerze, w szczególności w Kubernetesie, do pliku to zły pomysł.

Kolejny punkt, tutaj chcę o tym jeszcze raz porozmawiać - skoro poruszamy temat logów, warto byłoby porozmawiać o tym, jak powinny wyglądać logi, aby praca z nimi była wygodna. Jak mówiłem temat nie jest bezpośrednio związany z Kubernetesem, ale bardzo dobrze nawiązuje do tematyki DevOps. W temacie kultury rozwoju i przyjaźni pomiędzy tymi dwoma różnymi działami - Dev i Ops, tak aby każdy czuł się komfortowo.

Oznacza to, że obecnie w idealnym przypadku logi powinny być zapisywane w formacie JSON. Jeśli masz jakąś własną niezrozumiałą aplikację, która zapisuje logi w niezrozumiałych formatach, bo wstawiasz jakiś wydruk czy coś w tym stylu, to czas wygooglować jakiś framework, jakiś wrapper, który pozwala na zaimplementowanie normalnego logowania; włącz tam parametry rejestrowania w JSON, ponieważ JSON jest prostym formatem, parsowanie jest proste.

Jeśli Twój JSON nie działa według jakichś kryteriów, nikt nie wie co, to przynajmniej napisz logi w formacie, który można przeanalizować. Tutaj raczej warto pomyśleć o tym, że jeśli np. uruchamiasz kilka kontenerów lub po prostu procesy z nginxem, a każdy ma swoje własne ustawienia logowania, to prawdopodobnie wydaje się, że będzie ci to bardzo niewygodne przeanalizuj je. Ponieważ dla każdej nowej instancji nginx trzeba napisać własny parser, bo oni zapisują logi inaczej. Ponownie, prawdopodobnie warto było pomyśleć o upewnieniu się, że wszystkie te instancje nginx miały tę samą konfigurację logowania i zapisywały wszystkie swoje logi absolutnie jednolicie. To samo dotyczy absolutnie wszystkich zastosowań.

Na koniec chcę też dolać oliwy do ognia, żeby najlepiej unikać kłód w formacie wielowierszowym. Rzecz w tym, że jeśli kiedykolwiek pracowałeś z podmiotami zbierającymi dzienniki, najprawdopodobniej widziałeś, co ci obiecują, że potrafią pracować z dziennikami wielowierszowymi, wiedzą, jak je zbierać i tak dalej. Tak naprawdę, moim zdaniem, żaden kolekcjoner nie jest dziś w stanie normalnie, w pełni i bez błędów zbierać dzienników wielowierszowych. Po ludzku, tak aby było wygodnie i bez błędów.

Wymagania dotyczące tworzenia aplikacji w Kubernetesie

Ale śledzenie stosu to zawsze dzienniki wielowierszowe i sposoby ich uniknięcia. Pytanie brzmi: dziennik jest zapisem zdarzenia, a stactrace w rzeczywistości nie jest dziennikiem. Jeśli zbierzemy logi i umieścimy je gdzieś w Elasticsearch, a następnie wyciągniemy z nich wykresy, zbudujemy raporty aktywności użytkowników na Twojej stronie, to gdy pojawi się ślad stosu, będzie to oznaczać, że dzieje się coś nieoczekiwanego, nieobsłużona sytuacja w Twojej aplikacji. Rozsądne jest także automatyczne przesyłanie śladów stosu do systemu, który może je śledzić.

Jest to oprogramowanie (ten sam Sentry), które zostało stworzone specjalnie do pracy ze śledzeniem stosu. Może natychmiast tworzyć zautomatyzowane zadania, przypisywać je do kogoś, ostrzegać o wystąpieniu stacttras, grupować te stacttrasy według jednego typu i tak dalej. W zasadzie nie ma większego sensu mówienie o stactracach, gdy mówimy o logach, bo przecież są to różne rzeczy i mają różne cele.

Konfiguracja

Następnie porozmawiamy o konfiguracji w Kubernetesie: co z nią zrobić i jak powinny być konfigurowane aplikacje wewnątrz Kubernetesa. Generalnie zazwyczaj powtarzam, że Docker nie dotyczy kontenerów. Wszyscy wiedzą, że Docker dotyczy kontenerów, nawet ci, którzy nie pracowali z Dockerem zbyt wiele. Powtarzam, Docker nie dotyczy kontenerów.

Moim zdaniem Docker dotyczy standardów. A standardy istnieją praktycznie na wszystko: standardy budowania aplikacji, standardy instalowania aplikacji.

Wymagania dotyczące tworzenia aplikacji w Kubernetesie

I to coś – używaliśmy go już wcześniej, stało się szczególnie popularne wraz z pojawieniem się kontenerów – to coś nazywa się zmiennymi ENV (środowiskowymi), to znaczy zmiennymi środowiskowymi, które znajdują się w twoim systemie operacyjnym. Jest to ogólnie idealny sposób na skonfigurowanie aplikacji, ponieważ jeśli masz aplikacje w JAVA, Python, Go, Perl, nie daj Boże, i wszystkie one potrafią odczytać hosta bazy danych, użytkownika bazy danych, zmienne hasła bazy danych, to jest to idealne rozwiązanie. Masz aplikacje w czterech różnych językach skonfigurowane w planie bazy danych w ten sam sposób. Nie ma już różnych konfiguracji.

Wszystko można skonfigurować za pomocą zmiennych ENV. Kiedy mówimy o Kubernetesie, istnieje świetny sposób na zadeklarowanie zmiennych ENV bezpośrednio w Deployment. W związku z tym, jeśli mówimy o tajnych danych, to możemy od razu wypchnąć tajne dane ze zmiennych ENV (hasła do baz danych itp.) Do sekretu, utworzyć tajny klaster i wskazać w opisie ENV we Wdrożeniu, że nie deklarujemy bezpośrednio z sekretu zostanie odczytana wartość tej zmiennej oraz wartość tej zmiennej hasła bazy danych. Jest to standardowe zachowanie Kubernetes. Jest to najbardziej idealna opcja konfiguracji aplikacji. Tylko na poziomie kodu, ponownie dotyczy to programistów. Jeśli jesteś DevOpsem, możesz zapytać: „Chłopaki, nauczcie swoją aplikację odczytywania zmiennych środowiskowych. I wszyscy będziemy szczęśliwi.”

Jeśli wszyscy w firmie czytają zmienne środowiskowe o tej samej nazwie, to świetnie. Żeby nie było tak, że jedni czekają na bazę danych postgres, inni na nazwę bazy danych, jeszcze inni na coś innego, jeszcze inni na jakiś dbn, żeby odpowiednio zachować jednolitość.

Problem pojawia się, gdy masz tak wiele zmiennych środowiskowych, że po prostu otwierasz Deployment - a istnieje pięćset linii zmiennych środowiskowych. W tym przypadku po prostu przerosłeś zmienne środowiskowe i nie musisz się już męczyć. W takim przypadku sensowne byłoby rozpoczęcie korzystania z konfiguracji. Oznacza to, że przeszkol swoją aplikację do korzystania z konfiguracji.

Pytanie tylko, że konfiguracje nie są takie, jak myślisz. Config.pi nie jest konfiguracją wygodną w użyciu. Lub jakaś konfiguracja w twoim własnym formacie, alternatywnie podarowana - to też nie jest ta konfiguracja, którą mam na myśli.

Mówię o konfiguracji w akceptowalnych formatach, czyli zdecydowanie najpopularniejszym standardem jest standard .yaml. Jasne jest, jak to przeczytać, jest czytelne dla człowieka, jasne jest, jak to odczytać z aplikacji.

W związku z tym, oprócz YAML, możesz także użyć np. JSON, parsowanie jest mniej więcej tak samo wygodne jak YAML pod względem odczytania stamtąd konfiguracji aplikacji. Czytanie jest zauważalnie bardziej niewygodne dla ludzi. Możesz wypróbować format a la ini. Z ludzkiego punktu widzenia jest to dość wygodne do odczytania, ale automatyczne przetwarzanie może być niewygodne, w tym sensie, że jeśli kiedykolwiek będziesz chciał wygenerować własne konfiguracje, wygenerowanie formatu ini może już być niewygodne.

Ale w każdym razie niezależnie od tego, jaki format wybierzesz, chodzi o to, że z punktu widzenia Kubernetesa jest to bardzo wygodne. Możesz umieścić całą konfigurację w Kubernetesie, w ConfigMap. Następnie weź tę mapę konfiguracyjną i poproś, aby została zamontowana w Twoim zasobniku w określonym katalogu, gdzie Twoja aplikacja odczyta konfigurację z tej mapy konfiguracyjnej tak, jakby to był tylko plik. Tak naprawdę warto to zrobić, gdy w aplikacji dostępnych jest wiele opcji konfiguracyjnych. Lub jest to po prostu jakaś złożona struktura, istnieje zagnieżdżanie.

Jeśli masz mapę konfiguracyjną, możesz bardzo dobrze nauczyć swoją aplikację, na przykład automatycznego śledzenia zmian w pliku, w którym zamontowana jest mapa konfiguracyjna, a także automatycznego ponownego ładowania aplikacji, gdy zmienią się konfiguracje. Ogólnie byłoby to idealne rozwiązanie.

Ponownie, już o tym mówiłem - tajne informacje nie znajdują się w mapie konfiguracyjnej, tajne informacje nie są zawarte w zmiennych, tajne informacje nie są zawarte w tajemnicach. Stamtąd połącz te tajne informacje z dyplomacją. Zwykle wszystkie opisy obiektów Kubernetesa, wdrożeń, map konfiguracyjnych i usług przechowujemy w git. W związku z tym umieszczanie hasła do bazy danych w git, nawet jeśli jest to Twój git, który masz wewnętrznie w firmie, jest złym pomysłem. Ponieważ git przynajmniej pamięta wszystko i samo usunięcie stamtąd haseł nie jest takie proste.

Kontrola zdrowia

Następnym punktem jest tak zwana kontrola stanu zdrowia. Ogólnie rzecz biorąc, kontrola stanu polega po prostu na sprawdzeniu, czy aplikacja działa. Jednocześnie najczęściej mówimy o pewnych aplikacjach internetowych, dla których odpowiednio z punktu widzenia kontroli stanu (lepiej nie tłumaczyć tu i dalej) będzie to jakiś specjalny adres URL, który przetwarzają jako standardem, zwykle to robią /health.

Odpowiednio podczas uzyskiwania dostępu do tego adresu URL nasza aplikacja mówi albo „tak, OK, u mnie wszystko w porządku, 200” lub „nie, u mnie nie wszystko jest w porządku, około 500”. W związku z tym, jeśli nasza aplikacja nie jest aplikacją http ani aplikacją internetową, mówimy teraz o jakimś demonie i możemy dowiedzieć się, jak przeprowadzić kontrolę stanu. Oznacza to, że nie jest konieczne, jeśli aplikacja nie jest http, wszystko działa bez kontroli stanu i nie można tego zrobić w żaden sposób. Możesz okresowo aktualizować niektóre informacje w pliku, możesz wymyślić specjalne polecenie dla swojego demona, np. daemon status, który powie „tak, wszystko w porządku, demon działa, żyje”.

Po co to jest? Pierwszą i najbardziej oczywistą rzeczą jest prawdopodobnie to, dlaczego potrzebna jest kontrola stanu - aby zrozumieć, że aplikacja działa. To znaczy, to jest po prostu głupie, kiedy teraz jest gotowe, wygląda na to, że działa, więc możesz być pewien, że działa. I okazuje się, że aplikacja działa, kontener działa, instancja działa, wszystko jest w porządku - a wtedy użytkownicy już odcięli wszystkie numery telefonów od pomocy technicznej i mówią „co ty…, ty zasnąłem, nic nie działa.”

Kontrola stanu to właśnie taki sposób, aby z punktu widzenia użytkownika przekonać się, że to działa. Jedna z metod. Ujmijmy to w ten sposób. Z punktu widzenia Kubernetesa jest to również sposób na zrozumienie, kiedy aplikacja się uruchamia, ponieważ rozumiemy, że istnieje różnica pomiędzy momentem uruchomienia, utworzenia i uruchomienia kontenera, a momentem uruchomienia aplikacji bezpośrednio w tym kontenerze. Ponieważ jeśli weźmiemy jakąś przeciętną aplikację Java i spróbujemy uruchomić ją w stacji dokującej, to na czterdzieści sekund, a nawet minutę, a nawet dziesięć, może zacząć się dobrze. W takim przypadku możesz przynajmniej zapukać do jego portów, nie będzie tam odpowiadać, to znaczy nie jest jeszcze gotowy do odbioru ruchu.

Ponownie, za pomocą kontroli stanu i dzięki temu, że tu skręcamy, możemy w Kubernetesie zrozumieć, że nie tylko kontener w aplikacji wzrósł, ale sama aplikacja została uruchomiona, już reaguje na sprawdzanie stanu, co oznacza, że ​​możemy tam kierować ruch.

Wymagania dotyczące tworzenia aplikacji w Kubernetesie

To, o czym teraz mówię, nazywa się testami gotowości/żywotności w Kubernetesie; w związku z tym nasze testy gotowości odpowiadają za dostępność aplikacji w balansowaniu. Oznacza to, że jeśli w aplikacji wykonywane są testy gotowości, to wszystko jest w porządku, ruch kliencki trafia do aplikacji. Jeśli nie zostaną wykonane testy gotowości, to aplikacja po prostu nie uczestniczy, ta konkretna instancja nie uczestniczy w równoważeniu, jest usuwana z równoważenia, ruch kliencki nie płynie. W związku z tym potrzebne są testy Liveness w Kubernetesie, aby w przypadku zablokowania aplikacji można było ją ponownie uruchomić. Jeśli test żywotności nie zadziała dla aplikacji zadeklarowanej w Kubernetesie, to aplikacja nie tylko zostanie usunięta z równoważenia, ale zostanie uruchomiona ponownie.

I tu jest ważna kwestia, o której chciałbym wspomnieć: z praktycznego punktu widzenia test gotowości jest zwykle stosowany częściej i jest częściej potrzebny niż test żywotności. Oznacza to, że po prostu bezmyślne deklarowanie zarówno testów gotowości, jak i żywotności, ponieważ Kubernetes może to zrobić, a wykorzystajmy wszystko, co potrafi, nie jest zbyt dobrym pomysłem. Wyjaśnię dlaczego. Ponieważ punktem drugim w testowaniu jest to, że dobrym pomysłem byłoby sprawdzenie podstawowej usługi w kontrolach stanu. Oznacza to, że jeśli masz aplikację internetową, która udostępnia pewne informacje, które z kolei, oczywiście, muszą skądś pobierać. W bazie danych np. Cóż, zapisuje informacje, które przychodzą do tego API REST, w tej samej bazie danych. Następnie, odpowiednio, jeśli twoja kontrola stanu odpowiada po prostu tak, jak skontaktowano się z slashhealth, aplikacja powie „200, OK, wszystko w porządku”, a jednocześnie baza danych twojej aplikacji jest niedostępna, a aplikacja kontroli stanu powie „200, OK, wszystko w porządku ” – To zła kontrola stanu zdrowia. To nie tak powinno działać.

To znaczy Twoja aplikacja, gdy pojawi się żądanie /health, nie odpowiada tylko „200, ok”, najpierw udaje się np. do bazy danych, próbuje się z nią połączyć, robi tam coś bardzo podstawowego, np. wybiera, po prostu sprawdza, czy jest połączenie w bazy danych i możesz wysyłać zapytania do bazy danych. Jeśli wszystko się udało, odpowiedź brzmi „200, OK”. Jeśli się nie powiedzie, pojawia się komunikat, że wystąpił błąd, baza danych jest niedostępna.

Dlatego w związku z tym ponownie wracam do testów gotowości/żywotności - dlaczego najprawdopodobniej potrzebujesz testu gotowości, ale test żywotności jest kwestionowany. Bo jeśli opiszesz kontrole kondycji dokładnie tak, jak przed chwilą mówiłem, to okaże się, że w części instancyjnej nie jest ona dostępnaв или со всех instancew bazie danych np. Kiedy zadeklarowałeś test gotowości, nasze kontrole stanu zaczęły zawodzić, w związku z czym wszystkie aplikacje, z których baza danych nie jest dostępna, są po prostu wyłączane z równoważenia i tak naprawdę „zawieszają się” po prostu w zaniedbanym stanie i czekają, aż ich bazy danych zostaną uruchomione praca.

Jeśli zadeklarowaliśmy test żywotności, to wyobraźmy sobie, że nasza baza danych uległa awarii, a w Twoim Kubernetesie połowa wszystkiego zaczyna się od nowa, ponieważ test żywotności się nie powiódł. Oznacza to, że musisz uruchomić ponownie. To wcale nie jest to, czego chcesz, miałem nawet osobiste doświadczenie w praktyce. Mieliśmy aplikację do czatu napisaną w JS i wprowadzoną do bazy danych Mongo. I problem w tym, że już na początku mojej pracy z Kubernetesem opisywaliśmy gotowość, żywotność testów w oparciu o zasadę, że Kubernetes to potrafi, więc z tego skorzystamy. W związku z tym w pewnym momencie Mongo stało się trochę „nudne” i próbka zaczęła zawodzić. W związku z tym, zgodnie z testem deszczowości, strąki zaczęły „zabijać”.

Jak rozumiesz, kiedy zostaną „zabici”, jest to czat, to znaczy, że zawiesza się na nim wiele połączeń od klientów. Oni też są „zabijani” – nie, nie klienci, tylko kontakty – nie wszyscy w tym samym czasie, a ponieważ nie są zabijani w tym samym czasie, jedni wcześniej, inni później, nie zaczynają od tego samego czas. Poza tym w przypadku standardowej losowości nie możemy przewidzieć z dokładnością do milisekundy czasu rozpoczęcia aplikacji za każdym razem, więc robią to pojedynczo. Powstaje jeden infospot, jest doliczany do bilansu, wszyscy klienci tam przychodzą, nie jest w stanie wytrzymać takiego obciążenia, bo jest sam, a z grubsza pracuje ich tam kilkunastu i spada. Następny podnosi się, cały ciężar spada na niego, on też spada. Cóż, te spadki po prostu następują kaskadą. W końcu jak to rozwiązano - musieliśmy po prostu ściśle zatrzymać ruch użytkowników do tej aplikacji, pozwolić wszystkim instancjom wzrosnąć, a następnie uruchomić cały ruch użytkowników na raz, tak aby był już rozdzielony pomiędzy wszystkie dziesięć instancji.

Gdyby nie ogłoszenie testu żywotności, który wymusiłby ponowne uruchomienie wszystkiego, aplikacja poradziłaby sobie z tym doskonale. Ale wszystko, począwszy od równoważenia, jest dla nas wyłączone, ponieważ bazy danych są niedostępne i wszyscy użytkownicy „odpadli”. Następnie, gdy ta baza danych stanie się dostępna, wszystko jest objęte równoważeniem, ale aplikacje nie muszą zaczynać się od nowa i nie ma potrzeby tracić na to czasu i zasobów. Wszyscy już są, są gotowi na ruch, więc ruch po prostu się otwiera, wszystko jest w porządku - aplikacja jest na swoim miejscu, wszystko nadal działa.

Dlatego testy gotowości i żywotności są różne, a ponadto teoretycznie można przeprowadzić różne kontrole stanu, na przykład jeden typ promienia, jeden typ liv i sprawdzać różne rzeczy. Podczas testów gotowości sprawdź swoje backendy. Na przykład w teście żywotności nie sprawdza się z punktu widzenia, czy test żywotności jest ogólnie po prostu odpowiedzią aplikacji, jeśli w ogóle jest w stanie odpowiedzieć.

Ponieważ test żywotności, ogólnie rzecz biorąc, polega na tym, że „utkniemy”. Rozpoczęła się nieskończona pętla lub coś innego - i żadne więcej żądań nie są przetwarzane. Dlatego warto je nawet rozdzielić - i wdrożyć w nich inną logikę.

Jeśli chodzi o to, na co musisz odpowiedzieć, kiedy masz test, kiedy przeprowadzasz kontrolę stanu zdrowia. To po prostu naprawdę ból. Ci, którzy to znają, prawdopodobnie będą się śmiać - ale poważnie, widziałem w swoim życiu usługi, które w 200% przypadków odpowiadały „XNUMX”. To znaczy, kto odnosi sukces. Ale jednocześnie w treści odpowiedzi piszą „taki a taki błąd”.

Oznacza to, że przychodzi do ciebie status odpowiedzi - wszystko się udało. Ale jednocześnie musisz przeanalizować ciało, ponieważ ciało mówi „przepraszam, żądanie zakończyło się błędem” i to jest po prostu rzeczywistość. Widziałem to w prawdziwym życiu.

I żeby niektórym nie wydawało się to śmieszne, a innym bardzo bolesne, warto jednak trzymać się prostej zasady. Podczas kontroli stanu i w zasadzie podczas pracy z aplikacjami internetowymi.

Jeśli wszystko poszło dobrze, odpowiedz dwusetną odpowiedzią. W zasadzie każda dwusetna odpowiedź będzie Ci odpowiadać. Jeśli bardzo dobrze czytasz ragsy i wiesz, że niektóre statusy odpowiedzi różnią się od innych, odpowiedz odpowiednimi: 204, 5, 10, 15, cokolwiek. Jeśli nie jest zbyt dobrze, to po prostu „dwa zero zero”. Jeśli wszystko pójdzie źle i kontrola stanu nie odpowiada, odpowiedz dowolną pięciosetną częścią. Ponownie, jeśli rozumiesz, jak odpowiedzieć, jak różne statusy odpowiedzi różnią się od siebie. Jeśli nie rozumiesz, możesz odpowiedzieć na kontrole stanu zdrowia pod numerem 502, jeśli coś pójdzie nie tak.

To kolejna kwestia. Chcę jeszcze trochę wrócić do sprawdzania podstawowych usług. Jeśli zaczniesz na przykład sprawdzać wszystkie podstawowe usługi stojące za Twoją aplikacją - ogólnie wszystko. To, co otrzymujemy z punktu widzenia architektury mikroserwisowej, to mamy taką koncepcję jak „niskie sprzężenie” – czyli wtedy, gdy Twoje usługi są od siebie minimalnie zależne. Jeśli jeden z nich ulegnie awarii, wszystkie pozostałe bez tej funkcji po prostu będą nadal działać. Niektóre funkcje po prostu nie działają. W związku z tym, jeśli powiążesz ze sobą wszystkie kontrole stanu, skończy się to awarią jednej rzeczy w infrastrukturze, a ponieważ upadła, wszystkie kontrole stanu wszystkich usług również zaczną zawodzić – i ogólnie jest więcej infrastruktury dla cała architektura mikroserwisowa nr. Wszystko tam pociemniało.

Dlatego jeszcze raz powtórzę, że należy sprawdzić usługi leżące u podstaw, czyli te, bez których Twoja aplikacja w stu procentach przypadków nie może spełnić swojego zadania. Oznacza to, że logiczne jest, że jeśli masz API REST, za pomocą którego użytkownik zapisuje do bazy danych lub pobiera z bazy danych, to w przypadku braku bazy danych nie możesz zagwarantować pracy z użytkownikami.

Jeśli jednak Twoi użytkownicy po wyjęciu ich z bazy zostaną dodatkowo wzbogaceni o jakieś inne metadane, z innego backendu, które wprowadzisz przed wysłaniem odpowiedzi do frontendu - a ten backend nie jest dostępny, oznacza to, że podajesz swoje odpowiedź bez jakiejkolwiek części metadanych.

Dalej mamy też jeden z bolesnych problemów przy uruchamianiu aplikacji.

Tak naprawdę nie dotyczy to w ogóle Kubernetesa; tak się złożyło, że kultura pewnego rodzaju masowego rozwoju, a w szczególności DevOps, zaczęła się rozprzestrzeniać mniej więcej w tym samym czasie co Kubernetes. W sumie zatem okazuje się, że trzeba z gracją zamknąć aplikację bez Kubernetesa. Ludzie to robili jeszcze przed Kubernetesem, ale wraz z pojawieniem się Kubernetesa zaczęliśmy o tym masowo rozmawiać.

Pełne wdzięku zamknięcie

Ogólnie rzecz biorąc, czym jest Graceful Shutdown i dlaczego jest potrzebne? Dzieje się tak w przypadku awarii aplikacji z jakiegoś powodu, co musisz zrobić app stop - albo otrzymujesz np. sygnał z systemu operacyjnego, Twoja aplikacja musi to zrozumieć i coś z tym zrobić. Najgorszy scenariusz to oczywiście sytuacja, w której Twoja aplikacja otrzyma SIGTERM i będzie brzmiała: „SIGTERM, poczekajmy, pracuj, nic nie rób”. To wręcz zła opcja.

Wymagania dotyczące tworzenia aplikacji w Kubernetesie

Prawie równie złą opcją jest sytuacja, gdy Twoja aplikacja otrzymuje SIGTERM i jest w stylu „powiedzieli segterm, to znaczy, że kończymy, nie widziałem, nie znam żadnych żądań użytkowników, nie wiem, jakiego rodzaju wnioski, nad którymi teraz pracuję, powiedzieli SIGTERM, co oznacza, że ​​kończymy „ To także zła opcja.

Która opcja jest dobra? Pierwszą kwestią jest wzięcie pod uwagę zakończenia operacji. Dobrą opcją jest, aby Twój serwer nadal brał pod uwagę to, co robi, jeśli otrzyma SIGTERM.

SIGTERM to miękkie zamknięcie, jest specjalnie zaprojektowane, można je przechwycić na poziomie kodu, można je przetworzyć, powiedzmy, że teraz, poczekaj, najpierw skończymy pracę, którą mamy, a potem wyjdziemy.

Z perspektywy Kubernetesa wygląda to tak. Kiedy mówimy do poda działającego w klastrze Kubernetes „proszę zatrzymać się, odejdź” lub następuje ponowne uruchomienie lub aktualizacja, gdy Kubernetes odtwarza pody, Kubernetes wysyła do poda ten sam komunikat SIGTERM, czeka na jakiś czas, i to jest czas, w którym on czeka, to też jest skonfigurowane, w dyplomach jest taki specjalny parametr i nazywa się Graceful ShutdownTimeout. Jak rozumiesz, nie bez powodu tak się to nazywa i nie bez powodu o tym teraz mówimy.

Tam możemy konkretnie określić, jak długo musimy czekać pomiędzy momentem wysłania SIGTERM do aplikacji, a momentem, w którym zrozumiemy, że aplikacja chyba oszalała za czymś lub „utknęła” i nie zamierza się zakończyć - i musimy to zrobić wyślij go SIGKILL, czyli ciężko ukończ jego pracę. Oznacza to, że mamy uruchomionego pewnego rodzaju demona, który przetwarza operacje. Rozumiemy, że średnio nasze operacje, nad którymi pracuje demon, nie trwają jednorazowo dłużej niż 30 sekund. W związku z tym, gdy nadejdzie SIGTERM, rozumiemy, że nasz demon może zakończyć co najwyżej 30 sekund po SIGTERM. Na wszelki wypadek zapisujemy to np. 45 sekund i mówimy, że SIGTERM. Następnie czekamy 45 sekund. Teoretycznie w tym czasie demon powinien zakończyć swoje dzieło i zakończyć się. Ale jeśli nagle nie może, oznacza to, że najprawdopodobniej utknął — nie przetwarza już normalnie naszych żądań. A w 45 sekund możesz go bezpiecznie przygwoździć.

I tutaj tak naprawdę można wziąć pod uwagę nawet 2 aspekty. Po pierwsze zrozum, że jeśli otrzymałeś żądanie, to jakoś zacząłeś z nim pracować i nie udzieliłeś użytkownikowi odpowiedzi, ale otrzymałeś np. SIGTERM. Warto to dopracować i dać odpowiedź użytkownikowi. To jest punkt numer jeden w tym względzie. Punkt numer dwa jest taki, że jeśli napiszesz własną aplikację, generalnie zbuduj architekturę w taki sposób, że otrzymasz żądanie dla swojej aplikacji, a następnie zaczniesz pracować, zaczniesz skądś pobierać pliki, pobierać bazę danych i tak dalej. - To. Ogólnie rzecz biorąc, twój użytkownik, twoje żądanie wisi na pół godziny i czeka, aż mu odpowiesz - wtedy najprawdopodobniej będziesz musiał popracować nad architekturą. Oznacza to, że po prostu weź pod uwagę nawet zdrowy rozsądek, że jeśli twoje operacje są krótkie, to warto zignorować SIGTERM i go zmodyfikować. Jeśli Twoje operacje są długie, nie ma sensu ignorować SIGTERM w tym przypadku. Aby uniknąć tak długich operacji, sensowne jest przeprojektowanie architektury. Aby użytkownicy nie tylko kręcili się i czekali. Nie wiem, zrób tam jakiś websocket, wykonaj odwrotne hooki, które twój serwer już wyśle ​​do klienta, cokolwiek innego, ale nie zmuszaj użytkownika do zawieszenia się na pół godziny i po prostu poczekaj na sesję, aż ty odpowiedz mu. Ponieważ nie można przewidzieć, gdzie może się zepsuć.

Kiedy aplikacja zakończy działanie, powinieneś podać odpowiedni kod zakończenia. Oznacza to, że jeśli aplikacja została poproszona o zamknięcie, zatrzymanie i była w stanie normalnie się zatrzymać, nie musisz zwracać żadnego kodu wyjścia 1,5,255 i tak dalej. Wszystko, co nie jest kodem zerowym, przynajmniej w systemach Linux, jestem tego pewien, uważa się za nieudane. Oznacza to, że uważa się, że w tym przypadku Twoja aplikacja zakończyła się błędem. W związku z tym, w sposób polubowny, jeśli Twoja aplikacja zakończy się bez błędu, na wyjściu wpiszesz 0. Jeśli z jakiegoś powodu aplikacja nie powiedzie się, na wyjściu pojawi się wartość różna od 0. I możesz pracować z tymi informacjami.

I ostatnia opcja. Źle jest, gdy użytkownik wysyła żądanie i zawiesza się na pół godziny podczas jego przetwarzania. Ale ogólnie chciałbym też powiedzieć o tym, co ogólnie warto ze strony klienta. Nie ma znaczenia, czy masz aplikację mobilną, front-end itp. Należy wziąć pod uwagę, że w zasadzie sesja użytkownika może zostać zakończona, wszystko może się zdarzyć. Żądanie może zostać wysłane np. niedostatecznie przetworzone i nie otrzyma żadnej odpowiedzi. Twój frontend czy aplikacja mobilna – w ogóle każdy frontend, tak to ujmijmy – powinien wziąć to pod uwagę. Jeśli pracujesz z websocketami, jest to generalnie najgorszy ból, jaki kiedykolwiek doświadczyłem.

Kiedy twórcy niektórych zwykłych czatów o tym nie wiedzą, okazuje się, że websocket może się zepsuć. W ich przypadku, gdy coś dzieje się na serwerze proxy, po prostu zmieniamy konfigurację i następuje przeładowanie. Oczywiście w tym przypadku wszystkie długotrwałe sesje są rozdarte. Programiści przybiegają do nas i mówią: „Chłopaki, co wy robicie, czat się zepsuł wszystkim naszym klientom!” Mówimy im: „Co robisz? Czy Twoi klienci nie mogą ponownie się połączyć? Mówią: „Nie, sesje nie powinny być rozdarte”. Krótko mówiąc, jest to właściwie bzdura. Należy wziąć pod uwagę stronę klienta. Zwłaszcza, jak mówię, przy długotrwałych sesjach, takich jak websockety, może się zepsuć i niezauważony przez użytkownika trzeba mieć możliwość ponownej instalacji takich sesji. I wtedy wszystko jest idealne.

Ресурсы

Właściwie, tutaj opowiem ci prostą historię. Znowu z prawdziwego życia. Najbardziej chora rzecz, jaką kiedykolwiek słyszałem o zasobach.

Zasoby w tym przypadku mam na myśli pewnego rodzaju żądania, limity, które możesz nakładać na pody w swoich klastrach Kubernetes. Najzabawniejsza rzecz, jaką usłyszałem od programisty... Jeden z moich kolegów programistów w poprzednim miejscu pracy powiedział kiedyś: „Moja aplikacja nie uruchamia się w klastrze”. Sprawdziłem, czy się nie uruchamia, ale albo nie mieści się w zasobach, albo ustalono bardzo małe limity. Krótko mówiąc, aplikacji nie można uruchomić ze względu na zasoby. Mówię: „Nie zacznie się ze względu na zasoby, ty decydujesz, ile potrzebujesz i ustalasz odpowiednią wartość”. Mówi: „Jakiego rodzaju zasoby?” Zacząłem mu tłumaczyć, że Kubernetes, limity żądań i bla, bla, bla trzeba ustawić. Mężczyzna słuchał przez pięć minut, skinął głową i powiedział: „Przyjechałem tu pracować jako programista, nie chcę nic wiedzieć o żadnych zasobach. Przyszedłem tutaj, żeby napisać kod i to wszystko. To jest smutne. To bardzo smutna koncepcja z punktu widzenia dewelopera. Zwłaszcza we współczesnym, że tak powiem, świecie postępowych devopsów.

Dlaczego w ogóle potrzebne są zasoby? W Kubernetesie istnieją 2 typy zasobów. Niektóre nazywane są żądaniami, inne nazywane są limitami. Dzięki zasobom zrozumiemy, że zasadniczo zawsze istnieją tylko dwa podstawowe ograniczenia. Oznacza to, że limity czasu procesora i limity pamięci RAM dla kontenera działającego w Kubernetes.

Limit określa górny limit sposobu wykorzystania zasobu w aplikacji. Oznacza to, że jeśli w limitach podasz 1 GB pamięci RAM, Twoja aplikacja nie będzie mogła wykorzystać więcej niż 1 GB pamięci RAM. A jeśli nagle zechce i spróbuje to zrobić, wówczas pojawi się proces o nazwie oom zabójca, czyli brak pamięci i zabije twoją aplikację - to znaczy po prostu uruchomi się ponownie. Aplikacje nie zostaną ponownie uruchomione ze względu na procesor. Jeśli chodzi o procesor, jeśli aplikacja próbuje użyć dużo, więcej niż określono w limitach, procesor zostanie po prostu wybrany ściśle. Nie prowadzi to do ponownego uruchomienia. To jest granica - to jest górna granica.

I jest prośba. Żądanie to sposób, w jaki Kubernetes rozumie, w jaki sposób węzły w klastrze Kubernetes są zapełniane aplikacjami. Oznacza to, że żądanie jest rodzajem zatwierdzenia aplikacji. Mówi, czego chcę użyć: „Chciałbym, żebyś zarezerwował dla mnie tyle procesora i tyle pamięci”. Taka prosta analogia. A co jeśli mamy węzeł, który ma w sumie, nie wiem, 8 procesorów. I tam przybywa kapsuła, której żądania mówią 1 CPU, co oznacza, że ​​w węźle pozostało 7 CPU. Oznacza to odpowiednio, że gdy tylko do tego węzła dotrze 8 podów, z których każdy ma w swoich żądaniach 1 procesor, w węźle, jakby z punktu widzenia Kubernetesa, zabrakło procesora i nie można obsłużyć większej liczby podów z żądaniami uruchomiony w tym węźle. Jeśli we wszystkich węzłach zabraknie procesora, Kubernetes zacznie informować, że w klastrze nie ma odpowiednich węzłów do uruchomienia podów, ponieważ skończył się procesor.

Do czego potrzebne są żądania i dlaczego bez żądań myślę, że nie ma potrzeby uruchamiać czegokolwiek w Kubernetesie? Wyobraźmy sobie hipotetyczną sytuację. Uruchamiasz aplikację bez żądań, Kubernetes nie wie, ile z tego masz, do jakich węzłów możesz to wypchnąć. Cóż, popycha, popycha, popycha na węzły. W pewnym momencie zaczniesz generować ruch do swojej aplikacji. I jedna z aplikacji nagle zaczyna wykorzystywać zasoby do granic, jakie posiada zgodnie z limitami. Okazuje się, że w pobliżu znajduje się inna aplikacja, która również potrzebuje zasobów. W węźle faktycznie zaczynają fizycznie kończyć się zasoby, na przykład OP. W węźle faktycznie zaczynają fizycznie kończyć się zasoby, na przykład pamięć o dostępie swobodnym (RAM). Kiedy w węźle zabraknie prądu, najpierw przestanie odpowiadać okno dokowane, potem kostka, a na końcu system operacyjny. Po prostu stracą przytomność i WSZYSTKO na pewno przestanie dla Ciebie działać. Oznacza to, że spowoduje to zablokowanie węzła i konieczne będzie jego ponowne uruchomienie. Krótko mówiąc, sytuacja nie jest zbyt dobra.

A gdy masz żądania, limity nie różnią się zbytnio, a przynajmniej nie wiele razy więcej niż limity lub żądania, to możesz mieć takie normalne, racjonalne wypełnianie aplikacji w węzłach klastrów Kubernetes. Jednocześnie Kubernetes jest w przybliżeniu świadomy, ile z tego, gdzie umieszcza, ile z tego, gdzie wykorzystuje. To znaczy, że to właśnie taki moment. Ważne jest, aby to zrozumieć. Ważne jest, aby kontrolować, czy jest to wskazane.

Przechowywanie danych

Następny punkt dotyczy przechowywania danych. Co z nimi zrobić i w ogóle, co zrobić z trwałością w Kubernetesie?

Myślę, że znowu w naszym Szkoła wieczorowa, był temat o bazie danych w Kubernetesie. I wydaje mi się, że nawet z grubsza wiem, co powiedzieli Ci Twoi koledzy na pytanie: „Czy da się uruchomić bazę danych w Kubernetesie?” Z jakiegoś powodu wydaje mi się, że Twoi koledzy powinni byli Ci powiedzieć, że jeśli zadajesz sobie pytanie, czy da się uruchomić bazę danych w Kubernetesie, to jest to niemożliwe.

Logika jest tu prosta. Na wszelki wypadek wyjaśnię jeszcze raz, jeśli jesteś naprawdę fajnym facetem, który potrafi zbudować w miarę odporny na awarie system rozproszonej sieciowej pamięci masowej, zrozumiesz, jak zmieścić bazę danych w tym przypadku, jak powinna działać chmura natywna w kontenerach ogólnie w bazie danych. Najprawdopodobniej nie masz wątpliwości, jak go uruchomić. Jeśli masz takie pytanie i chcesz mieć pewność, że to wszystko się rozwinie i dotrwa do śmierci w produkcji i nigdy nie spadnie, to tak się nie dzieje. Dzięki takiemu podejściu z pewnością strzelisz sobie w stopę. Więc lepiej tego nie robić.

Co powinniśmy zrobić z danymi, które nasza aplikacja chciałaby przechowywać, niektórymi zdjęciami, które przesyłają użytkownicy, niektórymi rzeczami, które nasza aplikacja generuje podczas działania, np. przy uruchomieniu? Co z nimi zrobić w Kubernetesie?

Ogólnie rzecz biorąc, idealnie, tak, oczywiście, Kubernetes jest bardzo dobrze zaprojektowany i ogólnie był początkowo pomyślany dla aplikacji bezstanowych. To znaczy w przypadku aplikacji, które w ogóle nie przechowują informacji. To jest idealne.

Ale oczywiście idealna opcja nie zawsze istnieje. Więc co? Pierwszym i najprostszym punktem jest wzięcie jakiegoś S3, byle nie domowego, co też nie jest jasne, jak to działa, ale od jakiegoś dostawcy. Dobry, normalny dostawca - i naucz swoją aplikację obsługi S3. Oznacza to, że gdy użytkownik chce przesłać plik, powiedz „tutaj, proszę, prześlij go do S3”. Kiedy będzie chciał go otrzymać, powiedz: „Oto link do S3 i zabierz go stąd”. To jest idealne.

Jeśli nagle z jakiegoś powodu ta idealna opcja nie jest odpowiednia, masz aplikację, której nie napisałeś, której nie rozwijasz, lub jest to jakieś straszne dziedzictwo, nie może ona korzystać z protokołu S3, ale musi współpracować z lokalnymi katalogami w foldery lokalne. Weź coś mniej lub bardziej prostego, wdróż Kubernetes. Oznacza to, że natychmiastowe odgrodzenie Cepha w celu wykonania jakichś minimalnych zadań jest, moim zdaniem, złym pomysłem. Bo Ceph oczywiście jest dobry i modny. Ale jeśli tak naprawdę nie rozumiesz, co robisz, to kiedy już nałożysz coś na Ceph, możesz bardzo łatwo i po prostu nigdy więcej tego nie wyjąć. Ponieważ, jak wiadomo, Ceph przechowuje dane w swoim klastrze w formie binarnej, a nie w postaci prostych plików. Dlatego jeśli nagle klaster Ceph ulegnie awarii, istnieje całkowite i duże prawdopodobieństwo, że już nigdy nie odzyskasz stamtąd swoich danych.

Zorganizujemy kurs na Ceph, możesz zapoznaj się z programem i złóż wniosek.

Dlatego lepiej zrobić coś prostego, jak serwer NFS. Kubernetes może z nimi współpracować, możesz zamontować katalog pod serwerem NFS - Twoja aplikacja działa jak katalog lokalny. Jednocześnie oczywiście musisz zrozumieć, że znowu musisz coś zrobić ze swoim NFS, musisz zrozumieć, że czasami może on stać się niedostępny i rozważyć pytanie, co zrobisz w tym przypadku. Być może należy utworzyć kopię zapasową gdzieś na osobnym komputerze.

Następnym punktem, o którym mówiłem, jest to, co zrobić, jeśli aplikacja generuje pewne pliki podczas działania. Na przykład podczas uruchamiania generuje plik statyczny, który opiera się na informacjach, które aplikacja otrzymuje dopiero w momencie uruchomienia. Co za chwila. Jeśli nie ma zbyt wielu takich danych, nie musisz się w ogóle przejmować, po prostu zainstaluj tę aplikację dla siebie i pracuj. Pytanie tylko brzmi: co, spójrz. Bardzo często wszelkiego rodzaju starsze systemy, takie jak WordPress i tak dalej, zwłaszcza ze zmodyfikowanymi jakimiś sprytnymi wtyczkami, sprytni programiści PHP, często wiedzą, jak to zrobić, aby wygenerowali dla siebie jakiś plik. Odpowiednio jeden generuje jeden plik, drugi generuje drugi plik. Oni są różni. Równoważenie odbywa się w klastrze Kubernetes klienta po prostu przez przypadek. W związku z tym okazuje się, że nie wiedzą, jak na przykład współpracować. Jeden podaje jedną informację, drugi daje użytkownikowi inną informację. Jest to coś, czego powinieneś unikać. Oznacza to, że w Kubernetesie gwarantujemy, że wszystko, co uruchomisz, będzie działać w wielu instancjach. Ponieważ Kubernetes jest rzeczą poruszającą się. W związku z tym może przenieść wszystko, kiedy tylko chce, bez pytania kogokolwiek. Dlatego trzeba na to liczyć. Wszystko uruchomione w jednej instancji prędzej czy później zakończy się niepowodzeniem. Im więcej rezerwacji, tym lepiej. Ale powtarzam, jeśli masz kilka takich plików, możesz je umieścić tuż pod sobą, ważą niewielką ilość. Jeśli jest ich trochę więcej, prawdopodobnie nie należy wpychać ich do pojemnika.

Radziłbym, że w Kubernetesie jest taka cudowna rzecz, że możesz używać głośności. W szczególności istnieje wolumin typu pusty reż. Oznacza to, że Kubernetes automatycznie utworzy katalog w swoich katalogach usług na serwerze, na którym zacząłeś. A on ci go da, abyś mógł z niego skorzystać. Jest tylko jeden ważny punkt. Oznacza to, że Twoje dane nie będą przechowywane w kontenerze, ale na hoście, na którym działasz. Co więcej, Kubernetes w normalnej konfiguracji może kontrolować takie puste katalogi i jest w stanie kontrolować ich maksymalny rozmiar i nie pozwolić na jego przekroczenie. Jedyną kwestią jest to, że to, co napisałeś w pustym katalogu, nie zostanie utracone podczas ponownego uruchamiania poda. Oznacza to, że jeśli Twój kapsuła przez pomyłkę spadnie i ponownie się podniesie, informacje w pustym katalogu nigdzie nie zostaną przesłane. Może go użyć ponownie na nowym początku – i to dobrze. Jeśli Twój kapsuła gdzieś odejdzie, to naturalnie odejdzie bez danych. Oznacza to, że gdy tylko kapsuła z węzła, w którym została uruchomiona, z pustym katalogiem zniknie, pusty katalog zostanie usunięty.

Co jeszcze jest dobrego w pustym katalogu? Może służyć na przykład jako pamięć podręczna. Wyobraźmy sobie, że nasza aplikacja generuje coś w locie, przekazuje to użytkownikom i robi to przez długi czas. Dlatego aplikacja np. generuje i przekazuje je użytkownikom, a jednocześnie gdzieś je przechowuje, aby następnym razem, gdy użytkownik przyjdzie po to samo, szybciej będzie oddać to od razu wygenerowane. Można poprosić Kubernetesa o utworzenie pustego katalogu w pamięci. W ten sposób Twoje pamięci podręczne mogą ogólnie działać z błyskawiczną szybkością - pod względem szybkości dostępu do dysku. Oznacza to, że masz pusty katalog w pamięci, w systemie operacyjnym jest on przechowywany w pamięci, ale dla ciebie, dla użytkownika wewnątrz kapsuły, wygląda to jak katalog lokalny. Nie potrzebujesz aplikacji, aby uczyć jakiejkolwiek magii. Po prostu bezpośrednio pobierasz i umieszczasz plik w katalogu, ale tak naprawdę w pamięci systemu operacyjnego. Jest to również bardzo wygodna funkcja z punktu widzenia Kubernetesa.

Jakie problemy ma Minio? Główny problem Minio polega na tym, że aby to coś działało, musi gdzieś działać i musi istnieć jakiś system plików, czyli pamięć. I tutaj napotykamy te same problemy, które ma Ceph. Oznacza to, że Minio musi gdzieś przechowywać swoje pliki. To po prostu interfejs HTTP do plików. Co więcej, funkcjonalność jest wyraźnie gorsza niż w przypadku S3 Amazona. Wcześniej nie był w stanie poprawnie autoryzować użytkownika. Teraz, o ile wiem, może już tworzyć segmenty z różnymi uprawnieniami, ale znowu wydaje mi się, że głównym problemem jest, że tak powiem, podstawowy system przechowywania.

W jaki sposób pusty katalog w pamięci wpływa na limity? Nie ma to żadnego wpływu na limity. Leży w pamięci hosta, a nie w pamięci twojego kontenera. Oznacza to, że Twój kontener nie widzi pustego katalogu w pamięci jako części zajętej pamięci. Gospodarz to widzi. W związku z tym tak, z punktu widzenia kubernetesa, kiedy zaczniesz tego używać, dobrze byłoby zrozumieć, że poświęcasz część swojej pamięci na pusty katalog. W związku z tym zrozum, że pamięć może zabraknąć nie tylko z powodu aplikacji, ale także dlatego, że ktoś pisze do tych pustych katalogów.

Chmurowość

Ostatnim podtematem jest to, czym jest Cloudnative. Dlaczego jest to potrzebne? Chmurowość i tak dalej.

Oznacza to, że są to aplikacje, które są zdolne i napisane do pracy w nowoczesnej infrastrukturze chmurowej. Ale tak naprawdę Cloudnative ma jeszcze jeden taki aspekt. Że jest to nie tylko aplikacja, która uwzględnia wszystkie wymagania nowoczesnej infrastruktury chmurowej, ale także wie, jak pracować z tą nowoczesną infrastrukturą chmurową, wykorzystaj zalety i wady tego, że działa w tych chmurach. Nie przesadzaj i nie pracuj w chmurze, ale skorzystaj z zalet pracy w chmurze.

Wymagania dotyczące tworzenia aplikacji w Kubernetesie

Weźmy jako przykład Kubernetes. Twoja aplikacja działa w Kubernetesie. Twoja aplikacja zawsze może, a raczej administratorzy Twojej aplikacji, zawsze mogą utworzyć konto usługi. Czyli konto do autoryzacji w samym Kubernetesie na jego serwerze. Dodaj tam pewne prawa, których potrzebujemy. Dostęp do Kubernetes możesz uzyskać z poziomu swojej aplikacji. Co możesz zrobić w ten sposób? Przykładowo z aplikacji odbieraj dane o tym, gdzie znajdują się Twoje inne aplikacje, inne podobne instancje i razem jakoś klastrujcie na Kubernetesie, jeśli jest taka potrzeba.

Ponownie, dosłownie mieliśmy sprawę niedawno. Mamy jednego kontrolera, który monitoruje kolejkę. A kiedy w tej kolejce pojawią się jakieś nowe zadania, trafiają one do Kubernetesa - i wewnątrz Kubernetesa tworzy nowy pod. Daje temu kapsułowi nowe zadanie i w ramach tego kapsuły wykonuje to zadanie, wysyła odpowiedź do samego kontrolera, a kontroler następnie robi coś z tymi informacjami. Na przykład dodaje bazę danych. Czyli znowu jest to plus tego, że nasza aplikacja działa w Kubernetesie. Możemy wykorzystać samą wbudowaną funkcjonalność Kubernetesa, aby w jakiś sposób rozszerzyć i uczynić funkcjonalność naszej aplikacji wygodniejszą. Oznacza to, że nie ukrywaj jakiejś magii dotyczącej uruchamiania aplikacji, uruchamiania pracownika. W Kubernetesie wystarczy wysłać żądanie w aplikacji, jeśli aplikacja jest napisana w Pythonie.

To samo dotyczy sytuacji, gdy wyjdziemy poza Kubernetes. Mamy gdzieś uruchomionego Kubernetesa – dobrze, jeśli jest w jakiejś chmurze. Ponownie możemy, a nawet powinniśmy, jak sądzę, wykorzystać możliwości samej chmury, w której działamy. Od elementarnych rzeczy, które zapewnia nam chmura. Balansowanie, czyli możemy tworzyć balansery chmurowe i z nich korzystać. To bezpośrednia korzyść z tego, co możemy wykorzystać. Bo równoważenie chmury, po pierwsze, po prostu głupio zdejmuje z nas odpowiedzialność za to, jak ona działa, jak jest skonfigurowana. Do tego jest to bardzo wygodne, bo zwykły Kubernetes potrafi integrować się z chmurami.

To samo tyczy się skalowania. Zwykły Kubernetes może integrować się z dostawcami usług w chmurze. Wie jak zrozumieć, że jeśli w klastrze zabraknie węzłów, czyli skończyła się przestrzeń na węzły, to trzeba dołożyć – Kubernetes sam doda nowe węzły do ​​Twojego klastra i zacznie na nich uruchamiać pody. Oznacza to, że kiedy nadchodzi ładunek, liczba palenisk zaczyna rosnąć. Kiedy w węzłach klastra zabraknie tych podów, Kubernetes uruchamia nowe węzły i w związku z tym liczba podów może jeszcze wzrosnąć. I jest to bardzo wygodne. Jest to bezpośrednia możliwość skalowania klastra na bieżąco. Niezbyt szybko, w tym sensie, że nie jest to sekunda, ale raczej minuta na dodanie nowych węzłów.

Ale z mojego doświadczenia wynika, że ​​to najfajniejsza rzecz, jaką kiedykolwiek widziałem. Gdy klaster Cloudnative jest skalowany na podstawie pory dnia. Była to usługa zaplecza, z której korzystali ludzie na zapleczu. Oznacza to, że przychodzą do pracy o 9 rano, zaczynają logować się do systemu i odpowiednio klaster Cloudnative, w którym to wszystko działa, zaczyna puchnąć, uruchamiając nowe pody, aby każdy, kto przyjdzie do pracy, mógł pracować z aplikacją. Kiedy wychodzą z pracy o 8:6 lub 30:XNUMX, klastry Kubernetes zauważają, że nikt już nie korzysta z aplikacji i zaczynają się kurczyć. Gwarantowane są oszczędności do XNUMX procent. To działało wtedy w Amazonie, w Rosji nie było wtedy nikogo, kto potrafiłby to zrobić tak dobrze.

Powiem wprost, oszczędności wynoszą 30 procent po prostu dlatego, że korzystamy z Kubernetesa i korzystamy z możliwości chmury. Teraz można to zrobić w Rosji. Oczywiście nie będę się nikomu reklamował, ale powiedzmy, że są dostawcy, którzy mogą to zrobić, zapewniając to od razu po wyjęciu z pudełka za pomocą przycisku.

Jest jeszcze ostatnia kwestia, na którą chciałbym zwrócić Państwa uwagę. Aby Twoja aplikacja, Twoja infrastruktura była Cloudnative, warto w końcu zacząć dostosowywać podejście Infrastructure as a Code, czyli oznacza to, że Twoja aplikacja, a raczej Twoja infrastruktura, jest potrzebna dokładnie tak samo jak kod Opisz swoją aplikację, logikę biznesową w formie kodu. I pracuj z nim jak z kodem, to znaczy przetestuj go, wdróż, przechowuj w gicie, zastosuj do niego CICD.

I właśnie to pozwala, po pierwsze, zawsze mieć kontrolę nad swoją infrastrukturą, zawsze wiedzieć, w jakim jest stanie. Po drugie, unikaj ręcznych operacji, które powodują błędy. Po trzecie, unikaj po prostu tak zwanej rotacji, kiedy musisz ciągle wykonywać te same zadania ręczne. Po czwarte, pozwala znacznie szybciej odzyskać siły w przypadku awarii. W Rosji za każdym razem, gdy o tym mówię, zawsze jest ogromna liczba osób, które mówią: „Tak, to jasne, ale jest podejście, krótko mówiąc, nie trzeba niczego naprawiać”. Ale to prawda. Jeśli coś jest zepsute w Twojej infrastrukturze, to z punktu widzenia podejścia Cloudnative i z punktu widzenia Infrastruktury jako kodu, zamiast to naprawiać, iść na serwer, dowiedzieć się, co jest uszkodzone i to naprawić, jest to łatwiejsze aby usunąć serwer i utworzyć go ponownie. I przywrócę to wszystko.

Wszystkie te kwestie zostały omówione szerzej na stronie Kursy wideo Kubernetes: Junior, Basic, Mega. Klikając w link możesz zapoznać się z programem i warunkami. Wygodą jest to, że Kubernetesa możesz opanować ucząc się w domu lub pracując 1-2 godziny dziennie.

Źródło: www.habr.com

Dodaj komentarz