Nasze wnioski po roku migracji GitLab.com na Kubernetes

Przyp. tłum.: Wdrażanie Kubernetes w GitLab uznawane jest za jeden z głównych czynników przyczyniających się do wzrostu firmy. Niemniej jednak, do niedawna infrastruktura serwisu online GitLab.com była oparta na maszynach wirtualnych, a migracja do K8s rozpoczęła się zaledwie rok temu i wciąż trwa. Z przyjemnością przedstawiamy tłumaczenie niedawnego artykułu inżyniera SRE GitLab na temat tego, jak to przebiega i jakie wnioski wyciągają inżynierowie zaangażowani w projekt.

Nasze wnioski po roku migracji GitLab.com na Kubernetes

Od około roku nasz dział infrastruktury zajmuje się migracją wszystkich usług działających na GitLab.com do Kubernetes. W tym czasie napotkaliśmy problemy związane nie tylko z przenoszeniem usług do Kubernetes, ale także z zarządzaniem hybrydowym wdrożeniem podczas przejścia. O cennych lekcjach, które zdobyliśmy, mowa będzie w tym artykule.

Od samego początku GitLab.com jego serwery działały w chmurze na maszynach wirtualnych. Tym maszynami zarządza Chef, a ich instalacja odbywa się za pomocą naszego oficjalnego pakietu Linux. Strategia wdrażania na wypadek, gdyby trzeba było zaktualizować aplikację, polega na prostym aktualizowaniu parku serwerów w skoordynowany sposób sekwencyjnie przy pomocy CI-pipeline. Metoda ta — choć wolna i nieco nudna — gwarantuje, że GitLab.com stosuje te same metody instalacji i konfiguracji, co użytkownicy wersji autonomicznych (self-managed) instalacji GitLab, którzy używają naszych pakietów Linux.

Używamy tej metody, ponieważ niezwykle ważne jest, aby doświadczyć wszystkich smutków i radości, które przeżywają członkowie społeczności, gdy instalują i konfigurowują własne kopie GitLab. Podejście to dobrze sprawdzało się przez pewien czas, jednak gdy liczba projektów na GitLab przekroczyła 10 milionów, zrozumieliśmy, że nie spełnia już naszych potrzeb w zakresie skalowania i wdrażania.

Pierwsze kroki w kierunku Kubernetes i cloud-native GitLab

W 2017 roku powstał projekt GitLab Charts Aby przygotować GitLab do wdrożenia w chmurze oraz umożliwić użytkownikom instalację GitLab w klastrach Kubernetes, wiedzieliśmy, że przeniesienie GitLab do Kubernetes zwiększy możliwości skalowania platformy SaaS, uprości wdrożenia i poprawi efektywność wykorzystania zasobów obliczeniowych. Jednocześnie wiele funkcji naszej aplikacji zależało od zamontowanych podziałów NFS, co spowolniło przejście z maszyn wirtualnych.

Dążenie do cloud native i Kubernetes umożliwiło naszym inżynierom zaplanowanie stopniowego przejścia, w trakcie którego zrezygnowaliśmy z niektórych zależności aplikacji od sieciowych magazynów, równocześnie kontynuując rozwój nowych funkcji. Od momentu, kiedy zaczęliśmy planować migrację latem 2019 roku, wiele z tych ograniczeń zostało usuniętych, a proces przenoszenia GitLab.com na Kubernetes teraz idzie pełną parą!

Funkcje działania GitLab.com w Kubernetes

Dla GitLab.com używamy jednego regionalnego klastra GKE, który obsługuje cały ruch aplikacji. Aby zminimalizować złożoność (już i tak skomplikowanej) migracji, skupiamy się na usługach, które nie zależą od lokalnego magazynu lub NFS. GitLab.com w głównej mierze opiera się na monolitycznej bazie kodu napisanej w Rails, a my kierujemy ruch w zależności od charakterystyki obciążenia na różne punkty końcowe, izolowane w swoich własnych pulach węzłów.

