Obrazy gotowe do produkcji dla K8s

Ta historia dotyczy tego, jak używamy kontenerów w środowisku produkcyjnym, w szczególności Kubernetes. Artykuł poświęcony jest zbieraniu metryk i logów z kontenerów, a także budowaniu obrazów.

Obrazy gotowe do produkcji dla K8s

Jesteśmy z firmy fintech Exness, która rozwija usługi handlu online i produkty fintech dla B2B i B2C. Nasz dział badawczo-rozwojowy ma wiele różnych zespołów, dział rozwoju zatrudnia ponad 100 pracowników.

Reprezentujemy zespół odpowiedzialny za platformę dla naszych programistów do gromadzenia i uruchamiania kodu. W szczególności jesteśmy odpowiedzialni za gromadzenie, przechowywanie i raportowanie metryk, logów i zdarzeń z aplikacji. Obecnie obsługujemy około trzech tysięcy kontenerów Docker w środowisku produkcyjnym, utrzymujemy naszą pamięć masową Big Data o pojemności 50 TB i zapewniamy rozwiązania architektoniczne zbudowane wokół naszej infrastruktury: Kubernetes, Rancher i różnych dostawców chmury publicznej. 

Nasza motywacja

Co się pali? Nikt nie może odpowiedzieć. Gdzie jest palenisko? Trudno to zrozumieć. Kiedy się zapalił? Można się tego dowiedzieć, ale nie od razu. 

Obrazy gotowe do produkcji dla K8s

Dlaczego niektóre kontenery stoją, a inne upadły? Który kontener był winien? W końcu pojemniki z zewnątrz są takie same, ale w środku każdy z nich ma swojego Neo.

Obrazy gotowe do produkcji dla K8s

Nasi programiści to kompetentni ludzie. Wykonują dobre usługi, które przynoszą zysk firmie. Ale zdarzają się awarie, gdy kontenery z aplikacjami gubią się. Jeden kontener zużywa za dużo procesora, inny sieci, trzeci operacji we/wy, a czwarty jest całkowicie niejasny, co robi z gniazdami. Wszystko upada, a statek tonie. 

Agenci

Aby zrozumieć, co dzieje się w środku, postanowiliśmy umieścić agentów bezpośrednio w kontenerach.

Obrazy gotowe do produkcji dla K8s

Agenci ci to programy ograniczające, które utrzymują kontenery w takim stanie, aby się nie stłukły. Agenci są ujednoliceni, co pozwala na ujednolicone podejście do obsługi kontenerów. 

W naszym przypadku agenci muszą dostarczać logi w standardowym formacie, otagowane i ograniczone. Powinny także zapewniać nam ustandaryzowane wskaźniki, które można rozszerzyć z punktu widzenia aplikacji biznesowej.

Agenci oznaczają także narzędzia do obsługi i konserwacji, które mogą pracować w różnych systemach orkiestracji obsługujących różne obrazy (Debian, Alpine, Centos itp.).

Wreszcie agenci muszą obsługiwać proste CI/CD zawierające pliki Dockera. W przeciwnym razie statek się rozpadnie, bo kontenery zaczną być dostarczane po „krzywych” szynach.

Zbuduj proces i docelowe urządzenie obrazu

Aby wszystko było ujednolicone i łatwe w zarządzaniu, należy przestrzegać pewnego standardowego procesu kompilacji. Dlatego zdecydowaliśmy się zbierać kontenery po kontenerach - to jest rekurencja.

Obrazy gotowe do produkcji dla K8s

Tutaj pojemniki są reprezentowane przez pełne kontury. Jednocześnie postanowili umieścić w nich zestawy dystrybucyjne, aby „życie nie wyglądało jak maliny”. Dlaczego tak zrobiono, wyjaśnimy poniżej.
 
Rezultatem jest narzędzie do kompilacji — kontener specyficzny dla wersji, który odwołuje się do określonych wersji dystrybucji i określonych wersji skryptów.

Jak tego używamy? Mamy Docker Hub, który zawiera kontener. Odzwierciedlamy to w naszym systemie, aby pozbyć się zewnętrznych zależności. Rezultatem jest pojemnik oznaczony na żółto. Tworzymy szablon, aby zainstalować w kontenerze wszystkie potrzebne dystrybucje i skrypty. Następnie składamy gotowy do użycia obraz: programiści umieszczają w nim kod i niektóre własne specjalne zależności. 

