Continuous Integration i Continuous Delivery to nieodłączne elementy nowoczesnego developmentu. Dzięki nim automatyzujesz testowanie, budowanie i wdrażanie swoich aplikacji – zyskując czas, jakość i pewność, iż Twoja aplikacja działa, jak należy.
jeżeli chcesz lepiej zrozumieć samą koncepcję CI/CD, sprawdź mój wcześniejszy artykuł:
Continuous Integration i Continuous Delivery – wprowadzenie
Tutaj natomiast przejdziemy do konkretów – zbudujemy kompletny pipeline CI/CD w GitLabie dla aplikacji Java opartej na Spring Boot. Dowiesz się, jak:
- zbudować projekt (Maven/Gradle),
- uruchomić testy jednostkowe i integracyjne,
- przeprowadzić statyczną analizę kodu,
- zbudować obraz Dockera,
- wypchnąć go do GitLab Container Registry,
- automatycznie wdrożyć aplikację na serwer.
Krok 1: Stwórz prostą aplikację Spring Boot
Nie musimy komplikować – wystarczy prosty endpoint:
@RestController public class HelloController { @GetMapping("/hello") public String getHello() { return "hello"; } }Dodaj też przykładowy test jednostkowy, na potrzeby scenariusza CI/CD:
@SpringBootTest class HelloControllerTest { @Autowired private MockMvc mockMvc; @Test void helloShouldReturnDefaultMessage() throws Exception { mockMvc.perform(get("/hello")) .andExpect(status().isOk()) .andExpect(content().string("hello")); } }Krok 2: Konfiguracja Pipelin’u .gitlab-ci.yml
W katalogu głównym projektu utwórz plik .gitlab-ci.yml. Na samym początku tego pliku określ, z jakiego obrazu Dockerowego chcesz korzystać w jobach CI/CD – dla projektów Maven najczęściej wybieramy oficjalny obraz:
image: maven:3.9.4-eclipse-temurin-17To bardzo ważne – ten obraz zapewnia środowisko z zainstalowanym Mavenem i Javą 17. Dzięki temu wszystkie komendy mvn będą działać poprawnie.
Następnie definiujemy etapy (stages):
stages: - build - test - analyze - package - deployKrok 3: Budowanie i testowanie
before_script: - chmod +x mvnw # jeżeli używasz mvnw, który znajduje się w repo (zamiast tego z obrazu) musisz dodać te uprawnienia build: stage: build script: - ./mvnw clean compile test: stage: test script: - ./mvnw testKrok 4: Analiza kodu
Aby statyczna analiza kodu działała, musisz dodać do pom.xml plugin SpotBugs (lub inny).
<plugin> <groupId>com.github.spotbugs</groupId> <artifactId>spotbugs-maven-plugin</artifactId> <version>4.7.3.0</version> <configuration> <failOnError>false</failOnError> </configuration> </plugin>Następnie w .gitlab-ci.yml dodajesz:
analyze: stage: analyze script: - ./mvnw com.github.spotbugs:spotbugs-maven-plugin:4.7.3.0:checkKrok 5: Budowanie Dockera i publikacja
W tym etapie chcemy zbudować obraz Dockera z naszą aplikacją Java i wysłać go do GitLab Container Registry, czyli prywatnego rejestru obrazów dostępnego w Twoim projekcie GitLab.
Ale uwaga! Do budowania i pushowania obrazów Dockerowych potrzebujemy specjalnego środowiska – nie wystarczy już zwykły image z Mavenem. Tutaj konieczne jest uruchomienie Docker-in-Docker (DinD) – czyli środowiska, które pozwoli GitLabowi uruchamiać polecenia docker build, docker push itp.
Dlatego w tym etapie:
- używamy obrazu docker:latest, który zawiera klienta Dockera,
- uruchamiamy usługę pomocniczą docker:dind, która daje dostęp do samego demona Dockera wewnątrz kontenera.
Oto gotowy przykład konfiguracji joba:
package: stage: package image: docker:latest # Obraz z klientem Docker services: - docker:dind # Demon Docker w kontenerze script: - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY - docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA . - docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHAKrok 6: Automatyczny deploy
Etap wdrożenia zależy od tego, na jakie środowisko publikujesz aplikację. Inaczej będzie wyglądać deploy do AWS, inaczej na serwer z Kubernetesem, a jeszcze inaczej – na klasyczny VPS z Linuksem i Dockerem.
Na koniec naszego pipeline’u automatycznie wdrażamy aplikację na zdalny serwer VPS. W tym przykładzie używamy klasycznego połączenia SSH z wykorzystaniem sshpass, a sam deploy realizujemy dzięki docker-compose.
deploy: stage: deploy image: alpine:latest before_script: - apk add --no-cache openssh sshpass script: - sshpass -p "$DEPLOY_SERVER_PASSWORD" ssh -o StrictHostKeyChecking=no root@123.123.123.123 " docker login -u gitlab-ci-token -p $CI_JOB_TOKEN registry.gitlab.com && docker pull registry.gitlab.com/my-group/my-project:$CI_COMMIT_SHORT_SHA && IMAGE_TAG=$CI_COMMIT_SHORT_SHA docker-compose -f /root/myapp/docker-compose.yml up -d"Uwaga: W powyższym przykładzie dane wrażliwe (klucz prywatny SSH i adres IP serwera) zostały wpisane jawnie tylko w celach demonstracyjnych. W prawdziwym projekcie zawsze przechowuj takie informacje jako zmienne środowiskowe w ustawieniach GitLaba (CI/CD → Variables), aby uniknąć przypadkowego wycieku danych i zadbać o bezpieczeństwo.
Podsumowanie
I gotowe! Masz w pełni funkcjonalny pipeline CI/CD dla aplikacji Java w GitLabie. Budujesz, testujesz, analizujesz, pakujesz w kontener i… automatycznie wdrażasz!
Finalny plik .gitlab-ci.yml
Moje szkolenie
Chcesz zobaczyć live coding, praktyczne przykłady i jeszcze więcej detali CI/CD?
Dołącz do mojego szkolenia CI/CD dla Java Developerów, które poprowadzę już w maju – zarezerwuj miejsce i wynieś swój dev workflow na wyższy poziom!