W przypadku frontendu te typy dzielą się na zapytania webowe, API, Git SSH/HTTPS oraz Registry. W przypadku backendu dzielimy zadania w kolejkach według różnych charakterystyk w zależności od z góry określonych granic zasobów, które pozwalają nam ustalać docelowe wskaźniki poziomu usług (Service-Level Objectives, SLO) dla różnych obciążeń.

Wszystkie te usługi GitLab.com są skonfigurowane za pomocą niemodyfikowanego chartu Helm GitLab. Konfiguracja odbywa się w subchartach, które mogą być selektywnie włączane w miarę, jak stopniowo przenosimy usługi do klastra. Nawet biorąc pod uwagę, że zdecydowano się nie włączać do migracji niektórych naszych stateful usług, takich jak Redis, Postgres, GitLab Pages i Gitaly, użycie Kubernetes pozwala znacznie zmniejszyć liczbę maszyn wirtualnych, którymi obecnie zarządza Chef.

Przezroczystość i zarządzanie konfiguracją Kubernetes

Wszystkie ustawienia są zarządzane przez sam GitLab. W tym celu wykorzystuje się trzy projekty konfiguracyjne oparte na Terraformie i Helm. Staramy się wszędzie tam, gdzie to możliwe, używać samego GitLaba do uruchamiania GitLaba, ale do zadań operacyjnych mamy działającą osobną instancję GitLab. Jest ona potrzebna, aby nie być zależnym od dostępności GitLab.com podczas przeprowadzania wdrożeń i aktualizacji GitLab.com.

Chociaż nasze pipeline'y dla klastra Kubernetes działają na osobnej instancji GitLab, repozytoria kodu mają swoje lustra, publicznie dostępne pod następującymi adresami:

  • k8s-workloads/gitlab-com — konfiguracja GitLab.com dla wykresu Helm;
  • k8s-workloads/gitlab-helmfiles — zawiera konfiguracje dla usług, które nie są bezpośrednio związane z aplikacją GitLab. Obejmuje to konfiguracje do logowania i monitorowania klastra, a także dla zintegrowanych narzędzi, takich jak PlantUML;
  • Gitlab-com-infrastructure — konfiguracja Terraform dla Kubernetes i starej (legacy) infrastruktury VM. Tutaj konfiguruje się wszystkie zasoby potrzebne do uruchomienia klastra, w tym sam klaster, pule węzłów, konta usług, rezerwację adresów IP.

Nasze wnioski po roku migracji GitLab.com na Kubernetes
Przy wprowadzaniu zmian pokazuje się ogólnodostępne krótkie streszczenie z odsyłaczem do szczegółowego diffu, który SRE analizuje przed wprowadzeniem zmian w klastrze.

Dla SRE link prowadzi do szczegółowego diffu w instancji GitLab, która jest używana do eksploatacji i do której dostęp jest ograniczony. To pozwala pracownikom i społeczności bez dostępu do projektu eksploatacyjnego (który jest otwarty tylko dla SRE) przeglądać proponowane zmiany w konfiguracji. Łącząc ogólnodostępną instancję GitLaba dla kodu z zamkniętą instancją do pipeline'ów CI, zachowujemy jednolity przepływ pracy, jednocześnie zapewniając niezależność od GitLab.com podczas aktualizacji konfiguracji.

Czego dowiedzieliśmy się podczas migracji

Podczas przeprowadzki zdobyliśmy doświadczenie, które stosujemy do nowych migracji i wdrożeń w Kubernetes.

1. Wzrost kosztów z powodu ruchu między strefami dostępności

Nasze wnioski po roku migracji GitLab.com na Kubernetes
Codzienna statystyka egress (bajty na dobę) dla zbioru repozytoriów Git na GitLab.com

Google dzieli swoją sieć na regiony. Te z kolei dzielą się na strefy dostępności (AZ). Git hosting wiąże się z dużymi ilościami danych, dlatego ważne jest dla nas kontrolowanie przepływu danych wychodzących. W przypadku ruchu wewnętrznego przepływ danych wychodzących jest bezpłatny tylko wtedy, gdy pozostaje w granicach jednej strefy dostępności. W momencie pisania tego artykułu przekazujemy około 100 TB danych w typowy dzień roboczy (i to tylko dla repozytoriów Git). Usługi, które w naszej starej topologii opartej na VM były na tych samych maszynach wirtualnych, teraz działają w różnych podach Kubernetes. Oznacza to, że część ruchu, która wcześniej była lokalna dla VM, może potencjalnie wychodzić poza strefy dostępności.

