Urządzenie Helm i jego pułapki

Urządzenie Helm i jego pułapki
Koncept transportowca Typhon, Anton Swanepoel

Nazywam się Dmitrij Sugrobow, jestem programistą w „Leroy Merlin”. W artykule opowiem, po co potrzebny jest Helm, jak upraszcza pracę z Kubernetes, co się zmieniło w trzeciej wersji i jak za jego pomocą aktualizować aplikacje w produkcji bez przestojów.

To jest streszczenie na podstawie wystąpienia na konferencji @Kubernetes Conference by Mail.ru Cloud Solutions — jeśli nie chcesz czytać, obejrzyj wideo.

Odtwarzaj wideo

Dlaczego używamy Kubernetes w produkcji

„Leroy Merlin” jest liderem na rynku DIY w Rosji i Europie. W naszej firmie pracuje ponad stu programistów, 33 000 pracowników i ogromna liczba osób odwiedzających hipermarkety i stronę internetową. Aby uszczęśliwić wszystkich, postanowiliśmy stosować standardowe podejścia w branży. Tworzyć nowe aplikacje, korzystając z architektury mikrousługowej; aby izolować środowiska i zapewnić właściwą dostawę, stosować kontenery; a do orkiestracji używać Kubernetes. Koszt korzystania z orkiestratorów szybko maleje: na rynku przybywa inżynierów znających tę technologię, pojawiają się dostawcy oferujący Kubernetes jako usługę.

Wszystko, co robi Kubernetes, można oczywiście osiągnąć innymi metodami, na przykład używając Jenkins i docker-compose, ale po co utrudniać sobie życie, jeśli jest gotowe i niezawodne rozwiązanie? Dlatego zdecydowaliśmy się na Kubernetes i już od roku używamy go w produkcji. Obecnie mamy dwadzieścia cztery klastry Kubernetes, najstarszy z nich ma ponad rok, w nim jest około dwustu podów.

Przekleństwo dużych ilości plików YAML w Kubernetes

Aby uruchomić mikrousługę w Kubernetes, musimy stworzyć co najmniej pięć plików YAML: dla Deployment, Service, Ingress, ConfigMap, Secrets — i wysłać je do klastra. Dla następnej aplikacji napiszemy ten sam zestaw plików YAML, dla trzeciej — jeszcze jeden i tak dalej. Pomnóżmy liczbę dokumentów przez liczbę środowisk, już otrzymujemy setki plików, nie uwzględniając jeszcze dynamicznych środowisk.

Urządzenie Helm i jego pułapki
Adam Reese, główny opiekun Helm, wprowadził pojęcie „Cykl rozwoju w Kubernetes”, który wygląda tak:

  1. Copy YAML — skopiuj plik YAML.
  2. Paste YAML — wklej go.
  3. Fix Indents — popraw wcięcia.
  4. Repeat — powtórz.

Opcja działa, ale trzeba wiele razy kopiować pliki YAML. Aby zmienić ten cykl, wymyślono Helm.

Czym jest Helm

Po pierwsze, Helm — menedżer pakietów, pomagający znaleźć i zainstalować potrzebne programy. Aby zainstalować, na przykład, MongoDB nie trzeba wchodzić na oficjalną stronę i pobierać plików binarnych, wystarczy wykonać polecenie helm install stable/mongodb.

Po drugie, Helm — szablonowanie, pomaga parametryzować pliki. Wróćmy do sytuacji z plikami YAML w Kubernetes. Łatwiej jest napisać ten sam plik YAML, dodać do niego kilka placeholderów, w które Helm podstawia wartości. To znaczy, że zamiast dużego zestawu plików YAML będziemy mieli zestaw szablonów, w które w odpowiednim momencie zostaną podstawione potrzebne wartości.

Po trzecie, Helm — mistrz wdrożeń. Dzięki niemu można instalować, cofać i aktualizować aplikacje. Zobaczmy, jak to zrobić.

Urządzenie Helm i jego pułapki

Jak używać Helm do wdrażania własnych aplikacji

Zainstalujemy klienta Helm na komputerze, postępując zgodnie z oficjalną instrukcją. Następnie stworzymy zestaw plików YAML. Zamiast podawania konkretnych wartości zostawimy placeholdery, które w przyszłości Helm wypełni informacjami. Zestaw takich plików nazywa się Helm chart. Do klienta konsolowego Helm można go wysłać na trzy sposoby:

  • wskazać folder z szablonami;
  • zapakować w archiwum .tar i wskazać na nie;
  • dodać szablon do zdalnego repozytorium i dodać link do repozytorium w kliencie Helm.

