Jak uzyskać dostęp do zasobów Kubernetes Pod

Jak uzyskać dostęp do zasobów Kubernetes PodNagroda od Tohad

Na początku pracy z Kubernetes często zapomina się o konfiguracji zasobów kontenerów. Na tym etapie wystarczy upewnić się, że obraz Docker działa i można go wdrożyć w klastrze Kubernetes.

Jednak później aplikacja musi być wdrożona w produkcyjnym klastrze wraz z innymi aplikacjami. W tym celu należy przydzielić zasoby dla kontenera i upewnić się, że są wystarczające do uruchomienia i działania aplikacji, a także aby nie wystąpiły problemy z innymi uruchomionymi aplikacjami.

Zespół Kubernetes aaS od Mail.ru przetłumaczyła artykuł o zasobach kontenerów (CPU i MEM), zapytaniach i ograniczeniach zasobów. Dowiesz się, jakie korzyści dają te konfiguracje i co się stanie, jeśli ich nie ustawisz.

Zasoby obliczeniowe

Mamy dwa typy zasobów z następującymi jednostkami:

  • Procesor centralny (CPU) — rdzenie;
  • Pamięć (MEM) — bajty.

Zasoby są określane dla każdego kontenera. W następującym pliku YAML Pod zobaczysz sekcję zasobów, która zawiera żądane i maksymalne zasoby:

  • Żądane zasoby Pod = suma żądanych zasobów wszystkich kontenerów;
  • Maksymalne zasoby Pod = suma maksymalnych zasobów wszystkich kontenerów.

apiVersion: v1
kind: Pod
metadata:
  name: backend-pod-name
  labels:
    application: backend
spec:
  containers:
    — name: main-container
      image: my-backend
      tag: v1
      ports:
      — containerPort: 8080
      resources:
        requests:
          cpu: 0.2 # ŻĄDANE CPU: 200m rdzeni
          memory: "1Gi" # ŻĄDANA MEM: 1Gi
        limits:
          cpu: 1 # MAX UŻYCIE CPU: 1 rdzeń
          memory: "1Gi" # MAX UŻYCIE MEM:  1Gi
    — name: other-container
      image: other-app
      tag: v1
      ports:
      — containerPort: 8000
      resources:
        requests:
          cpu: "200m" # ŻĄDANE CPU: 200m rdzeni
          memory: "0.5Gi" # ŻĄDANA MEM: 0.5Gi
        limits:
          cpu: 1 # MAX UŻYCIE CPU: 1 rdzeń
          memory: "1Gi" # MAX UŻYCIE MEM:  1Gi

Przykład żądanych i maksymalnych zasobów

Pole resources.requested z specyfikacji Pod — jeden z elementów, który jest używany do wyszukiwania odpowiedniego węzła. Już na nim można zaplanować wdrożenie Pod. Jak więc szuka się odpowiedniego węzła?

Kubernetes składa się z kilku komponentów, w tym zawiera główny węzeł lub master node (Kubernetes Control Plane). W master node znajduje się kilka procesów: kube-apiserver, kube-controller-manager i kube-scheduler.

Proces kube-scheduler odpowiada za przeglądanie nowo utworzonych modułów i wyszukiwanie możliwych węzłów roboczych, które spełniają wszystkie wymagania modułów, w tym dotyczące liczby żądanych zasobów. Lista węzłów znalezionych przez kube-scheduler jest rankingurowana. Pod jest planowany na węźle z najwyższymi wynikami.

Jak uzyskać dostęp do zasobów Kubernetes PodGdzie zostanie umieszczony fioletowy Pod?

Na obrazku widać, że kube-scheduler musi zaplanować nowy fioletowy Pod. Klaster Kubernetes zawiera dwa węzły: A i B. Jak można zauważyć, kube-scheduler nie może zaplanować Pod na węzeł A — dostępne (niewykorzystane) zasoby nie odpowiadają wymaganiom fioletowego Pod. Tak więc, wymagane przez fioletowy Pod 1 GB pamięci nie zmieści się na węźle A, ponieważ dostępny poziom pamięci wynosi 0,5 GB. Jednak węzeł B ma wystarczające zasoby. W rezultacie kube-scheduler decyduje, że celem fioletowego Pod jest węzeł B.

Teraz wiemy, jak wymagane zasoby wpływają na wybór węzła do uruchomienia Pod. Ale jak wpływają ograniczenia zasobów?