Regionalne klastry GKE pozwalają na objęcie kilku stref dostępności dla zapewnienia rezerwy. Rozważamy opcję podziału regionalnego klastra GKE na klastry jedno strefowe dla usług, które generują duże ilości ruchu. To pozwoli na obniżenie kosztów przepływu danych przy zachowaniu rezerwy na poziomie klastra.

2. Limity, żądania zasobów i skalowanie

Nasze wnioski po roku migracji GitLab.com na Kubernetes
Liczba replik obsługujących ruch produkcyjny na registry.gitlab.com. Ruch osiąga szczyt około 15:00 UTC.

Nasza historia migracji zaczęła się w sierpniu 2019 roku, kiedy przenieśliśmy pierwszą usługę – rejestr kontenerów GitLab (GitLab Container Registry) – do Kubernetes. Ta krytycznie ważna usługa o dużym ruchu idealnie nadawała się do pierwszej migracji, ponieważ jest aplikacją stateless z niewielką liczbą zależności zewnętrznych. Pierwszym problemem, z którym się spotkaliśmy, była duża liczba wyrzuconych podów z powodu braku pamięci na węzłach. Z tego powodu musieliśmy zmienić żądania i limity.

Okazało się, że w przypadku aplikacji, której zużycie pamięci rośnie w czasie, niskie wartości dla żądań (rezerwujących pamięć dla każdego poda) w połączeniu z "hojnie" ustawionym limitami użytkowania prowadziły do nasycenia (saturacji) węzłów i wysokiego poziomu wyrzucania. Aby poradzić sobie z tym problemem, postanowiono zwiększyć żądania i obniżyć limityTo było odciążenie węzłów i zapewniło cykl życia podów, który nie powodował zbyt dużego obciążenia węzła. Teraz zaczynamy migracje z hojnie (i prawie jednorodnie) określonymi wartościami requestów i limitów, dostosowując je w razie potrzeby.

3. Metryki i logi

Nasze wnioski po roku migracji GitLab.com na Kubernetes
Dział infrastrukturalny koncentruje się na opóźnieniach, procencie błędów i saturacji w stosunku do ustalonych celów poziomu usług (SLO), związanych z ogólną dostępnością naszego systemu.

Miniony rok był kluczowy dla działu infrastrukturalnego, z poprawą w monitorowaniu i zarządzaniu SLO. SLO pozwoliły nam ustalać cele dla poszczególnych usług, nad którymi uważnie czuwaliśmy w trakcie migracji. Jednak nawet z taką poprawioną obserwowalnością nie zawsze od razu widać problemy, korzystając z metryk i alertów. Na przykład, koncentrując się na opóźnieniach i procencie błędów, nie pokrywamy wszystkich scenariuszy użycia usługi, która przechodzi migrację.

Ten problem został zauważony niemal natychmiast po przeniesieniu części obciążeń do klastra. Szczególnie mocno dawał o sobie znać, gdy konieczne było sprawdzenie funkcji, dla których liczba zapytań jest niewielka, ale mają one bardzo specyficzne zależności konfiguracyjne. Jedną z kluczowych lekcji po migracji było, że w monitorowaniu należy uwzględniać nie tylko metryki, ale także logi i „długi ogon” (mowa o takim ich rozkładzie na wykresie — przyp. tłum.) błędów. Teraz dla każdej migracji włączamy szczegółowy wykaz zapytań do logów (log queries) i planujemy jasne procedury wycofania, które w przypadku problemów można przekazywać od jednej zmiany do kolejnej.

