W zespołach developerskich stawiających na szybkie i częste dostarczanie oraz testowanie oprogramowania jedną z pierwszych rzeczy, która powinna zostać wdrożona, jest proces ciągłej integracji i ciągłego dostarczania, czyli ang. Continuous Integration/Continuous Delivery (CI/CD).
W dużym skrócie – powinniśmy stworzyć automat, który w czasie rzeczywistym będzie reagował na operacje zachodzące w naszym repozytorium i w oparciu o najnowszą wersję kodu wykona kolejne kroki, takie jak:
- kompilacja,
- testy,
- wdrożenie na środowiska,
- powiadomienie o ewentualnych błędach autora wprowadzanej zmiany.
Oczywiście, proces ten powinien inaczej reagować na zmiany w repozytorium głównym, deweloperskim, a jeszcze inaczej w gałęziach pobocznych – to wszystko trzeba najpierw dokładnie omówić wewnątrz zespołu projektowego, uwzględniając ustalony wcześniej flow, aby w następnym kroku poprawnie skonfigurować w narzędziu do CI/CD.
Z artykułu dowiecie się, jak i dlaczego warto w tym procesie wykorzystać Gitlab CI.
Implementacja procesu
Jest wiele aplikacji, takich jak Jenkins czy TeamCity, które świetnie radzą sobie z implementacją procesu i każda z nich ma swoich zwolenników. Jednak wszystkie łączy wspólna wada – są kolejnym narzędziem w naszym stacku technologicznym i będą wymagały dodatkowych zasobów, czyli czasu osoby, która zadba o poprawną integrację z repozytorium kodu, weźmie na siebie nadawanie odpowiednich uprawnień dla użytkowników, czy wreszcie będzie musiała zająć się monitorowaniem i utrzymywaniem maszyny, na której ta aplikacja będzie uruchomiona.
I tutaj pojawia się alternatywa: jeżeli kod przechowywany jest w repozytorium GitLab, to zamiast poszukiwać zewnętrznych rozwiązań, można skorzystać z wbudowanego narzędzia do ciągłej integracji zwanego GitLab CI.
Gitlab CI
Skoro Gitlab CI nie wymaga dodatkowej integracji z repozytorium kodu, to skąd projekt „wie”, że ma go używać? Ponieważ CI samo w sobie jest częścią projektu, a dokładniej plik gitlab-ci ,napisany w języku formalnym YAML używanym też między innymi do pisania manifestów Kubernetesa czy Ansible.
Plik ten umieszczony w katalogu głównym definiuje całą listę kroków wykonywanych przy okazji każdej zmiany kodu źródłowego w projekcie – oczywiście w oparciu o odpowiednie reguły. Jest to spore ułatwienie, które dodatkowo pozwala na wersjonowanie zmian samego CI/CD wraz z całym projektem i sprawia, że w bardzo łatwy sposób może być on migrowany i współdzielony.
Dodatkowo GitLab udostępnia w swoim GUI edytor pipeline’ów, który jest po prostu edytorem tekstowym naszego pliku yaml i ma sprawić, że praca nad CI/CD będzie łatwa, szybka i przyjemna, pomimo zachowania wszelkich reguł obowiązujących w repozytorium kodu. Sama konfiguracja gitlab-ci może też pomóc w utrzymywaniu standardów wytwarzania oprogramowania w obrębie organizacji poprzez include przygotowanego wcześniej wspólnego pliku przechowywanego w globalnym repozytorium. Jednak na tym etapie skupię się na możliwie jak najprostszym przypadku.
Konfiguracja Gitlab CI
W pliku gitlab-ci.yaml opisujemy kolejne etapy procesu CI/CD, czyli tak zwany pipeline, którego zawartość odczytywana jest w momencie wykonania w repozytorium polecenia git push.
Podstawową jednostką opisującą ten proces jest zadanie (ang. job), czyli definicja jednego lub kilku poleceń wraz z warunkami, w jakich zostaną one uruchomione. Polecenia te, zawarte w sekcji scripts, mogą być na przykład:
- uruchomieniem narzędzi typu maven czy docker,
- poleceniem systemowym,
- przypisaniem zmiennej środowiskowej.
W przypadku komend służących do przygotowania środowiska warto dodatkowo stworzyć sekcję before_script, która zostanie wykonana przed właściwym skryptem.
Kiedy mamy już zdefiniowane zadania, możemy je pogrupować w kolejne etapy (ang. stages), takie jak:
- build,
- test,
- deploy.
Będą one uruchomione w kolejności, w jakiej zostały zdefiniowane.
Załóżmy, że mamy już własne skrypty do kompilowania, testowania i deploymentu i chcemy je wykorzystać w naszym procesie CI/CD. Plik gitlab-ci.yaml mógłby wyglądać następująco:
Kolejne kroki
Tak jak wspomniałem, każdy poprawnie napisany pipeline, powinien rozróżniać działania, jakie ma podjąć w zależności od brancha, w jakim się znajduje. Jako że gitlab-ci.yaml jest integralną częścią projektu, nie będzie przechowywać kilku różnych wersji w zależności od tego, w której gałęzi się znajduje, a w zamian za to użyje warunku uruchomienia dla każdego etapu.
Opcja „only” służy do określenia, że ma być uruchomiony tylko wtedy, gdy spełnione są warunki, co w połączeniu z warunkiem „refs” pozwala nam zdefiniować zależność, aby dany etap był uruchomiony tylko dla określonej gałęzi. Jego przeciwieństwem jest opcja „expect”, która pozwala wykluczyć nasz etap z listy.
Samo warunkowanie ma dużo szersze zastosowanie. Mamy możliwość np.: uruchomienia danego etapu tylko w przypadku ustawienia odpowiedniej zmiennej środowiskowej albo jedynie, gdy nastąpi zmiana w określonych plikach. Zamiast ograniczać za pomocą nazwy gałęzi możemy także użyć tagów, włączając w to wyrażenia regularne.
Dodajmy zatem do naszego pipeline’a następujące warunki:
- Każdy etap uruchamia się jedynie w przypadku zmian w plikach z rozszerzeniem .py.
- Skrypt testujący uruchamiamy tylko w przypadku brancha „master”.
- „Deployment” startuje tylko wtedy, kiedy wartość DEPLOYMENT jest prawdziwa.
Runnery
Czy to oznacza, że od posiadania pełnoprawnego CI/CD dzieli nas już tylko wpisanie (albo wklejenie) w edytor kilkunastu linijek kodu? I tak i nie, ponieważ GitLab CI do uruchomienia potrzebuje runnerów, czyli niezależnych hostów, na których będą uruchamiane wszystkie zdefiniowane przez nas kroki.
W GitLab CI możemy korzystać zarówno z runnerów publicznych, jak i prywatnych. Pierwsze rozwiązanie będzie oczywiście szybsze, natomiast jeżeli zależy nam na odpowiedniej konfiguracji do potrzeb projektu, włączając w to właściwy system operacyjny oraz wszystkie niezbędne aplikacje i rozszerzenia, których używamy do budowania i wdrażania projektu, powinniśmy mieć runner prywatny. Albo użyć odpowiedniego obrazu Dockera, do czego jeszcze wrócę.
Więcej o tym, jak skonfigurować runnery, znajdziemy tutaj [link do dokumentacji].
Uruchomienie
Skoro mamy już gotowy pipeline (oraz przygotowane runnery), to najwyższa pora, aby go uruchomić i sprawdzić, czy rzeczywiście wykonuje dokładnie to, co sobie w nim zdefiniowaliśmy.
Gitlab udostępnia graficzną wizualizację pipeline’ów, która pozwala na łatwe zrozumienie tego, co dzieje się w ramach naszego CI/CD oraz informuje nas o statusie każdego z etapów.
Każdy etap jest reprezentowany przez osobną kolumnę i poza listą zdefiniowanych w nim zadań, udostępnia takie informacje jak czas ich wykonywania oraz nazwy maszyn wirtualnych, na których zostały uruchomione.
Z poziomu wizualizacji możemy też łatwo uruchamiać lub anulować poszczególne pipeline’y, a także analizować logi, czy sprawdzać wartości zwracane przez nasze skrypty, co może być szczególnie pomocne przy szybkiej identyfikacji ewentualnych problemów i błędów pojawiających się wraz ze wzrostem złożoności projektu.
Docker jako alternatywa
Na koniec wrócę jeszcze do runnerów, ponieważ aby jakakolwiek komenda zdefiniowana w jobie wykonała się poprawnie, musi być znana w środowisku, w którym się wykonuje. Jeżeli zatem chcemy uruchomić nasze skrypty, to muszą się one znajdować na naszym runnerze, podobnie jak każde inne potrzebne narzędzia oraz biblioteki.
W przypadku posiadania ograniczonej puli runnerów i większej liczby projektów robi się to nieco kłopotliwe, dlatego dobrym rozwiązaniem mogą okazać się obrazy dockerowe, które po skonfigurowaniu i dodaniu do pliku konfiguracyjnego będą używane w procesie CI/CD.
Mogą to być standardowe obrazy typu node:10, albo, jeżeli mamy specyficzne wymagania dotyczące środowiska budowania, własne – pod warunkiem, że zostaną one wcześniej zarejestrowane w zdalnym repozytorium takim jak np. Docker Hub.
Podsumowanie
Podsumowując, Gitlab CI to wszechstronne i elastyczne narzędzie do zarządzania procesem Continuous Integration/Continuous Delivery, które dzięki bezpośredniej integracji z platformą GitLab umożliwia łatwe zarządzanie projektem i współpracę zespołu. Jest intuicyjne, łatwe w konfiguracji, a jednocześnie daje duże możliwości do debuggowania i monitorowania pipeline’ów, dlatego warto się nim zainteresować, gdy planujemy wprowadzić proces CI/CD w naszym projekcie.
***
Jeśli interesują Cię dobre praktyki we wdrożeniu CI/CD, zajrzyj koniecznie również do innego artykułu autorstwa naszego specjalisty.
Zostaw komentarz