Niezbędny jest także plik ze wartościami — values.yaml. Dane z niego będą podstawiane w szablon. Stwórzmy go również.

Urządzenie Helm i jego pułapki
W drugiej wersji Helm istnieje dodatkowa aplikacja serwerowa — Tiller. Działa na zewnątrz Kubernetes i czeka na żądania od klienta Helm, a po ich przyjęciu podstawia odpowiednie wartości w szablon i wysyła do Kubernetes.

Urządzenie Helm i jego pułapki
Helm 3 jest prostszy: zamiast przetwarzania szablonów na serwerze, informacje są teraz przetwarzane całkowicie po stronie klienta Helm i wysyłane bezpośrednio do API Kubernetes. To uproszczenie zwiększa bezpieczeństwo klastra i ułatwia proces wdrażania.

Jak to wszystko działa

Uruchamiamy polecenie helm install. Wskażemy nazwę wydania aplikacji, podamy ścieżkę do values.yaml. Na końcu wskażemy repozytorium, w którym znajduje się chart oraz jego nazwę. W tym przypadku to „lmru” i „bestchart” odpowiednio.

helm install --name bestapp --values values.yaml lmru/bestchart

Wykonanie polecenia jest możliwe tylko raz, przy powtórnym wykonaniu zamiast install trzeba użyć upgrade. Dla uproszczenia zamiast dwóch poleceń można wykonać polecenie upgrade z dodatkowym kluczem --install. Przy pierwszym uruchomieniu Helm wyśle polecenie do zainstalowania wydania, a następnie będzie je aktualizować.

helm upgrade --install bestapp --values values.yaml lmru/bestchart

Pułapki w deploymencie nowych wersji aplikacji z Helm

W tym momencie opowieści gram z salą w 'Kto chce zostać milionerem', i ustalamy, jak zmusić Helm do aktualizacji wersji aplikacji. Zobacz wideo.

Kiedy uczyłem się pracy z Helm, zaskoczyło mnie dziwne zachowanie podczas próby aktualizacji wersji uruchomionych aplikacji. Kod aplikacji został zaktualizowany, nowy obraz został załadowany do rejestru Dockera, wysłałem polecenie do wdrożenia – i nic się nie stało. Poniżej kilka nie do końca udanych sposobów aktualizacji aplikacji. Badając każdy z nich bardziej szczegółowo, zaczynasz rozumieć wewnętrzną strukturę narzędzia oraz przyczyny takiego nieoczywistego zachowania.

Sposób 1. Nie zmieniać informacji od ostatniego uruchomienia

Jak głosi oficjalnej strony Helm, 'Kubernetes chartry mogą być duże i skomplikowane, więc Helm stara się niczego nie zmieniać bez potrzeby'. Dlatego, jeśli zaktualizujesz najnowszą wersję obrazu aplikacji w rejestrze dockera i wykonasz polecenie helm upgrade, to nic się nie stanie. Helm będzie myślał, że nic się nie zmieniło i nie będzie potrzeby wysyłania w Kubernetes polecenia do aktualizacji aplikacji.

Tutaj i dalej tag latest pokazany jest wyłącznie jako przykład. Przy wskazywaniu tego tagu Kubernetes za każdym razem pobiera obraz z rejestru dockera, niezależnie od parametru imagePullPolicy. Używanie latest w produkcji jest niepożądane i powoduje efekty uboczne.

Sposób 2. Aktualizować LABEL w obrazie

Jak napisano w tym samym dokumentacji, 'Helm będzie aktualizować aplikację, tylko jeśli zmieniła się od ostatniego wydania'. Logicznym sposobem na to wydaje się aktualizacja etykiety LABEL w samym obrazie dockera. Jednak Helm nie zagląda do obrazów aplikacji i nie ma pojęcia o jakichkolwiek zmianach w nich. W związku z tym, przy aktualizacji etykiet w obrazie, Helm ich nie zauważy, a polecenie aktualizacji aplikacji w Kubernetes nie zostanie wysłane.

Sposób 3. Używać klucza --force

