Autoskalowanie i zarządzanie zasobami w Kubernetes (przegląd i raport wideo)

27 kwietnia na konferencji Strajk 2019w ramach sekcji „DevOps” przekazany został raport „Autoskalowanie i zarządzanie zasobami w Kubernetesie”. Opowiada o tym, jak wykorzystać K8, aby zapewnić wysoką dostępność aplikacji i najwyższą wydajność.

Autoskalowanie i zarządzanie zasobami w Kubernetes (przegląd i raport wideo)

Tradycyjnie mamy przyjemność zaprezentować wideo z raportu (44 minuty, znacznie więcej informacji niż artykuł) i główne streszczenie w formie tekstowej. Iść!

Przeanalizujmy słowo po słowie temat raportu i zacznijmy od końca.

Kubernetes

Załóżmy, że mamy kontenery Docker na naszym hoście. Po co? Aby zapewnić powtarzalność i izolację, co z kolei pozwala na proste i dobre wdrożenie, CI/CD. Posiadamy wiele takich pojazdów z kontenerami.

Co w tym przypadku zapewnia Kubernetes?

  1. Przestajemy myśleć o tych maszynach i zaczynamy pracować z „chmurą” skupisko kontenerów lub strąki (grupy pojemników).
  2. Co więcej, nawet nie myślimy o pojedynczych podach, ale zarządzamy ich większą liczbąоwiększe grupy. Taki prymitywów wysokiego poziomu pozwólcie nam powiedzieć, że istnieje szablon do uruchomienia określonego obciążenia, a oto wymagana liczba instancji do jego uruchomienia. Jeśli później zmienimy szablon, wszystkie instancje ulegną zmianie.
  3. Z deklaratywne API Zamiast wykonywać sekwencję konkretnych poleceń, opisujemy „strukturę świata” (w YAML), którą tworzy Kubernetes. I znowu: gdy zmieni się opis, zmieni się także jego rzeczywiste wyświetlanie.

Управление ресурсами

CPU

Uruchommy na serwerze nginx, php-fpm i mysql. W usługach tych będzie działać jeszcze więcej procesów, z których każdy będzie wymagał zasobów obliczeniowych:

Autoskalowanie i zarządzanie zasobami w Kubernetes (przegląd i raport wideo)
(liczby na slajdzie to „papugi”, abstrakcyjne zapotrzebowanie każdego procesu na moc obliczeniową)

Aby ułatwić pracę z tym, logiczne jest łączenie procesów w grupy (na przykład wszystkie procesy nginx w jedną grupę „nginx”). Prostym i oczywistym sposobem na to jest umieszczenie każdej grupy w kontenerze:

Autoskalowanie i zarządzanie zasobami w Kubernetes (przegląd i raport wideo)

Aby kontynuować, musisz pamiętać, czym jest kontener (w systemie Linux). Ich pojawienie się było możliwe dzięki trzem kluczowym funkcjom jądra, zaimplementowanym dość dawno temu: możliwości, przestrzenie nazw и cgrupy. Dalszy rozwój ułatwiły inne technologie (w tym wygodne „powłoki”, takie jak Docker):

Autoskalowanie i zarządzanie zasobami w Kubernetes (przegląd i raport wideo)

W kontekście raportu interesują nas tylko cgrupy, ponieważ grupy kontrolne są częścią funkcjonalności kontenerów (Docker itp.), która implementuje zarządzanie zasobami. Procesy połączone w grupy, jak chcieliśmy, są grupami kontrolnymi.

Wróćmy do wymagań procesora dla tych procesów, a teraz dla grup procesów:

Autoskalowanie i zarządzanie zasobami w Kubernetes (przegląd i raport wideo)
(Powtarzam, że wszystkie liczby są abstrakcyjnym wyrazem zapotrzebowania na zasoby)

