Continuous Integration/Continuous Delivery to dwa pojęcia, które są kluczowym elementem procesu dostarczania oprogramowania. Jenkins wykorzystywany wcześniej w naszych projektach dawał zadawalające efekty. Stąd pytanie - dlaczego zaczęliśmy migrować te procesy na rozwiązania oferowane przez GitLab i jego CI? W poniższym artykule postaramy się przybliżyć zalety korzystania z tego rozwiązania.

GitLab CI

GitLab jest znany, jeżeli nie wszystkim, to większości developerów. Jego podstawowym zadaniem jest wersjonowanie repozytoriów. Na przestrzeni ostatnich lat projekt ten dostarczył zintegrowany system do CI/CD, który ma kilka zalet wyróżniających go od innych rozwiązań. Ważne jest to że są one zintegrowane, a nie dostarczane w formie dodatkowych pluginów jak w przypadku Jenkinsa. Złożone aplikacje coraz częściej korzystają z dobrodziejstw mikroserwisów. W przypadku mikroserwisów i stale rosnącej popularności orchestratora Kubernetes, GitLab CI spełnia wymogi dostarczania takich aplikacji i ułatwia pracę z nimi. Funkcjonalności, które wyróżniają GitLab CI:

  • wbudowane repozytorium Docker wraz z wbudowanym flow do operacji na kontenerach
  • przeglądnie zbudowanych artefaktów przez interfejs web
  • zmienne środowiskowe z ograniczonym dostępem
  • deployment na konkretne środowiska, podzielone i niezależne
  • historia, dająca spojrzenie na to co aktualnie jest uruchomione/było uruchamiane na serwerach
  • GitLab Runner pozwala na bezpieczne przechowywanie danych wrażliwych uruchamianych z odpowiednich branchy z ograniczonym dostępem
  • integracja z klastrem Kubernetes
  • zintegrowane uruchomienie usług Kubernetes (helm, nginx Ingress, Prometheus, GitLab Runner)
  • uproszczona konfiguracja
  • skalowalność systemu

GitLab Runner

GitLab CI używa GitLab Runner, aby uruchamiać poszczególne procesy w drzewie. Runnery dzielimy na Shared Runners, Specific Runners oraz Group Runners(więcej).

  • Shared Runners - runnery wykonujące podobne zadania, które mogą być wykrzystywane przez kilka projektów. Kolejność uruchamiania zadań zarządzana jest przez kolejkę typu ‘fair usage queue’. Ma to zapewnić optymalizację wykorzystania zasobów na maszynach z działającymi runnerami.
  • Specific Runners - runnery używane w przypadku projektów wymagających specyficznej konfiguracji, np. większe uprawnienia wymagane do zbudowania modułu. Kolejka zadań dla tego typu ranerów działa w trybie FIFO.
  • Group Runners - przydatne, gdy chemy pogrupować projekty w grupy i dla każdej z nich wyspecyfikiować zestaw runnerów specyficznych dla danej grupy. Podobnie jak dla Specific Runners kolejka zadań działa w trybie FIFO.

Domyślnie GitLab Runner korzysta z kontenerów Docker w kolejnych etapach budowania, testowanie oraz deployment. Jest też możliwość użycia innych rozwiązań niż Docker: [źródło]
Domyślnym wyborem jest tu Docker ponieważ cykl życia kontenerów spełnia wymogi procesów uruchamianych przez runnery, a w szczególności po zakończeniu procesu zwalnia wszystkie zasoby. Docker jest również używany w pod-ach Kubernetes, a GitLab posiada wbudowany rejestr Docker, do którego możemy dodawać własne obrazy, później mogą być uruchamiane przez Kubernetes. To wszystko sprawia, że pracujemy w spójnym, opartym o kontenery środowisku.

Developer free

Jedną z największych zalet Gitlab CI jest swoboda dostosowania do własnych potrzeb procesu budowania aplikacji oraz jego monitorowania przez developera. Definicja build-ów odbywa się poprzez, edycję pliku gitlab.ci np.

build-with-test:
  image: maven:latest
  stage: build
  script:
    - mvn package


Powyższy prosty build obejmujący również testy, możemy w prosty sposób zmodyfikować tak, aby w fazie build wyłączyć testy i wydzielić je do oddzielnego procesu:

test-before-package:
  image: maven:latest
  stage: build
  script:
    - mvn test

build-package:
  image: maven:latest
  stage: build
  script:
    - mvn package -Dmaven.test.skip=true


Zdefiniowany proces może być wywołany automatycznie lub ręcznie. Istnieje również możliwość uruchamiania procesów warunkowo.

#auto
test-before-package:
  image: maven:latest
  stage: build
  script:
    - mvn test

#ręcznie
build-package:
  image: maven:latest
  stage: build
  script:
    - mvn package -Dmaven.test.skip=true
when: manual

#warunkowo
on-fail-go-to-tag:
  image: maven:latest
  stage: cleanup
  script:
    - mvn liquibase:rollback -Dliquibase.rollbackTag=checkpoint
when: on_failure

Konfiguracja, budowanie, testy i deployment na różne środowiska mogą być w prosty sposób dostosowane przez developera. Przykłady użycia wraz z listą dostępnych tagów znajdują się pod adresem: https://docs.gitlab.com/ee/ci/yaml. Łatwość budowania dowolnych konfiguracji dzięki wykorzystaniu obrazów Docker ułatwia korzystanie w projekcie z różnych narzędzi. Żeby to zobrazować posłużmy się przykładem projektu, gdzie specyficzne wymagania doprowadziły do podjęcia decyzji o wykorzystaniu Elasticsearch. W tradycyjnym podejściu musiałby zostać zaangażowany administrator IT, którego zadaniem byłoby przygotowanie środowisk do pracy deweloperów, testów i środowiska produkcyjnego. Zamiast tego wykorzystując Docker i dowolne narzędzie do deploymentu na klaster Kubernetes (helm, kubectl) developer samodzielnie może skonfigurować i uruchomić, a wcześniej zautomatyzować testy poprzez odpowiedni pipeline Gitlab CI.

Podsumowanie

Gitlab CI jest naprawdę potężnym narzędziem, które dostarcza rozwiązania spełniające oczekiwania stawiane przed nowoczesnymi zespołami tworzącymi oprogramowanie. Każdy etap budowania, testowania, dostarczania aplikacji jest monitorowany oraz dzięki przejrzystości wykonywanych operacji pozwala developerowi na szybsze dostarczanie nowych funkcjonalności.