Na początku słowo wyjaśnienia: w poprzednim artykule zapowiedziałem kontynuację dotyczącą monitorowania aplikacji. Ten temat pojawi się w osobnym wpisie.
Dziś natomiast skupiam się na czymś, co powinno zostać omówione wcześniej, na poprawnym workflow CI/CD dla aplikacji Kotlin + Ktor w chmurze Google.
Założenia
-
Kod źródłowy jest hostowany w serwisie GitHub
-
Każda Pull Request (PR) automatycznie uruchamia budowanie i testy
-
Merge do main wyzwala budowanie obrazu kontenerowego i opcjonalny deployment
-
Budowanie obrazu odbywa się za pomocą Jib (bez Dockera)
Co to jest Pull Request (PR) i merge?
GitHub (i inne współczesne systemy kontroli wersji) pozwalają na rozwijanie oprogramowania w gałęziach (branches). Programiści pracują nad nowymi funkcjami lub poprawkami błędów w osobnych gałęziach, a następnie, gdy zmiany są gotowe, tworzą tzw. Pull Request (PR).
PR to prośba o włączenie (merge) zmian z jednej gałęzi (optymalnie zawierającej jedną zmianę funkcjonalną lub poprawkową)
do głównej gałęzi projektu, najczęściej main
.
W ramach PR inni członkowie zespołu mogą przeglądać kod (code review), sugerować poprawki,
komentować lub zatwierdzać zmiany. Dopiero po zatwierdzeniu i mergu (czyli scalenia zmian) do main
,
kod staje się częścią głównej wersji aplikacji.
Taki proces umożliwia:
-
wyższą jakość kodu (dzięki code review)
-
unikanie błędów w głównej gałęzi (a przynajmniej ich minimalizację)
-
automatyczne uruchamianie testów przed scaleniem (CI)
Połączenie GitHub z Cloud Build
Po skonfigurowaniu połączenia z repozytorium w zakładce Repositories (Cloud Build) możemy utworzyć triggery, które będą reagować na zdarzenia zachodzące w projekcie GitHub.
Trigger 1: Pull Request (CI)
Ten trigger uruchamia się automatycznie dla każdego PR skierowanego do main.
Pozwala na zbudowanie aplikacji i uruchomienie testów jeszcze przed wykonaniem merge
.
-
Typ: "Pull request"
-
Gałąź docelowa: ^main$
-
Konfiguracja builda:
cloudbuild.test.yaml
steps:
- name: 'gradle:8.14.2-jdk21'
dir: '.'
env:
- 'PROJECT_ID=$PROJECT_ID'
entrypoint: bash
args:
- -c
- |
./gradlew build --no-daemon
Trigger 2: Merge do main (CI/CD)
Ten trigger uruchamia się po zatwierdzeniu PR i scaleniu go z main. Na tym etapie budowany jest obraz kontenera i opcjonalnie następuje deploy.
-
Typ: "Push to branch"
-
Gałąź: ^main$
-
Konfiguracja builda: cloudbuild.yaml
steps:
- name: 'gradle:8.14.2-jdk21'
dir: '.'
env:
- 'PROJECT_ID=$PROJECT_ID'
entrypoint: bash
args:
- -c
- |
./gradlew jib --no-daemon
Dobre praktyki
Pull Requesty powinny być wykorzystywane jako formalny punkt walidacji kodu przed jego scaleniem do głównej gałęzi projektu. To właśnie w PR-ach odbywa się przegląd zmian, uruchamiane są testy i zapadają decyzje o dopuszczeniu kodu do produkcyjnej wersji aplikacji.
Zdecydowanie nie należy wdrażać aplikacji automatycznie na podstawie kodu znajdującego się w Pull Requeście.
Proces deploymentu powinien być uruchamiany dopiero po scaleniu zmian do gałęzi main
,
co gwarantuje, że do środowiska trafia jedynie przetestowany i zaakceptowany kod.
Warto również przechowywać w repozytorium dwa osobne pliki konfiguracyjne cloudbuild.yaml
: jeden dla buildów i deploymentu,
drugi dla budowania i testowania PR. Pozwala to na precyzyjne kontrolowanie, co i kiedy jest wykonywane w zależności od kontekstu.
Dla większej elastyczności dobrze jest korzystać z mechanizmu zmiennych,
takich jak PROJECT_ID
, co umożliwia łatwe przenoszenie konfiguracji między projektami i środowiskami.
Co dalej?
W kolejnym kroku warto rozważyć dodanie automatycznego wdrażania aplikacji do usługi Cloud Run po pomyślnym zakończeniu procesu builda. To pozwoli jeszcze bardziej zautomatyzować cały proces CI/CD, skracając czas między zakończeniem pracy programisty a udostępnieniem nowej wersji użytkownikom.
Kolejnym rozszerzeniem może być włączenie skanowania bezpieczeństwa budowanego obrazu kontenerowego, jako osobnego kroku w pipeline. Dzięki temu możliwe będzie wykrywanie znanych podatności w zależnościach i bibliotekach już na etapie integracji.
Warto również rozbudować workflow o testy end-to-end (E2E) lub testy kontraktowe, które pozwolą jeszcze lepiej zabezpieczyć jakość aplikacji, szczególnie w środowiskach z mikrousługami lub systemami komunikującymi się po API.
Podsumowanie
Konfiguracja przedstawiona w tym artykule stanowi solidny fundament pod profesjonalny proces CI/CD dla aplikacji pisanych w Kotlinie i uruchamianych na Cloud Run. Dzięki wyraźnemu podziałowi na buildy dla PR-ów i buildy produkcyjne uzyskujemy bezpieczeństwo, powtarzalność i kontrolę nad całym procesem wdrożeniowym.
Zastosowanie narzędzia Jib pozwala na budowanie obrazów kontenerowych bez konieczności używania Dockera, co dodatkowo upraszcza infrastrukturę i skraca czas buildów.
Automatyczne uruchamianie testów w PR-ach zwiększa jakość kodu, a deployment po zatwierdzeniu zmian pozwala mieć pewność, że do środowiska trafiają jedynie sprawdzone i zaakceptowane aktualizacje.
Całość tworzy przejrzysty i nowoczesny workflow, który może być z powodzeniem wykorzystywany nawet w bardziej złożonych projektach.
W kolejnym wpisie przygotujemy testy i prosty monitoring.
Repozytorium: https://github.com/mariuszz/cloud-run-ktor-hello
Linki
Inne artykuły z serii
-
Wprowadzenie
-
Pierwsze wdrożenie
-
Budowanie obrazów kontenerowych dla kotlin + ktor bez Dockera z użyciem Jib i Cloud Build
-
Profesjonalny workflow CI/CD dla aplikacji Kotlin + Ktor z użyciem Cloud Build i GitHub