Ograniczenia zasobów to granica, której CPU/MEM nie mogą przekraczać. Niemniej jednak zasób CPU jest elastyczny, dlatego kontenery, które osiągnęły ograniczenia CPU, nie spowodują zakończenia pracy Pod. Zamiast tego uruchomi się ograniczenie CPU. Jeśli jednak osiągnięty zostanie limit użycia MEM, kontener zostanie zatrzymany przez OOM-Killer i uruchomiony ponownie, jeśli jest to dozwolone przez ustawienia RestartPolicy.

Wymagane i ograniczone zasoby w szczegółach

Jak uzyskać dostęp do zasobów Kubernetes PodZwiązek zasobów między Dockerem a Kubernetesem

Najlepszym sposobem wyjaśnienia, jak działają wymagane i ograniczone zasoby, jest przedstawienie związku między Kubernetesem a Dockerem. Na powyższym rysunku można zobaczyć, jak związane są pola Kubernetes i flagi uruchamiania Dockera.

Pamięć: żądanie i ograniczenie

containers:
...
 resources:
   requests:
     memory: "0.5Gi"
   limits:
     memory: "1Gi"

Jak wspomniano powyżej, pamięć jest mierzona w bajtach. Opierając się na dokumentacji Kubernetes, możemy określić pamięć jako liczbę. Zwykle jest to liczba całkowita, na przykład 2678 — czyli 2678 bajtów. Można również użyć sufiksów G i Gi, ważne jest, aby pamiętać, że nie są one równoznaczne. Pierwszy — dziesiętny, a drugi — binarny. Na przykład, jak wspomniano w dokumentacji k8s: 128974848, 129e6, 129M, 123Mi — są one praktycznie ekwiwalentne.

Parametr Kubernetes limits.memory odpowiada fladze --memory z Dockera. W przypadku request.memory strzałka dla Dockera jest nieobecna, ponieważ Docker nie używa tego pola. Możesz zapytać, czy jest to w ogóle potrzebne? Tak, jest potrzebne. Jak już wspomniałem, pole ma znaczenie dla Kubernetes. Na podstawie informacji z niego kube-scheduler decyduje, na którym węźle zaplanować Pod.

Co się stanie, jeśli ustawi się zbyt mało pamięci dla żądania?

Jeśli kontener osiągnie granice wymaganej pamięci, Pod jest umieszczany w grupie Pod, które zostają zatrzymane w przypadku braku pamięci w węźle.

Co się stanie, jeśli ustalisz zbyt niską wartość limitu pamięci?

Jeśli kontener przekroczy limit pamięci, zostanie zakończony z powodu OOM-Killed. Zostanie uruchomiony ponownie, jeśli to możliwe na podstawie RestartPolicy, gdzie domyślną wartością jest Zawsze.

Co się stanie, jeśli nie podasz wymaganej pamięci?

Kubernetes weźmie wartość limitu i ustawi ją jako domyślną.

Co może się stać, jeśli nie określisz limitu pamięci?

Kontener nie ma ograniczeń, może używać tyle pamięci, ile chce. Jeśli zacznie korzystać z całej dostępnej pamięci węzła, zostanie zabity przez OOM. Następnie kontener zostanie uruchomiony ponownie, jeśli to możliwe na podstawie RestartPolicy.

Co się stanie, jeśli nie podasz limitów pamięci?

To najgorszy scenariusz: planer nie wie, ile zasobów potrzebuje kontener, co może spowodować poważne problemy na węźle. W takim przypadku dobrze byłoby mieć domyślne ograniczenia w przestrzeni nazw (ustawiane przez LimitRange). Domyślnie nie ma ograniczeń — Pod nie ma ograniczeń, może używać tyle pamięci, ile chce.

Jeśli wymagane pamięci jest więcej, niż może zaoferować węzeł, Pod nie zostanie zaplanowany. Ważne jest, aby pamiętać, że Requests.memory nie jest minimalną wartością. To opis ilości pamięci wystarczającej do ciągłej pracy kontenera.

Zazwyczaj zaleca się ustawienie tej samej wartości dla request.memory i limit.memory. Dzięki temu Kubernetes nie zaplanuje Pod na węźle, który ma wystarczająco pamięci, aby uruchomić Pod, ale nie wystarczająco na jego działanie. Należy pamiętać, że przy planowaniu Pod Kubernetes bierze pod uwagę tylko requests.memory, a limits.memory nie uwzględnia.

CPU: zapytanie i limit

containers:
...
 resources:
   requests:
     cpu: 1
   limits:
     cpu: "1200m"