Jednocześnie sam procesor ma pewne skończone zasoby (w tym przykładzie jest to 1000), których każdemu może brakować (suma potrzeb wszystkich grup wynosi 150+850+460=1460). Co się stanie w tym przypadku?

Jądro zaczyna dystrybuować zasoby i robi to „sprawiedliwie”, dając każdej grupie tę samą ilość zasobów. Ale w pierwszym przypadku jest ich więcej niż potrzeba (333>150), więc nadmiar (333-150=183) pozostaje w rezerwie, która jest również równo rozdzielona pomiędzy dwa inne kontenery:

Autoskalowanie i zarządzanie zasobami w Kubernetes (przegląd i raport wideo)

W rezultacie: pierwszy kontener miał wystarczającą ilość zasobów, drugi – nie miał wystarczających zasobów, trzeci – nie miał wystarczających zasobów. Oto efekt działań „uczciwy” program planujący w systemie Linux - CFS. Jego działanie można dostosować za pomocą przypisania ciężary każdego z pojemników. Na przykład tak:

Autoskalowanie i zarządzanie zasobami w Kubernetes (przegląd i raport wideo)

Spójrzmy na przypadek braku zasobów w drugim kontenerze (php-fpm). Wszystkie zasoby kontenera są równomiernie rozdzielone pomiędzy procesami. W rezultacie proces główny działa dobrze, ale wszyscy pracownicy zwalniają, otrzymując mniej niż połowę tego, czego potrzebują:

Autoskalowanie i zarządzanie zasobami w Kubernetes (przegląd i raport wideo)

Tak działa harmonogram CFS. Będziemy dalej nazywać wagi, które przypisujemy do kontenerów upraszanie. Dlaczego tak jest – patrz dalej.

Spójrzmy na całą sytuację z drugiej strony. Jak wiadomo, wszystkie drogi prowadzą do Rzymu, a w przypadku komputera, do procesora. Jeden procesor, wiele zadań – potrzebujesz sygnalizacji świetlnej. Najprostszym sposobem zarządzania zasobami jest „sygnalizacja świetlna”: zapewnia ona jednemu procesowi stały czas dostępu do procesora, potem kolejnemu itd.

Autoskalowanie i zarządzanie zasobami w Kubernetes (przegląd i raport wideo)

Takie podejście nazywa się twardymi kwotami (twarde ograniczenie). Zapamiętajmy to po prostu jako granice. Jeśli jednak rozdzielisz limity na wszystkie kontenery, pojawi się problem: mysql jechał wzdłuż drogi i w pewnym momencie skończyło się zapotrzebowanie na procesor, ale wszystkie inne procesy są zmuszone czekać, aż procesor bezczynny.

Autoskalowanie i zarządzanie zasobami w Kubernetes (przegląd i raport wideo)

Wróćmy do jądra Linuksa i jego interakcji z procesorem - ogólny obraz wygląda następująco:

Autoskalowanie i zarządzanie zasobami w Kubernetes (przegląd i raport wideo)

cgroup ma dwa ustawienia - zasadniczo są to dwa proste „skręty”, które pozwalają określić:

  1. waga kontenera (zapytań) wynosi akcji;
  2. procent całkowitego czasu procesora przeznaczonego na pracę nad zadaniami kontenerowymi (limity). udział.

Jak zmierzyć procesor?

Istnieją różne sposoby:

  1. Co to jest papugi, nikt nie wie - za każdym razem trzeba negocjować.
  2. Zainteresowanie jaśniej, ale względnie: 50% serwera z 4 rdzeniami i 20 rdzeniami to zupełnie inne rzeczy.
  3. Możesz skorzystać z tych, które już wymieniłeś ciężary, o czym Linux wie, ale są one również względne.
  4. Najbardziej odpowiednią opcją jest pomiar zasobów obliczeniowych w sekundy. Te. w sekundach czasu procesora w odniesieniu do sekund czasu rzeczywistego: na 1 sekundę rzeczywistą podano 1 sekundę czasu procesora - jest to jeden cały rdzeń procesora.