Równoległe obsługiwanie tych samych zapytań na starej infrastrukturze VM i nowej, opartej na Kubernetes, stanowiło unikalne wyzwanie. W odróżnieniu od migracji typu lift-and-shift (szybkie przeniesienie aplikacji „jak jest” do nowej infrastruktury; więcej informacji można znaleźć na przykład, tutaj — przyp. tłum.), równoległe działanie „starych” VM i Kubernetes wymaga, aby narzędzia monitorujące były zgodne z obu środowiskami i potrafiły łączyć metryki w jedną formę. Ważne jest, abyśmy używali tych samych paneli i zapytań do logów, aby osiągnąć spójną obserwowalność w czasie okresu przejściowego.

4. Przełączenie ruchu na nowy klaster

Dla GitLab.com część serwerów jest dedykowana etapie canary. Klaster canary obsługuje nasze wewnętrzne projekty, a także może być aktywowany przez użytkowników. Jednak przede wszystkim jest on przeznaczony do testowania zmian wprowadzanych w infrastrukturę i aplikację. Pierwsza przeniesiona usługa zaczęła od przyjmowania ograniczonej ilości wewnętrznego ruchu, a my nadal wykorzystujemy tę metodę, aby upewnić się, że spełniamy SLO zanim skierujemy cały ruch do klastra.

W przypadku migracji oznacza to, że najpierw zapytania do wewnętrznych projektów kierowane są do Kubernetes, a następnie stopniowo przełączamy resztę ruchu do klastra, zmieniając wagę dla backendu za pomocą HAProxy. W trakcie przejścia z VM na Kubernetes stało się jasne, że bardzo korzystne jest posiadanie prostego sposobu na przekierowywanie ruchu między starą a nową infrastrukturą oraz odpowiednio przygotowanie starej infrastruktury na przypadek rollbacku w pierwszych dniach po migracji.

5. Rezerwowe zasoby pod’ów i ich wykorzystanie

Prawie od razu zidentyfikowano następujący problem: pod’y dla usługi Registry uruchamiały się szybko, jednak uruchamianie pod’ów dla Sidekiq zajmowało do dwóch minut. Długotrwałe uruchamianie pod’ów dla Sidekiq stało się problemem, gdy przystąpiliśmy do migracji obciążeń roboczych dla workerów w Kubernetes, które muszą szybko przetwarzać zadania i szybko skalować.

W tym przypadku lekcja polegała na tym, że chociaż Horizontal Pod Autoscaler (HPA) w Kubernetes dobrze radzi sobie ze wzrostem ruchu, ważne jest, aby uwzględnić charakterystykę obciążeń roboczych i przydzielać rezerwowe zasoby pod’ów (szczególnie w warunkach nierównomiernego rozkładu popytu). W naszym przypadku zaobserwowano nagły wzrost zadań, co wiązało się z szybkim skalowaniem, co prowadziło do nasycenia zasobów CPU zanim zdążyliśmy skalować pulę węzłów.

Zawsze istnieje pokusa, aby jak najwięcej „wycisnąć” z klastra, jednak my, na początku borykając się z problemami z wydajnością, teraz zaczynamy z hojny budżetem pod i później go redukujemy, uważnie śledząc SLO. Uruchamianie podów dla usługi Sidekiq znacznie się przyspieszyło i teraz średnio zajmuje około 40 sekund. Zredukowanie czasu uruchamiania podów zyskał zarówno GitLab.com, jak i nasi użytkownicy instalacji self-managed, korzystający z oficjalnego Helm-charta GitLab.

Podsumowanie

Po przeniesieniu każdej usługi cieszyliśmy się z korzyści płynących z wykorzystania Kubernetes w produkcji: szybsze i bezpieczniejsze wdrażanie aplikacji, skalowanie oraz bardziej efektywne rozdysponowanie zasobów. Przy tym zalety migracji wykraczają poza usługę GitLab.com. Z każdej poprawy oficjalnego Helm-charta korzystają również jego użytkownicy.

Mam nadzieję, że spodobała się Wam historia naszych przygód z migracją do Kubernetes. Wciąż przenosimy nowe usługi do klastra. Dodatkowe informacje można znaleźć w następujących publikacjach:

P.S. od tłumacza

Przeczytaj także na naszym blogu:

Ź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