Z CPU sprawy są nieco bardziej skomplikowane. Wracając do obrazka ilustrującego powiązanie między Kubernetes a Docker, można zauważyć, że request.cpu -the node, and the other — --cpu-shares, podczas gdy limit.cpu odpowiada fladze cpus w Dockerze.

CPU, które żąda Kubernetes, jest mnożone przez 1024 — proporcję cykli CPU. Jeśli chcesz zażądać 1 pełnego rdzenia, musisz dodać cpu: 1, jak pokazano powyżej.

Żądanie pełnego rdzenia (proporcja = 1024) nie oznacza, że kontener go otrzyma. Jeśli twój komputer gospodarza ma tylko jeden rdzeń, a ty używasz więcej niż jednego kontenera, wszystkie kontenery muszą wspólnie korzystać z dostępnego CPU. Jak to działa? Przyjrzyjmy się obrazkowi.

Jak uzyskać dostęp do zasobów Kubernetes Pod
Żądanie CPU — system z jednym rdzeniem

Wyobraźmy sobie, że masz system hosta z jednym rdzeniem, na którym działają kontenery. Mama (Kubernetes) upiekła ciasto (CPU) i chce podzielić je między dzieci (kontenery). Troje dzieci chce po całym cieście (proporcja = 1024), a jedno dziecko chce połowę ciasta (512). Mama chce być sprawiedliwa i przeprowadza proste obliczenie.

# Сколько пирогов хотят дети?
# 3 ребенка хотят по целому пирогу и еще один хочет половину пирога
cakesNumberKidsWant = (3 * 1) + (1 * 0.5) = 3.5
# Выражение получается так:
3 (ребенка/контейнера) * 1 (целый пирог/полное ядро) + 1 (ребенок/контейнер) * 0.5 (половина пирога/половина ядра)
# Сколько пирогов испечено?
availableCakesNumber = 1
# Сколько пирога (максимально) дети реально могут получить?
newMaxRequest = 1 / 3.5 =~ 28%

Na podstawie obliczeń troje dzieci dostanie po 28% rdzenia, a nie po całym rdzeniu. Czwarte dziecko dostanie 14% pełnego rdzenia, a nie połowę. Ale wszystko będzie inaczej, jeśli masz system wielordzeniowy.

Jak uzyskać dostęp do zasobów Kubernetes Pod
Żądanie CPU — system wielordzeniowy (4)

Na powyższym obrazku widać, że troje dzieci chce po całym cieście, a jedno — połowę. Ponieważ mama upiekła cztery ciasta, każde z jej dzieci dostanie tyle, ile chce. W systemie wielordzeniowym zasoby procesora są rozdzielane pomiędzy wszystkie dostępne rdzenie procesora. Jeśli kontener jest ograniczony do mniej niż jedno pełne rdzeń CPU, to i tak może go używać w 100%.

Przytoczone wyżej obliczenia są uproszczone, aby zrozumieć, jak CPU jest rozdzielane między kontenery. Oczywiście, oprócz samych kontenerów, są także inne procesy, które korzystają z zasobów CPU. Gdy procesy w jednym kontenerze są bezczynne, inne mogą korzystać z jego zasobów. CPU: "200m" -the node, and the other — CPU: 0,2, co oznacza około 20% jednego rdzenia.

Teraz porozmawiajmy o limit.cpu. CPU, które ogranicza Kubernetes, mnoży się przez 100. Wynik to ilość czasu, jaką kontener może używać co 100 µs (cpu-period).

limit.cpu odpowiednio do flagi Dockera --cpus. To nowa kombinacja starych --cpu-period i --cpu-quota. Ustawiając to, określamy, ile dostępnych zasobów CPU kontener może maksymalnie wykorzystać zanim zacznie się throttling:

  • cpus — kombinacja cpu-period i cpu-quota. cpus = 1.5 jest równoważna ustawieniu cpu-period = 100000 i cpu-quota = 150000;
  • cpu-period — okres planisty CPU CFS, domyślnie 100 mikrosekund;
  • cpu-quota — liczba mikrosekund w cpu-period, które ogranicza kontener.

Co się stanie, jeśli ustawimy zbyt małe żądanie CPU?

Jeśli kontener potrzebuje więcej, niż jest ustawione, to odbierze CPU innym procesom.

Co się stanie, jeśli ustawimy zbyt niski limit CPU?

Ponieważ zasób CPU jest regulowany, to włączy się throttling.

Co się stanie, jeśli nie wskaźesz żądania CPU?

Podobnie jak w przypadku pamięci, wartość żądania odpowiada limitowi.