Aby jeszcze bardziej ułatwić mówienie, zaczęto mierzyć bezpośrednio jądra, czyli taki sam czas procesora w stosunku do rzeczywistego. Ponieważ Linux rozumie wagi, ale nie tyle czas/rdzeni procesora, potrzebny był mechanizm do tłumaczenia z jednego na drugi.

Rozważmy prosty przykład z serwerem z 3 rdzeniami procesora, gdzie trzem podom zostaną nadane wagi (500, 1000 i 1500), które można łatwo przeliczyć na odpowiednie części przydzielonych im rdzeni (0,5, 1 i 1,5).

Autoskalowanie i zarządzanie zasobami w Kubernetes (przegląd i raport wideo)

Jeśli weźmiesz drugi serwer, na którym będzie dwa razy więcej rdzeni (6), i umieścisz tam te same pody, rozkład rdzeni można łatwo obliczyć, po prostu mnożąc przez 2 (odpowiednio 1, 2 i 3). Ale ważny moment następuje, gdy na tym serwerze pojawia się czwarty pod, którego waga dla wygody wyniesie 3000. Zabiera część zasobów procesora (połowa rdzeni), a dla pozostałych podów są one przeliczane (o połowę):

Autoskalowanie i zarządzanie zasobami w Kubernetes (przegląd i raport wideo)

Kubernetes i zasoby procesora

W Kubernetesie zasoby procesora są zwykle mierzone w miliadrax, tj. Za masę podstawową przyjmuje się 0,001 rdzeni. (To samo w terminologii Linux/cgroups nazywa się udziałem procesora, chociaż dokładniej 1000 milirdzeniowych = 1024 udziałów procesora.) K8s dba o to, aby nie umieszczać na serwerze więcej podów niż jest zasobów procesora na sumę wag wszystkich podów.

Jak to się stało? Po dodaniu serwera do klastra Kubernetes raportowana jest liczba dostępnych rdzeni procesora. Podczas tworzenia nowego poda program planujący Kubernetes wie, ile rdzeni będzie potrzebował ten pod. Tym samym pod zostanie przypisany do serwera, na którym jest wystarczająca liczba rdzeni.

Co się stanie jeśli nie żądanie jest określone (tj. pod nie ma określonej liczby potrzebnych rdzeni)? Zastanówmy się, jak ogólnie Kubernetes liczy zasoby.

W przypadku kapsuły możesz określić zarówno żądania (harmonogram CFS), jak i limity (pamiętasz sygnalizację świetlną?):

  • Jeśli są one określone jako równe, do kapsuły przypisana jest klasa QoS gwarantowane. Ta liczba zawsze dostępnych dla niego rdzeni jest gwarantowana.
  • Jeśli żądanie jest mniejsze niż limit - klasa QoS wybuchowy. Te. Oczekujemy, że pod będzie zawsze korzystał z 1 rdzenia, ale ta wartość nie stanowi dla niego ograniczenia: czasami pod może wykorzystać więcej (gdy serwer ma na to wolne zasoby).
  • Istnieje również klasa QoS najlepszy wysiłek — obejmuje te właśnie zasobniki, dla których nie określono żądania. Zasoby są im przekazywane na końcu.

Память

Z pamięcią sytuacja jest podobna, choć nieco inna – wszak inny jest charakter tych zasobów. Ogólnie rzecz biorąc, analogia jest następująca:

Autoskalowanie i zarządzanie zasobami w Kubernetes (przegląd i raport wideo)

Zobaczmy, jak żądania są implementowane w pamięci. Pozwól podom działać na serwerze, zmieniając zużycie pamięci, aż jeden z nich stanie się tak duży, że zabraknie mu pamięci. W tym przypadku pojawia się zabójca OOM i zabija największy proces:

Autoskalowanie i zarządzanie zasobami w Kubernetes (przegląd i raport wideo)

Nie zawsze nam to odpowiada, dlatego można regulować, które procesy są dla nas ważne, a których nie należy zabijać. Aby to zrobić, użyj parametru oom_score_adj.

Wróćmy do klas QoS procesora i narysujmy analogię z wartościami oom_score_adj, które określają priorytety zużycia pamięci dla podów:

  • Najniższa wartość oom_score_adj dla poda - -998 - oznacza, że ​​taki pod powinien zostać zabity jako ostatni, to gwarantowane.
  • Najwyższy - 1000 - jest najlepszy wysiłek, takie strąki są zabijane w pierwszej kolejności.
  • Aby obliczyć pozostałe wartości (wybuchowy) istnieje formuła, której istota sprowadza się do tego, że im więcej zasobów zażądał kapsuła, tym mniejsze jest prawdopodobieństwo, że zostanie zabity.

Autoskalowanie i zarządzanie zasobami w Kubernetes (przegląd i raport wideo)

Drugi „zwrot akcji” – limit_w_bajtach - dla limitów. Dzięki niemu wszystko jest prostsze: po prostu przydzielamy maksymalną ilość wydanej pamięci i tutaj (w przeciwieństwie do procesora) nie ma mowy o tym, jak ją zmierzyć (pamięć).

Razem

Każdy pod w Kubernetesie jest podany requests и limits - oba parametry procesora i pamięci:

  1. na podstawie żądań działa planista Kubernetes, który rozdziela pody pomiędzy serwery;
  2. na podstawie wszystkich parametrów określana jest klasa QoS kapsuły;
  3. Wagi względne są obliczane na podstawie żądań procesora;
  4. harmonogram CFS jest konfigurowany w oparciu o żądania procesora;
  5. OOM Killer jest konfigurowany na podstawie żądań pamięci;
  6. „sygnalizacja świetlna” jest konfigurowana w oparciu o limity procesora;
  7. W oparciu o limity pamięci dla grupy c jest konfigurowany limit.

Autoskalowanie i zarządzanie zasobami w Kubernetes (przegląd i raport wideo)

Ogólnie rzecz biorąc, ten obraz odpowiada na wszystkie pytania dotyczące tego, jak przebiega główna część zarządzania zasobami w Kubernetesie.

Autoskalowanie

Automatyczne skalowanie klastrów K8s

Wyobraźmy sobie, że cały klaster jest już zajęty i należy utworzyć nowy zasobnik. Chociaż kapsuła nie może się pojawić, zawiesza się Do czasu. Aby tak się stało, możemy podłączyć nowy serwer do klastra lub... zainstalować Cluster-autoscaler, który zrobi to za nas: zamów maszynę wirtualną od dostawcy chmury (za pomocą żądania API) i podłącz ją do klastra , po czym pod zostanie dodany .

Autoskalowanie i zarządzanie zasobami w Kubernetes (przegląd i raport wideo)

Jest to autoskalowanie klastra Kubernetes, które sprawdza się świetnie (z naszego doświadczenia). Jednak, jak wszędzie, i tutaj są pewne niuanse...

Dopóki zwiększaliśmy rozmiar klastra, wszystko było w porządku, ale co się dzieje, gdy klaster zaczął się uwalniać? Problem polega na tym, że migracja podów (w celu uwolnienia hostów) jest bardzo trudna technicznie i kosztowna pod względem zasobów. Kubernetes stosuje zupełnie inne podejście.

Rozważmy klaster 3 serwerów z możliwością wdrożenia. Ma 6 podów: teraz są 2 na każdy serwer. Z jakiegoś powodu chcieliśmy wyłączyć jeden z serwerów. W tym celu użyjemy polecenia kubectl drain, Który:

  • zablokuje wysyłanie nowych podów na ten serwer;
  • usunie istniejące pody na serwerze.