Urządzenie Helm i jego pułapki
Zwróćmy się do podręczników i poszukajmy odpowiedniego klucza. Najbardziej sensownym zdaje się klucz --force. Pomimo mówiącej nazwy, zachowanie różni się od oczekiwanego. Zamiast wymuszać aktualizację aplikacji, rzeczywistym przeznaczeniem jest przywrócenie wydania w statusie FAILED. Jeśli ten klucz nie jest używany, konieczne jest sequentialne wykonanie poleceń helm delete && helm install --replace. Zamiast tego proponuje się użycie klucza --force, który automatyzuje sekwencyjne wykonanie tych poleceń. Więcej informacji w tej prośbie pull. Aby poinformować Helm o konieczności zaktualizowania wersji aplikacji, niestety ten klucz się nie nadaje.

Sposób 4. Zmiana oznaczeń bezpośrednio w Kubernetes

Urządzenie Helm i jego pułapki
Aktualizacja etykiety bezpośrednio w klastrze za pomocą polecenia kubectl edit — to zły pomysł. Ta akcja doprowadzi do niespójności informacji pomiędzy działającą aplikacją a tym, co pierwotnie zostało wysłane na wdrożenie. Zachowanie Helma podczas wdrożenia w tym przypadku różni się od jego wersji: Helm 2 nic nie zrobi, a Helm 3 wyda nową wersję aplikacji. Aby zrozumieć przyczynę, należy zrozumieć, jak działa Helm.

Jak działa Helm

Aby określić, czy aplikacja zmieniła się od ostatniego wydania, Helm może skorzystać z:

  • działającej aplikacji w Kubernetes;
  • nowego pliku values.yaml i aktualnego wykresu;
  • wewnętrznych informacji Helma o wydaniach.

Dla najbardziej dociekliwych: gdzie Helm przechowuje wewnętrzne informacje o wydaniach?Wykonując polecenie helm history, otrzymamy wszystkie informacje o wersjach zainstalowanych za pomocą Helma.

Urządzenie Helm i jego pułapki
Dodatkowo dostępne są szczegółowe informacje o przesłanych szablonach i wartościach. Możemy je zapytać:

Urządzenie Helm i jego pułapki
W drugiej wersji Helma te informacje znajdują się w tym samym przestrzeni nazw, gdzie uruchomiony jest Tiller (domyślnie — kube-system), w ConfigMap oznaczonym etykietą „OWNER=TILLER”:

Urządzenie Helm i jego pułapki
W momencie pojawienia się trzeciej wersji Helma informacje przeniosły się do sekretów, w tym samym przestrzeni nazw, gdzie uruchomiona jest aplikacja. Dzięki temu stało się możliwe jednoczesne uruchamianie kilku aplikacji w różnych przestrzeniach nazw z identycznymi nazwami wydań. W drugiej wersji było to duży ból głowy, gdy przestrzenie nazw były izolowane, ale mogły na siebie wpływać.

Urządzenie Helm i jego pułapki

Drugi Helm, gdy próbuje określić, czy aktualizacja jest wymagana, korzysta tylko z dwóch źródeł informacji: tego, co zostało mu teraz dostarczone, oraz wewnętrznych informacji o wydaniach, które znajdują się w ConfigMap.

Urządzenie Helm i jego pułapki
Trzeci Helm używa strategii trójstronnego scalania: oprócz tej informacji bierze pod uwagę także aplikację, która działa obecnie w Kubernetes.

Urządzenie Helm i jego pułapki
Z tego powodu stara wersja Helma nie będzie nic robić, ponieważ nie uwzględnia informacji o aplikacji w klastrze, a Helm 3 otrzyma zmiany i wdroży nową aplikację.

Metoda 5. Użyj klucza —recreate-pods

Z pomocą klucza --recreate-pods można osiągnąć to, co pierwotnie planowano uzyskać za pomocą klucza --force. Kontenery zostaną ponownie uruchomione, a zgodnie z polityką imagePullPolicy: Always dla tagu latest (o tym w przypisie powyżej), Kubernetes pobierze i uruchomi nową wersję obrazu. Zrobi to w sposób niezbyt optymalny: bez uwzględnienia StrategyType wdrożenia, nagle wyłączy wszystkie stare instancje aplikacji i przystąpi do uruchamiania nowych. W czasie ponownego uruchamiania system nie będzie działał, użytkownicy będą cierpieć.