Co jest dobrego w tym podejściu? 

  • Po pierwsze, pełna kontrola wersji narzędzi do kompilacji - kompilacja kontenerów, wersji skryptowych i dystrybucyjnych. 
  • Po drugie, osiągnęliśmy standaryzację: w ten sam sposób tworzymy szablony, obraz pośredni i gotowy do użycia. 
  • Po trzecie, kontenery zapewniają nam przenośność. Dziś korzystamy z Gitlaba, a jutro przeskoczymy na TeamCity lub Jenkins i będziemy mogli w ten sam sposób uruchamiać nasze kontenery. 
  • Po czwarte, minimalizowanie zależności. To nie przypadek, że w kontenerze umieściliśmy pakiety dystrybucyjne, ponieważ pozwala nam to uniknąć każdorazowego pobierania ich z Internetu. 
  • Po piąte, wzrosła szybkość kompilacji - obecność lokalnych kopii obrazów pozwala uniknąć marnowania czasu na pobieranie, ponieważ istnieje obraz lokalny. 

Inaczej mówiąc, uzyskaliśmy kontrolowany i elastyczny proces montażu. Używamy tych samych narzędzi do budowania dowolnych w pełni wersjonowanych kontenerów. 

Jak działa nasza procedura kompilacji

Obrazy gotowe do produkcji dla K8s

Montaż uruchamia się jednym poleceniem, proces przebiega na obrazku (zaznaczony na czerwono). Deweloper ma plik Dockera (zaznaczony na żółto), renderujemy go, zastępując zmienne wartościami. Po drodze dodajemy nagłówki i stopki - to są nasi agenci. 

Nagłówek dodaje dystrybucje z odpowiednich obrazów. A stopka instaluje nasze usługi w środku, konfiguruje uruchomienie obciążenia, rejestrowania i innych agentów, zastępuje punkt wejścia itp. 

Obrazy gotowe do produkcji dla K8s

Długo zastanawialiśmy się, czy zainstalować nadzorcę. W końcu zdecydowaliśmy, że go potrzebujemy. Wybraliśmy S6. Opiekun zapewnia zarządzanie kontenerem: umożliwia połączenie się z nim w przypadku awarii głównego procesu oraz zapewnia ręczne zarządzanie kontenerem bez jego odtwarzania. Dzienniki i metryki to procesy działające w kontenerze. Ich też trzeba jakoś kontrolować, a my robimy to przy pomocy przełożonego. Wreszcie S6 zajmuje się sprzątaniem, przetwarzaniem sygnałów i innymi zadaniami.

Ponieważ używamy różnych systemów orkiestracji, po zbudowaniu i uruchomieniu kontener musi zrozumieć, w jakim środowisku się znajduje i działać odpowiednio do sytuacji. Na przykład:
Dzięki temu możemy zbudować jeden obraz i uruchomić go w różnych systemach orkiestracji, a zostanie on uruchomiony z uwzględnieniem specyfiki tego systemu orkiestracji.

 Obrazy gotowe do produkcji dla K8s

Dla tego samego kontenera otrzymujemy różne drzewa procesów w Dockerze i Kubernetesie:

Obrazy gotowe do produkcji dla K8s

Ładunek jest wykonywany pod nadzorem S6. Zwróć uwagę na kolektory i zdarzenia - to nasi agenci odpowiedzialni za logi i metryki. Kubernetes ich nie ma, ale Docker tak. Dlaczego? 

Jeśli spojrzymy na specyfikację „podu” (zwanego dalej – Kubernetes podem), to zobaczymy, że kontener zdarzeń jest wykonywany w podu, który posiada wydzielony kontener kolektora, pełniący funkcję gromadzenia metryk i logów. Możemy wykorzystać możliwości Kubernetesa: uruchamianie kontenerów w jednym pod, w jednym procesie i/lub przestrzeni sieciowej. Właściwie przedstaw swoich agentów i wykonaj pewne funkcje. A jeśli ten sam kontener zostanie uruchomiony w Dockerze, otrzyma te same możliwości co dane wyjściowe, to znaczy będzie w stanie dostarczać logi i metryki, ponieważ agenci zostaną uruchomieni wewnętrznie. 

Metryki i dzienniki

Dostarczanie metryk i dzienników jest złożonym zadaniem. Jej decyzja ma kilka aspektów.
Infrastruktura tworzona jest do realizacji ładunku, a nie do masowego dostarczania kłód. Oznacza to, że proces ten należy wykonać przy minimalnych wymaganiach dotyczących zasobów kontenera. Staramy się pomagać naszym programistom: „Zdobądź kontener Docker Hub, uruchom go, a my dostarczymy logi”. 