Ponieważ Kubernetes odpowiada za utrzymanie liczby podów (6), to po prostu odtworzy je na innych węzłach, ale nie na tym, który jest wyłączony, ponieważ jest już oznaczony jako niedostępny do hostowania nowych podów. Jest to podstawowa mechanika Kubernetesa.

Autoskalowanie i zarządzanie zasobami w Kubernetes (przegląd i raport wideo)

Jednak i tutaj jest niuans. W podobnej sytuacji w przypadku StatefulSet (zamiast Deployment) działania będą inne. Teraz mamy już aplikację stanową - na przykład trzy pody z MongoDB, z których jeden ma jakiś problem (dane zostały uszkodzone lub inny błąd uniemożliwiający prawidłowe uruchomienie poda). I ponownie decydujemy się na wyłączenie jednego serwera. Co się stanie?

Autoskalowanie i zarządzanie zasobami w Kubernetes (przegląd i raport wideo)

MongoDB mógł umrzeć, ponieważ potrzebne jest kworum: w przypadku klastra trzech instalacji co najmniej dwie muszą działać. Jednak to nie dzieje się - dzięki Budżet PodDisruption. Parametr ten określa minimalną wymaganą liczbę stanowisk roboczych. Wiedza o tym, że jeden z podów MongoDB już nie działa i zobaczenie, że PodDisruptionBudget jest ustawiony na MongoDB minAvailable: 2, Kubernetes nie pozwoli Ci usunąć poda.

Konkluzja: aby przenoszenie (a właściwie ponowne tworzenie) podów działało poprawnie po zwolnieniu klastra, konieczne jest skonfigurowanie PodDisruptionBudget.

Skalowanie poziome

Rozważmy inną sytuację. Istnieje aplikacja działająca jako Deployment w Kubernetes. Ruch użytkowników trafia do jego podów (na przykład są ich trzy) i mierzymy w nich określony wskaźnik (powiedzmy obciążenie procesora). Gdy obciążenie wzrasta, rejestrujemy to zgodnie z harmonogramem i zwiększamy liczbę podów w celu dystrybucji żądań.

Dziś w Kubernetesie nie trzeba tego robić ręcznie: konfigurowane jest automatyczne zwiększanie/zmniejszanie liczby podów w zależności od wartości zmierzonych wskaźników obciążenia.

Autoskalowanie i zarządzanie zasobami w Kubernetes (przegląd i raport wideo)

Główne pytania tutaj to: co dokładnie mierzyć и jak interpretować uzyskane wartości (w celu podjęcia decyzji o zmianie liczby strąków). Można wiele zmierzyć:

Autoskalowanie i zarządzanie zasobami w Kubernetes (przegląd i raport wideo)

Jak to zrobić technicznie - zbierać metryki itp. — Mówiłem szczegółowo w raporcie nt Monitoring i Kubernetes. A główna rada dotycząca wyboru optymalnych parametrów brzmi eksperyment!

Jest Metoda UŻYJ (Nasycenie wykorzystania i błędy), którego znaczenie jest następujące. Na jakiej podstawie ma sens skalowanie np. php-fpm? Biorąc pod uwagę fakt, że brakuje pracowników, tak jest utylizacja. A jeśli pracownikom się skończy i nowe połączenia nie zostaną przyjęte, to już jest nasycenie. Obydwa te parametry należy zmierzyć i w zależności od wartości przeprowadzić skalowanie.

Zamiast zawierania

Raport ma ciąg dalszy: o skalowaniu wertykalnym i o tym, jak dobierać odpowiednie zasoby. Porozmawiam o tym w przyszłych filmach na temat naszego YouTuba - subskrybuj, aby nie przegapić!

Filmy i slajdy

Film z występu (44 minuty):

Prezentacja raportu:

PS

Inne relacje o Kubernetesie na naszym blogu:

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

Dodaj komentarz