W samym Kubernetes podobny problem również istniał przez długi czas. I oto, cztery lata po zgłoszeniu Problemu, problem został rozwiązany, a począwszy od wersji 1.15 Kubernetes pojawiła się możliwość rolling-restart podów.

Helm po prostu wyłącza wszystkie aplikacje i uruchamia nowe kontenery obok. Na produkcji nie można tak robić, aby nie wywołać przestoju aplikacji. Takie coś można stosować tylko do celów deweloperskich, można to robić tylko w środowiskach stagingowych.

Jak zaktualizować wersję aplikacji za pomocą Helma?

Będziemy zmieniać wartości przekazywane do Helma. Zazwyczaj są to wartości używane w miejsce tagu obrazu. W przypadku latest, często używanego w środowiskach nieprodukcyjnych, zmienną informacją jest adnotacja, która dla samego Kubernetesa jest bezużyteczna, a dla Helma służy jako sygnał do konieczności aktualizacji aplikacji. Opcje wypełnienia wartości adnotacji:

  1. Losowa wartość z użyciem standardowej funkcji — {{ randAlphaNum 6 }}.
    Jest pewna kwestia: po każdym wdrożeniu z użyciem wykresu z taką zmienną wartość adnotacji będzie unikalna, a Helm będzie uważał, że zaszły zmiany. Oznacza to, że zawsze będziemy ponownie uruchamiać aplikację, nawet jeśli nie zmieniliśmy jej wersji. To nie jest krytyczne, ponieważ nie będzie przestoju, ale wciąż jest to nieprzyjemne.
  2. Wstawiać aktualną datę i czas{{ .Release.Date }}.
    Opcja ta przypomina losową wartość z ciągle unikalną zmienną.
  3. Bardziej właściwy sposób — użyć sumy kontrolne. To jest SHA obrazu lub SHA ostatniego commita w Gicie — {{ .Values.sha }}.
    Trzeba będzie je obliczyć i wysłać do klienta Helm po stronie wywołującej, na przykład w Jenkinsie. Jeśli aplikacja się zmieni, to również suma kontrolna się zmieni. W związku z tym, Helm zaktualizuje aplikację tylko wtedy, gdy zajdzie taka potrzeba.

Podsumujmy nasze próby

  • Helm wprowadza zmiany w sposób najmniej inwazyjny, więc jakakolwiek zmiana na poziomie obrazu aplikacji w Rejestrze Dockera nie spowoduje aktualizacji: po wykonaniu polecenia nic się nie stanie.
  • Klucz --force jest używany do przywracania problematycznych wydań i nie jest związany z wymuszonymi aktualizacjami.
  • Klucz --recreate-pods wymusi aktualizację aplikacji, ale zrobi to w brutalny sposób: nagle wyłączy wszystkie kontenery. Na tym ucierpią użytkownicy, w produkcji nie powinno się tak robić.
  • Nie wprowadzaj zmian w klastrze Kubernetes za pomocą polecenia kubectl edit nie należy: naruszymy spójność, a zachowanie będzie się różnić w zależności od wersji Helma.
  • Z wydaniem nowej wersji Helma pojawiło się wiele niuansów. Problemy w repozytorium Helma są opisane zrozumiałym językiem, pomogą zrozumieć szczegóły.
  • Dodanie zmiennej adnotacji do chartu uczyni go bardziej elastycznym. Umożliwi to prawidłowe wdrażanie aplikacji, bez przestojów.

Mądrość z kategorii „pokój na całym świecie”, działająca we wszystkich dziedzinach życia: czytaj instrukcję przed użyciem, a nie po. Tylko posiadając pełne informacje, można budować niezawodne systemy i uszczęśliwiać użytkowników.

Inne linki na ten temat:

  1. Wprowadzenie do Helm 3
  2. Oficjalna strona Helma
  3. Repozytorium Helma na GitHubie
  4. 25 przydatnych narzędzi Kubernetes: wdrożenie i zarządzanie

Ta prezentacja pierwszy raz została zaprezentowana na @Kubernetes Conference by Mail.ru Cloud Solutions. Zobacz wideo inne prezentacje i subskrybuj zapowiedzi wydarzeń w Telegramie Wokół Kubernetes w Mail.ru Group.

Ź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