Drugim aspektem jest ograniczenie objętości kłód. Jeżeli w kilku kontenerach wystąpi gwałtowny wzrost ilości logów (aplikacja wyprowadza w pętli ślad stosu), obciążenie procesora, kanałów komunikacyjnych i systemu przetwarzania logów wzrasta, co wpływa na działanie hosta jako całe i inne pojemniki na gospodarzu, czasami prowadzi to do „upadku” hosta. 

Trzeci aspekt polega na tym, że od razu po wyjęciu z pudełka konieczna jest obsługa jak największej liczby metod gromadzenia metryk. Od odczytywania plików i odpytywania punktu końcowego Prometheusa po używanie protokołów specyficznych dla aplikacji.

Ostatnim aspektem jest minimalizacja zużycia zasobów.

Wybraliśmy rozwiązanie Go typu open source o nazwie Telegraf. Jest to złącze uniwersalne, które obsługuje ponad 140 typów kanałów wejściowych (wtyczek wejściowych) i 30 typów kanałów wyjściowych (wtyczek wyjściowych). Sfinalizowaliśmy to i teraz powiemy Ci, jak z niego korzystamy na przykładzie Kubernetesa. 

Obrazy gotowe do produkcji dla K8s

Załóżmy, że programista wdraża obciążenie, a Kubernetes otrzymuje żądanie utworzenia zasobnika. W tym momencie dla każdego poda automatycznie tworzony jest kontener o nazwie Collector (używamy webhooka mutacyjnego). Kolekcjoner jest naszym agentem. Kontener ten na początku konfiguruje się do współpracy z Prometheusem i systemem gromadzenia logów.

  • W tym celu używa adnotacji podów i w zależności od ich zawartości tworzy, powiedzmy, punkt końcowy Prometheusa; 
  • Na podstawie specyfikacji poda i konkretnych ustawień kontenera decyduje, w jaki sposób dostarczać logi.

Zbieramy dzienniki za pośrednictwem interfejsu Docker API: programiści muszą po prostu umieścić je na stdout lub stderr, a Collector to rozwiąże. Dzienniki są gromadzone fragmentami z pewnym opóźnieniem, aby zapobiec możliwemu przeciążeniu hosta. 

Metryki są gromadzone między wystąpieniami obciążenia (procesami) w kontenerach. Wszystko jest tagowane: przestrzeń nazw, under i tak dalej, a następnie konwertowane do formatu Prometheus - i staje się dostępne do gromadzenia (z wyjątkiem dzienników). Wysyłamy również logi, metryki i zdarzenia do Kafki i dalej:

  • Logi są dostępne w Graylog (do analizy wizualnej);
  • Dzienniki, metryki i zdarzenia są wysyłane do Clickhouse w celu długoterminowego przechowywania.

Wszystko działa dokładnie tak samo w AWS, tyle że Graylog zastępujemy Kafką z Cloudwatch. Wysyłamy tam logi i wszystko okazuje się bardzo wygodne: od razu wiadomo, do którego klastra i kontenera należą. To samo dotyczy Google Stackdriver. Oznacza to, że nasz schemat działa zarówno lokalnie z Kafką, jak i w chmurze. 

Jeśli nie mamy Kubernetesa z podami, schemat jest nieco bardziej skomplikowany, ale działa na tych samych zasadach.

Obrazy gotowe do produkcji dla K8s

Te same procesy są wykonywane wewnątrz kontenera, są one koordynowane przy użyciu S6. Wszystkie te same procesy działają w tym samym kontenerze.

W efekcie,

Stworzyliśmy kompletne rozwiązanie do budowania i uruchamiania obrazów, z opcjami gromadzenia i dostarczania logów i metryk:

  • Wypracowaliśmy ustandaryzowane podejście do składania obrazów i na jego podstawie opracowaliśmy szablony CI;
  • Agenci zbierający dane to nasze rozszerzenia Telegraf. Dobrze przetestowaliśmy je w produkcji;
  • Używamy webhooka mutacyjnego do implementowania kontenerów z agentami w podach; 
  • Zintegrowany z ekosystemem Kubernetes/Rancher;
  • Możemy wykonać te same kontenery w różnych systemach orkiestracji i uzyskać efekt, jakiego oczekujemy;
  • Utworzono całkowicie dynamiczną konfigurację zarządzania kontenerami. 

Współautor: Ilia Prudnikow

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

Dodaj komentarz