w ,

CI/CD dla Java Developerów w GitLabie – Kompletny Scenariusz w 6 Krokach

ci-cd
ci-cd

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ść, że Twoja aplikacja działa, jak należy.

👉 Jeśli 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-17

👉 To 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
  - deploy

🚀 Krok 3: Budowanie i testowanie

before_script:
  - chmod +x mvnw  # Jeśli 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 test

🔍 Krok 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:check

🐳 Krok 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_SHA

🌐 Krok 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 za pomocą 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

image: maven:3.9.4-eclipse-temurin-17

stages:
  - build
  - test
  - analyze
  - package
  - deploy

before_script:
  - chmod +x mvnw

build:
  stage: build
  script:
    - ./mvnw clean compile

test:
  stage: test
  script:
    - ./mvnw test

analyze:
  stage: analyze
  script:
    - ./mvnw com.github.spotbugs:spotbugs-maven-plugin:4.7.3.0:check

package:
  stage: package
  image: docker:latest
  services:
    - docker:dind
  script:
    - docker login -u &quot;gitlab-ci-token&quot; -p &quot;$CI_JOB_TOKEN&quot; $CI_REGISTRY
    - docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA .
    - docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA

deploy:
  stage: deploy
  image: alpine:latest
  only:
    - main
  before_script:
    - apk add --no-cache openssh sshpass
  script:
    - sshpass -p &quot;$DEPLOY_SERVER_PASSWORD&quot; ssh -o StrictHostKeyChecking=no root@123.123.123.123 &quot;
        docker login -u gitlab-ci-token -p $CI_JOB_TOKEN registry.gitlab.com &amp;&amp;
        docker pull registry.gitlab.com/my-group/my-project:$CI_COMMIT_SHORT_SHA &amp;&amp;
        IMAGE_TAG=$CI_COMMIT_SHORT_SHA docker-compose -f /root/myapp/docker-compose.yml up -d
      &quot;


🎓 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!

Napisane przez Przemysław Bykowski

Aktywny programista i energiczny trener. Specjalizuje się w Spring Boot i uczę go w ramach AkademiaSpring.pl. Po godzinach udzielam się na YouTubach. Więcej o mnie.

Dodaj komentarz

Tomcat vs Jetty vs Netty – Różnice w Obsłudze Żądań i Zarządzaniu Wątkami

prawo-stron-www

Nowe Przepisy Obejmujące Devów – EAA Zmienia Zasady Tworzenia Aplikacji i Stron