Minęło trochę czasu od mojego ostatniego artykułu. Wakacje się skończyły! Trzeba wrócić do pisania. Jako pierwszy artykuł po przerwie chciałbym wam przedstawić sposób na skonfigurowanie Continuous Deployment za pomocą Gitlab CI. Przejdziemy całą ścieżkę od pipeline-a, aż do Azure App Service. Możecie się zastanawiać: dlaczego używam gitlab-a zamiast Azure DevOps (dawnego VSTS) ? Korzystam w z niego w niekomercyjnych projektach od lat. Jest mi dużo bardziej znany niż inne rozwiązania dostępne na rynku. Na wstępie zaznaczam, że w tym tutorial-u nie będę opisywał jak zarejestrować się w Azure czy też założyć konto / projekt na Gitlab-ie.

Stworzenie Aplikacji

Zacznijmy od stworzenia aplikacji, którą możemy spakować w kontener i zdeployować. Nie musimy mieć nic wymyślnego. Wystarczy zwykły plik index.html. Zachowanie pipeline-a nie będzie się zbytnio różniło w stosunku do innych aplikacji. Sam plik niech zawiera dobrze znany wszystkim programistom napis `Hello World! `

<h1>Hello World!</h1>

Nie musimy nawet dodawać znaczników body, head, html etc., to tylko przykładowy artefakt naszej aplikacji.

Musimy jeszcze dopisać Dockerfile plik, który będzie miał definicję naszego obrazu. Aby napisana powyżej aplikacja wyświetlała się prawidłowo, wykorzystamy bazowy obraz serwera nginx.

FROM nginx:1.14.2-alpine
COPY . /usr/share/nginx/html
EXPOSE 80
CMD ["nginx","-g","daemon off;"]

Gotowe! W pięciu linijkach zmieściliśmy zarówno aplikację jak i definicję obrazu dockera. Super!

Utworzenie Azure Container Registry

Po utworzeniu aplikacji przejdźmy do zdefiniowania usługi Azure Container Registry. Jej zadaniem jest przechowywanie gotowych obrazów tzw. rejestr. Przykładem publicznego rejestru jest docker hub. Zakładam, że nie wszystkimi projektami będziecie się dzielić że światem, dlatego dzisiejszy przykład będzie oparty właśnie o ACR.

Najłatwiej utworzyć usługę poprzez wejście do portalu Azure i użycie przycisku z zielonym plusem w lewym górnym rogu ekranu. Następnie należy, w wyszukiwarkę, wpisać “Container Registry”. Na liście podpowiedzi powinna się wyświetlić usługa Container Registry. Po kliknięciu na wciskamy “Create”, po czym następuje przekierowanie do formularza. Uzupełniamy tam podstawowe dane na temat rejestru, takie jak Registry Name(nazwa i adres pod jakim rejestr będzie dostępny), rodzaj subskrypcji, grupę zasobów, lokację i, na końcu, dwa najważniejsze elementy użytkownika systemowego i SKU. W dalszej części, do łączenia się z serwerem, będziemy korzystać z konta admina. Chciałbym zaznaczyć, że nie jest to preferowane rozwiązanie produkcyjne. Zdecydowanie lepszym będzie wykorzystanie mechanizmu `service principal`. Instrukcje konfiguracji możesz przeczytać w dokumentacji MSDN.

Idąc dalej, wasza konfiguracja registru powinna wyglądać następująco.

Od razu po zdefiniowaniu rejestru powinniście do niego przejść. Będziecie potrzebować nazwy i hasła admina, aby spushować do niego obraz. Wszystko znajdziecie w zakładce Access Keys, tak jak to przedstawia poniższy obrazek:

Definicja Gitlab CI

Przejdźmy do serca całego artykułu – konfiguracji Gitlab CI. Będziemy potrzebować jednego pliku gitlab-ci.yml Zdefiniujemy w nim tylko jeden etap pipeline-a, będzie to deploy. Etap ten będzie zawierać trzy akcję:

  1. Zbudowanie obrazu wraz z dodaniem do niego tagu latest
  2. Zalogowanie się na konto admina w rejestrze kontenerów
  3. Spushowanie obrazu do rejestru kontenerów

Dodatkowo, możemy dodać jeszcze kilka innych fajnych opcji, takich jak:

  • Blokadę, ograniczającą możliwość wykonania deploy-a jedynie z branch-a master,
  • Definicję środowiska, do którego trafia aplikacja. Wtedy w Gitlab-ie otrzymamy bardzo ładny panel, skąd będziemy mogli przejść do aplikacji
  • Zmienne jak hasło i nazwa użytkownika powinny być pobierane jako zmienne środowiskowe, aby nie trzymać ich w kodzie

Zacznijmy od ostatniego. Wystarczy, że w projekcie na Gitlabie przejdziemy do zakładki Settings -> CI / CD i tam znajdziemy sekcję Enviroment Variables. Tutaj przepisujemy wartości znalezione z zakładce Access Keys zgodnie z obrazkiem poniżej:

Kolejność w tym przypadku nie ma znaczenia.

To jedyny podpunkt, który trzeba wykonać poza plikiem gitlab-ci.yml. Teraz, aby spełnić wszystkie wcześniej postawione wymagania, plik gitlab-ci.yml powinien wyglądać następująco:

stages:
  - deploy
    
deploy:
  image: docker:latest
  stage: deploy
  variables:
    DOCKER_DRIVER: overlay
  services:
    - docker:dind
  script:
    - docker build -t testingcd.azurecr.io/testappcd:latest .
    - echo "$DOCKER_PASSWD" | docker login $DOCKER_REPOSITORY --username $DOCKER_USER --password-stdin
    - docker push testingcd.azurecr.io/testappcd:latest
  only:
    - master
  environment:
    name: app-service
    url: https://testappcd.azurewebsites.net

Ponieważ Gitlab uruchomi pipleine w swoim kontenerze docker-a, potrzebne jest użycie mechanizmu “docker-in-docker” tak, aby można było z wnętrza kontenera wywoływać komendy docker-a. Powyższy pliczek jest dość prosty, ponieważ mamy tylko jeden zdefiniowany etap. W bardziej rzeczywistym przypadku plik ten będzie o wiele bardziej rozbudowany np. o uruchamianie testów jednostkowych / integracyjnych, statyczną analizę kodu etc. Z ciekawszych rzeczy, jakie możemy tu zobaczyć, jest odwołanie do zmiennych środowiskowych za pomocą znaku “$”. W pliku znajdziemy również definicje środowiska. Co prawda sekcja ta nie jest wymagana, ale osobiście wolę ją mieć.

Inną interesującą rzeczą jest wykorzystanie echo "$DOCKER_PASSWD" i potokowanie go jako argument polecenia docker login. Tylko po co? Gdyby użyć zwykłego docker login -u -p to w konsoli pojawiłby się warning, informujący że nie należy tak robić ze względów bezpieczeństwa.

Jak tylko zacomitujemy zmiany, automatycznie zostanie wywołany pipeline. Jeśli do tej pory wykonaliśmy wszystko poprawnie, wynikiem tego pipeline-a powinien być obraz dostępny w ACR.

Konfiguracja Azure App Service

Przechodzimy do ostatniej części tego tutoriala, czyli do konfiguracji Azure App service for containers. Jest to usługa PaaS, pozwalająca na uruchamianie aplikacji bez potrzeby martwienia się o administracje serwerami etc. Stworzenie usługi wymaga powstania tzw. App Service Plan. Proces tworzenia zasobu wygląda podobnie do wcześniej opisanego tworzenia rejestru. Ponownie, poprzez przycisk z zielonym znakiem plusa, przechodzimy do wyszukiwarki, gdzie wyszukujemy App Service Plan. Kliknięcie na podpowiedź spowoduje przekierowanie na ekran z opisem usługi. Kliknięcie w przycisk Create spowoduje przekierowanie do poniższego formularza:

Woląc hostować aplikacje na systemach operacyjnych z rodziny Linux niestety mam trochę bardziej ograniczone możliwości wybrania modelu rozliczeniowego. Dlatego, najmniejszy jaki mogę wybrać, to B1, który do celów tego tutorialu wystarczy aż nad to.

Następnie trzeba utworzyć aplikację. Ponownie przechodzimy ścieżkę “zielony plus” -> Wyszukiwarka -> “Web App for Containers” -> kliknięcie w podpowiedź -> Create i przejdziemy do poniższego formularza.

Jak widać sporo elementów formularza się powtarza, dlatego też pominę ich omawianie. Zdecydowanie ciekawsze część znajduje się pod polem Configure Container. Klikając tutaj zostaniemy przeniesieni do nowego formularza. Pozwoli nam na wybranie, jaki kontener ma być uruchomiony wewnątrz tego App Service.

Posiadamy kilka opcji: przykładowy, a także pomiędzy różnymi rejestrami kontenerów jak Azure Container Registry, Docker Hub czy private registry. W naszym wypadku wybieramy Azure Container Registry i tutaj portal azure pokieruje już nami za rączkę. Najpierw zostaną załadowane rejestry do wyboru, następnie po wybraniu rejestru zostaną załadowane znajdujące się w nim obrazy, potem tagi. Naprawdę całkiem przyjemnie to działa.

Po utworzeniu App Service-u musimy minimalną chwilę odczekać, aby  ukazała się aplikacja.

Tak więc wszystko działa poprawnie, Super!

Jeszcze jedna rzecz nam została: wewnątrz ustawień App Service przechodzimy do sekcji Container Settings i przestawiamy dźwignię o nazwie “Continuous Deployment” na “On”.

App Service będzie automatycznie “odświeżał” aplikację kiedy pojawi się nowa wersja obrazu.

Aby to przetestować wystarczy zmienić w pliku index.html napis Hello World! na Hello GitlabCI!. Następnie szybki commit, push. Odczekanie kilku chwil w zależności od szybkości internetu i pod tym samym adresem powinien się pojawić napis:

I tak to powinno działać! Bez żadnej ingerencji programistów / adminów / ekipy sprzątającej.

Podsumowanie

Tak właśnie przeszliśmy całe flow od pipeline-a Gitlab CI aż do Azure App Service. Mam nadzieje, że artykuł się spodobał.
Dzięki za przeczytanie! I jak zwykle:
Do Następnego!

Cześć.