CI/CD pipeline z użyciem Kubernetesa, AWS, Azure i .NET Core – Deploy na klaster testowy

Jest to następny wpis z serii CI/CD pipeline z użyciem Kubernetesa, AWS, Azure i .NET Core. Tym razem zepniemy cały flow z poprzednich wpisów i wdrożymy aplikację na klaster testowy.
Seria CI/CD pipeline z użyciem Kubernetesa, AWS, Azure i .NET Core:
- Stawianie klastra na AWS
- Helm 3.0 i ACR
- Dodawanie klastra w Octopus Deploy
- Deploy na klaster testowy
- Stawianie klastra na Azure oraz deploy
Przegląd architektury
Budowanie projektu w Azure Devops
Aplikację, którą będziemy wdrażać, można znaleźć tutaj. Jej jedyną funkcjonalnością jest wypisywanie zmiennych z “`appsettings.json“` na stronie głównej. Serwerem CI będzie Azure Devops. Proces tworzenia projektu i wyboru repozytorium w Azure Devops przechodziliśmy już w tym wpisie. Dodajmy do naszego pipeline kroki odtworzenia paczek nuget oraz budowania projektu:
trigger: - master pool: vmImage: 'ubuntu-latest' steps: - task: DotNetCoreCLI@2 inputs: command: 'restore' projects: 'k8s.helm.test/k8s.helm.test.csproj' feedsToUse: 'select' - task: DotNetCoreCLI@2 inputs: command: 'build' projects: 'k8s.helm.test/k8s.helm.test.csproj'
Dla testu możemy uruchomić pipeline przyciskiem “`Save and run“`.
Publikowanie obrazu dockerowego do repozytorium ACR
Po zbudowaniu projektu jesteśmy gotowi do opublikowania obrazu aplikacji. Repozytorium obrazów stworzyliśmy w tym wpisie. Musimy teraz dodać do niego połączenie w Azure Devops. Przechodzimy do strony ustawień w lewym dolnym rogu i wybieramy “Service connections” -> “New service connection” -> “Docker Registry”
Klikamy Azure Container Registry, wpisujemy dowonlą nazwę connection i wybieramy nasze repozytorium:
Wracamy do edycji pipelinu, w taskach wyszukujemy “Docker”
Wybieramy stworzone connection oraz nazywamy repozytorium dla kontenerów. Warto zwrócić uwagę na tag obrazu, będzie to numer builda. Będziemy go później potrzebować do pobrania obrazu poprzez Helma w Octopusie. Docker file aplikacji można znaleźć tutaj.
Dla testu uruchamiamy pipeline.
Pobieranie obrazu z prywatnego repozytorium
We wpisie gdzie tworzyliśmy paczkę helmową, obraz dockerowy był pobierany z publicznego repozytorium (DockerHub). Jednak repozytorium, do którego wypchnęliśmy obraz powyżej, jest repozytorium prywatnym. Helm w jakiś sposób musi się do niego dostać. W tym celu musimy stworzyć kubernetesowy “`Secret“`, którego Helm użyje do uwierzytelnienia się i pobrania obrazu, który opublikowaliśmy. Wpisujemy następującą komendę:
kubectl create secret docker-registry nazwaSecretu --namespace namespace --docker-server=url do repozytorium //itdepends.azurecr.io/k8s.test.app --docker-username= ServicePrincipalId --docker-password= ServicePrincipalSecret
Możemy użyć tutaj service principala, którego użyliśmy do uwierzytelnienia w feedzie Helmowym.
Następnie musimy dodać pole “`imageCredentials“` w pliku “`itdepends-deployment.yaml“` naszego wcześniej stworzonego chartu Helmowego.
imagePullSecrets: - name: {{ .Values.image.imagePullSecrets }}
Następnie podbijamy wersje chartu i wypychamy na githuba. Po chwili nowa wersja będzie dostępna w repo ACR. Cały chart dostępny jest tutaj.
Tworzenie procesu wdrożenia w Octopusie
Teraz stwórzmy projekt w Octopusie, w którym będziemy mogli zdefiniować proces jego wdrożenia na klaster testowy. W tym celu przechodzimy do zakładki “Projects”-> “Add project” i wpisujemy jego nazwę.
Octopus pozwala tworzyć zmienne dla projektów. Może to być przydatne do trzymania wartości, które zmieniają się per środowisko wdrożeniowe np. connection stringi. Żeby stworzyć taką zmienną, na poziomie projektu klikamy “Variables”.
Stwórzmy 2 zmienne, “`mongoConnectionString“` oraz “`mongoDatabaseName“`. W edytorze możemy oznaczyć je jako “Sensitive”, aby nie były widoczne od razu na wejściu. Dodatkowo ważne, aby określić zakres zmiennej na testowe środowisko.
Przejdźmy teraz do definiowania procesu wdrożenia, klikamy “Define your deployment process” -> “Add step”.
Jeśli używamy wersji Octopusa w chmurze, to na ten moment musimy przed wdrożeniem chartu Helmowego, zrobić update helm clienta. Aby to zrobić wybieramy krok “Script” -> “Run a Script”.
Wpisujemy nazwę oraz wybieramy rolę. Rola określa, na jakich deployment targetach krok się uruchomi. Musimy wybrać taką, w jakiej stworzyliśmy klaster testowy w poprzednim wpisie.
Przechodzimy niżej, wybieramy “Inline source code” i wpisujemy następujący kawałek skryptu:
choco upgrade kubernetes-helm -y
Zaznaczamy, że krok jest wymagany i zapisujemy. Następnie dodajemy kolejny krok przyciskiem “Add step”. Tym razem wybieramy “Kubernetes” -> “Upgrade a Helm Chart “.
Podobnie jak poprzednio nazywamy krok oraz wybieramy rolę.
Przechodzimy niżej, wybieramy feed chartów helmowych stworzony w poprzednim wpisie oraz sam chart.
Następnie musimy określić nazwę naszego release Helmowego. Musi być ona unikalna w danym namespace. Do wyboru mamy sporo zmiennych wbudowanych w Octopusa. W moim przypadku była to nazwa: “`itdepends-app-#{Octopus.Environment.Name}“`. Dodatkowo ważne jest wypełnienie pola namespace, na takie, do jakiego ma dostęp konto w kubernetesie, które tworzyliśmy tutaj.
Przechodzimy teraz do zakładki “Template values”. Tutaj możemy nadpisać domyślne wartości z pliku “`Values.yaml“` naszego chartu, podobnie jak to robiliśmy tutaj. Wpisujemy następujące wiersze klucz-wartość:
“`image.repository“` – nazwaRepozytoriumAcr/repozytoriumKontenerów *
“`image.tag“` – #{Octopus.Release.Number} **
“`image.imagePullSecrets“` – nazwaStworzonegoSecretuDoPobieraniaObrazów
“`settings.mongoConnectionString“` – #{nazwaZmiennejStworzonejDlaConnectionStringa}
“`settings.mongoDatabaseName“` – #{nazwaZmiennejStworzonejDlaNazwyBazy}
* nazwę repozytorium kontenerów wpisywaliśmy podczas tworzenia kroku “Docker” w Azure Devops.
** #{Octopus.Release.Number} jest to numer releasea w Octopusie. Numer ten będzie nadawany poprzez Azure Devops jako numer builda.
Na koniec oznaczamy ten krok jako wymagany i klikamy “Save”.
Uruchamianie deployu w Octopusie poprzez Azure Devops
W tym momencie mamy gotowe kroki 1, 2, 3, 5. Czas na krok numer 4, czyli uruchamianie deployu w Octopusie z poziomu Azure Devops.
Octopus wystawia API, poprzez które deployować releasy. Do tego zadania potrzebny nam będzie klucz, dzięki któremu będziemy mogli się poprzez API uwierzytelnić. W tym celu przechodzimy do Octopusa i w prawym górnym rogu klikamy nasz profil -> “Profile” -> “My API Keys” -> “New Api Key”.
Zachowujemy wygenerowany klucz, będzie nam potrzebny w Azure Devops.
Do deployowania releasów w Azure Devops potrzebujemy rozszerzenia “Octopus Deploy Integration”. Rozszerzenia możemy instalować na stronie https://marketplace.visualstudio.com/azuredevops.
Instalujemy powyższe rozszerzenie. Następnie musimy dodać połączenie do Octopusa w Azure Devops. Przechodzimy ponownie do “Settings” -> “Service connections” -> “New connection” i wyszukujemy “Octopus”.
Wypełniamy URL naszego Octopusa, wklejamy poprzednio wygenerowany API Key i wpisujemy nazwę.
Następnie w taskach pipelinu w Azure Devops będziemy mogli wyszukać następujące taski:
Wybieramy “Create Octopus Release”.
Wypełniamy poprzednio stworzone connection, space i projekt (nazwy zostaną pobrane z API Octopusa). W polu Release Number wpisujemy zmienną “`$(Build.BuildId)“`. Dzięki niej z poziomu Octopusa, Helm będzie mógł pobrać opublikowany obraz z repozytorium, który został tym id otagowany. Channel zostaje “default”. Przechodzimy niżej do pola “Deployment” i wybieramy środowisko testowe. Możemy zaznaczyć “Show deployment process”, dzięki temu w logach Azure Devops będziemy mogli zobaczyć progres tworzenia release.
Po dodaniu tego kroku zapisujemy pipeline. Po chwili uruchomione zostanie pierwsze wdrożenie na test. Jeśli wszystko poszło zgodnie z planem, w Azure Devops zobaczymy taki obraz:
Natomiast na dashboardzie Octopusa:
Po przejściu pod adres domeny lub IP stworzonego load balancera powinniśmy ujrzeć następujący widok:
Podsumowanie
I to tyle jeśli chodzi o ten wpis. Udało się zautomatyzować wdrożenie aplikacji na testowy klaster. W następnym wpisie postawimy produkcyjny klaster na Azure oraz wypromujemy aplikacje ze środowiska testowego na środowisko produkcyjne.