Nasza realizacja Continuous Deployment na platformie klienta

W True Engineering skonfigurowaliśmy proces ciągłego dostarczania aktualizacji na serwery klientów i chcemy podzielić się tym doświadczeniem.

Na początek opracowaliśmy system online dla klienta i wdrożyliśmy go w własnym klastrze Kubernetes. Teraz nasze wydajne rozwiązanie przeniosło się na platformę klienta, dla czego skonfigurowaliśmy w pełni automatyczny proces Continuous Deployment. Dzięki temu przyspieszyliśmy time-to-market – dostarczanie zmian do środowiska produkcyjnego.

W tym artykule opowiemy o wszystkich etapach procesu Continuous Deployment (CD) lub dostarczania aktualizacji na platformę klienta:

  1. jak zaczyna się ten proces,
  2. synchronizacja z repozytorium Git klienta,
  3. kompilacja backendu i frontend
  4. automatyczne wdrożenie aplikacji w środowisku testowym,
  5. automatyczne wdrożenie na Prod.

W trakcie podzielimy się szczegółami konfiguracji.

Nasza realizacja Continuous Deployment na platformie klienta

1. Start CD

Ciągłe dostarczanie zaczyna się od momentu, gdy programista umieszcza zmiany w gałęzi wydaniowej naszego repozytorium Git.

Nasza aplikacja działa na bazie architektury mikrousługowej i wszystkie jej komponenty są przechowywane w jednym repozytorium. Dzięki temu wszystkie mikrousługi są zbierane i instalowane, nawet jeśli zmienił się jeden z nich.

Zorganizowaliśmy pracę przez jedno repozytorium z kilku powodów:

  • Wygoda rozwoju — aplikacja rozwija się aktywnie, więc można pracować od razu z całym kodem.
  • Jednolity pipeline CI/CD, który gwarantuje, że aplikacja jako jednolita całość przechodzi przez wszystkie testy i dostarczana jest do środowiska prod klienta.
  • Wykluczamy zamieszanie w wersjach — nie musimy przechowywać mapy wersji mikrousług i opisywać dla każdej mikrousługi jej konfiguracji w skryptach Helm.

2. Synchronizacja z repozytorium Git kodu źródłowego klienta

Wprowadzone zmiany są automatycznie synchronizowane z repozytorium Git klienta. Tam skonfigurowano kompilację aplikacji, która uruchamia się po aktualizacji gałęzi, oraz wdrożenie na produkcję. Oba procesy odbywają się w ich środowisku z repozytorium Git.

Nie możemy pracować z repozytorium klienta bezpośrednio, ponieważ potrzebujemy własnych środowisk do rozwoju i testowania. Używamy do tych celów naszego repozytorium Git – jest on zsynchronizowany z ich repozytorium Git. Gdy tylko programista publikuje zmiany w odpowiedniej gałęzi naszego repozytorium, GitLab natychmiast przesyła te zmiany do klienta.

Nasza realizacja Continuous Deployment na platformie klienta

Następnie trzeba wykonać kompilację. Składa się ona z kilku etapów: kompilacji backendu i frontendu, testowania i dostarczenia do produkcji.

3. Kompilacja backendu i frontendu

Kompilacja backendu i frontendu to dwa równoległe zadania, które są realizowane w systemie GitLab Runner. Jej konfiguracja początkowej kompilacji znajduje się w tym samym repozytorium.

Tutorial dotyczący pisania skryptu YAML do kompilacji w GitLab.

GitLab Runner pobiera kod z odpowiedniego repozytorium, za pomocą polecenia kompilacji aplikacji Java przeprowadza kompilację i wysyła go do rejestru Docker. Tutaj kompilujemy backend i frontend, uzyskujemy obrazy Docker, które przechowujemy w repozytorium po stronie klienta. Do zarządzania obrazami Docker używamy wtyczki Gradle.

Synchronizujemy wersje naszych obrazów z wersją wydania, które zostanie opublikowane w Docker. Aby wszystko działało płynnie, wprowadziliśmy kilka ustawień:

1. Pomiędzy środowiskiem testowym a produkcyjnym kontenery nie są ponownie kompilowane. Zastosowaliśmy parametryzację, aby ten sam kontener mógł działać bez ponownej kompilacji we wszystkich ustawieniach, zmiennych środowiskowych i usługach zarówno w środowisku testowym, jak i na produkcji.

2. Aby zaktualizować aplikację za pomocą Helm, należy podać jej wersję. Mamy kompilację backendu, frontend i aktualizację aplikacji – to trzy różne zadania, dlatego ważne jest, aby wszędzie używać tej samej wersji aplikacji. Do tego zadania wykorzystujemy dane z historii Git, ponieważ nasza konfiguracja klastra K8S i aplikacji znajduje się w jednym repozytorium Git.

Wersję aplikacji uzyskujemy z wyników wykonania polecenia
git describe --tags --abbrev=7.

4. Automatyczne wdrażanie wszystkich zmian w środowisku testowym (UAT)

Kolejnym etapem w tym skrypcie kompilacji jest automatyczna aktualizacja klastra K8S. Dzieje się to pod warunkiem, że cała aplikacja została skompilowana, a wszystkie artefakty zostały opublikowane w Docker Registry. Po tym rozpoczyna się aktualizacja środowiska testowego.