Co się stanie, jeśli nie określę limitu CPU?

Kontener wykorzysta tyle CPU, ile potrzebuje. Jeśli w przestrzeni nazw zdefiniowana jest polityka CPU domyślnego (LimitRange), to ten limit będzie stosowany również do kontenera.

Co się wydarzy, jeśli nie określę ani żądania, ani limitu CPU?

Podobnie jak w przypadku pamięci, to najgorszy scenariusz. Planista nie wie, ile zasobów potrzebuje Twój kontener, co może spowodować poważne problemy na węźle. Aby tego uniknąć, należy ustawić domyślne ograniczenia dla przestrzeni nazw (LimitRange).

Pamiętaj: jeśli zażądają więcej CPU, niż mogą zapewnić węzły, Pod nie zostanie zaplanowany. Requests.cpu — to nie minimalna wartość, ale wartość wystarczająca do uruchomienia Pod i pracy bez zakłóceń. Jeśli aplikacja nie wykonuje skomplikowanych obliczeń, najlepiej ustawić request.cpu <= 1 i uruchomić tyle replik, ile to konieczne.

Idealna ilość żądanych zasobów lub limitu zasobów

Dowiedzieliśmy się o ograniczeniu zasobów obliczeniowych. Teraz czas odpowiedzieć na pytanie: „Ile zasobów potrzebuje mój Pod do bezproblemowego działania aplikacji? Jakie ilości są idealne?”.

Niestety, na te pytania nie ma jednoznacznych odpowiedzi. Jeśli nie wiesz, jak działa Twoja aplikacja, ile CPU lub pamięci potrzebuje, najlepiej zapewnić aplikacji dużo pamięci i CPU, a następnie przeprowadzić testy wydajności.

Oprócz testów wydajności, przez tydzień obserwuj zachowanie aplikacji w monitoringu. Jeśli z wykresów wynika, że Twoja aplikacja zużywa mniej zasobów, niż żądałeś, można zmniejszyć ilość zażądanych CPU lub pamięci.

Na przykład zapoznaj się z tym dashboardem Grafana. Wyświetla on różnicę między żądanymi zasobami lub limitem zasobów a aktualnym zużyciem zasobów.

Podsumowanie

Żądania i ograniczenia zasobów pomagają utrzymać sprawność klastra Kubernetes. Odpowiednia konfiguracja limitów minimalizuje koszty i nieprzerwanie utrzymuje aplikacje w działaniu.

Krótko mówiąc, należy pamiętać o kilku kwestiach:

  1. Wymagane zasoby to konfiguracja, która jest brana pod uwagę podczas uruchamiania (gdy Kubernetes planuje rozmieszczenie aplikacji). Z kolei limit zasobów ma znaczenie w trakcie działania — gdy aplikacja już działa na węźle.
  2. W porównaniu do pamięci, CPU to zasób regulowany. W przypadku niedoboru CPU Twój Pod nie zakończy pracy, uruchomi się mechanizm ograniczania.
  3. Wymagane zasoby i limit zasobów to nie minimalne i maksymalne wartości! Ustalając wymagane zasoby, gwarantujesz, że aplikacja będzie działać bez problemów.
  4. Dobrą praktyką jest ustawienie zapotrzebowania na pamięć równego limitowi pamięci.
  5. Dobrze jest ustawić zapotrzebowane CPU <=1, jeśli aplikacja nie wykonuje skomplikowanych obliczeń.
  6. Jeśli zażądzasz więcej zasobów, niż jest dostępne na węźle, Pod nigdy nie zostanie zaplanowany na ten węzeł.
  7. Aby określić odpowiednią ilość wymaganych zasobów/limitów zasobów, korzystaj z testowania obciążenia i monitorowania.

Mam nadzieję, że ten artykuł pomoże Ci zrozumieć podstawową koncepcję limitów zasobów. I będziesz mógł zastosować tę wiedzę w swojej pracy.

Powodzenia!

Co jeszcze przeczytać:

  1. Obserwowalność SRE: przestrzenie nazw i struktura metryk.
  2. 90+ przydatnych narzędzi dla Kubernetes: wdrożenie, zarządzanie, monitorowanie, bezpieczeństwo i nie tylko.
  3. Nasz kanał Wokół Kubernetes na Telegramie.

Źródło: habr.com

Kup solidny hosting stron z ochroną przed DDoS, serwery VPS VDS 🔥 Kup solidny hosting stron z ochroną przed DDoS, serwery VPS VDS | ProHoster