Aktualizacja klastra uruchamiana jest za pomocą Aktualizacja Helma. Jeśli coś poszło nie tak, Helm automatycznie i samodzielnie cofną wszystkie swoje zmiany. Nie trzeba go kontrolować.

Dostarczamy razem z buildującą konfigurację klastra K8S. Dlatego następnym krokiem jest aktualizacja jej: configMaps, deploymenty, usługi, sekrety i wszelkie inne konfiguracje K8S, które zmieniliśmy.

Po tym Helm uruchamia aktualizację RollOut samej aplikacji w środowisku testowym. Zanim aplikacja zostanie wdrożona na produkcję. Zrobiono to, aby użytkownicy ręcznie sprawdzili funkcje biznesowe, które udostępniliśmy w środowisku testowym.

5. Automatyczne wdrażanie wszystkich zmian na produkcję

Aby wdrożyć aktualizację w środowisku produkcyjnym, wystarczy nacisnąć jeden przycisk w GitLab — a kontenery zostaną natychmiast dostarczone do środowiska produkcyjnego.

Ta sama aplikacja może działać w różnych środowiskach — testowym i produkcyjnym — bez rebuildingu. Używamy tych samych artefaktów, nie zmieniając nic w aplikacji, a parametry definiujemy z zewnątrz.

Elastyczne parametryzowanie ustawień aplikacji zależy od tego, w jakim środowisku ta aplikacja będzie działać. Wszystkie ustawienia środowisk przenieśliśmy na zewnątrz: wszystko parametryzowane jest przez konfigurację K8S i parametry Helma. Gdy Helm wdraża wersję w środowisku testowym, stosowane są testowe parametry, a w środowisku produkcyjnym — parametry produkcyjne.

Najtrudniejsze było parametryzowanie wszystkich używanych usług i zmiennych, które zależą od środowiska, i przekształcenie ich w zmienne środowiskowe oraz opis-konfigurację parametrów środowiskowych dla Helma.

W parametrach aplikacji używane są zmienne środowiskowe. Ich wartości są ustawiane w kontenerach za pomocą K8S configmap, która jest szablonowana przy użyciu szablonów Go. Na przykład, ustawienie zmiennej środowiskowej dla nazwy domeny można zrobić tak:

APP_EXTERNAL_DOMAIN: {{ (pluck .Values.global.env .Values.app.properties.app_external_domain | first) }}

.Values.global.env – w tej zmiennej przechowywana jest nazwa środowiska (prod, stage, UAT).
.Values.app.properties.app_external_domain – w tej zmiennej określamy w pliku .Values.yaml potrzebną domenę

Podczas aktualizacji aplikacji Helm tworzy plik configmap.yaml na podstawie szablonów i wypełnia wartość APP_EXTERNAL_DOMAIN odpowiednią wartością w zależności od środowiska, w którym uruchamiana jest aktualizacja aplikacji. Ta zmienna ustawiana jest już w kontenerze. Dostęp do niej ma aplikacja, co oznacza, że w każdym środowisku aplikacji ta zmienna będzie miała inną wartość.

W stosunkowo niedawnym czasie w Spring Cloud pojawiło się wsparcie dla K8S, w tym praca z configMaps: Spring Cloud Kubernetes. Obecnie projekt jest intensywnie rozwijany i znacznie się zmienia, więc nie możemy go używać w produkcji. Jednak aktywnie monitorujemy jego stan i używamy go w konfiguracjach DEV. Gdy tylko stanie się stabilny — przejdziemy z użycia zmiennych środowiskowych na niego.

Podsumowując

Zatem, Continuous Deployment jest skonfigurowany i działa. Wszystkie aktualizacje odbywają się za jednym naciśnięciem przycisku. Dostarczanie zmian do środowiska produkcyjnego jest automatyczne. I co ważne, aktualizacje nie zatrzymują pracy systemu.

Nasza realizacja Continuous Deployment na platformie klienta

Plany na przyszłość: automatyczna migracja bazy

Zastanawialiśmy się nad aktualizacją bazy i możliwością jej cofnięcia. Przecież jednocześnie działają dwie różne wersje aplikacji: stara działa, a nowa się podnosi. A starą wyłączymy dopiero wtedy, gdy upewnimy się, że nowa wersja działa. Migracja bazy musi pozwalać na pracę z obiema wersjami aplikacji.

Dlatego nie możemy po prostu zmienić nazwy kolumny ani innych danych. Możemy jednak stworzyć nową kolumnę, skopiować do niej dane ze starej kolumny i napisać wyzwalacze, które przy aktualizacji danych jednocześnie będą je kopiować i aktualizować w innej kolumnie. A po udanym wdrożeniu nowej wersji aplikacji, po okresie wsparcia po uruchomieniu, będziemy mogli usunąć starą kolumnę i zbędny wyzwalacz.

Jeśli nowa wersja aplikacji działa nieprawidłowo, możemy cofnąć się do wcześniejszej wersji, w tym wcześniejszej wersji bazy. Innymi słowy, nasze zmiany pozwolą na jednoczesną pracę z wieloma wersjami aplikacji.

Planujemy zautomatyzować migrację bazy za pomocą zadania K8S, włączając ją do procesu CD. I na pewno podzielimy się tym doświadczeniem na Habrze.

Ź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