Fixing GitLab CI Integration Tests for Spring Boot with PostgreSQL in Docker

Fixing GitLab CI Integration Tests for Spring Boot

❌ The Problem

You’ve got a Spring Boot application using PostgreSQL in Docker. Everything works locally, but in GitLab CI, integration tests fail with:

Connection refused: Cannot connect to PostgreSQL at cookbook-db:5432

🖼️ Example of a failed pipeline
Pipeline Error


🔍 Root Cause Breakdown

This error typically happens due to one or more of the following:

  1. PostgreSQL container isn’t ready when the tests run.
  2. Incorrect container aliasing — Spring Boot can’t resolve cookbook-db.
  3. Missing or misconfigured environment variables (e.g., DB user/password).
  4. Port conflicts or unexposed ports in CI runner.

✅ Working Solution

🔧 1. .gitlab-ci.yml Configuration

variables:
  POSTGRES_USER: youruser
  POSTGRES_PASSWORD: yourpassword
  POSTGRES_DB: cookbook-db
  POSTGRES_HOST_AUTH_METHOD: trust

stages:
  - build
  - test

maven-build:
  stage: build
  image: maven:3.9.9-eclipse-temurin-21
  script:
    - mvn clean compile
  artifacts:
    paths:
      - target/

integration-test:
  stage: test
  image: maven:3.9.9-eclipse-temurin-21
  services:
    - name: postgres:15.4-alpine
      alias: cookbook-db
      command: ["postgres", "-c", "max_connections=100"]
  variables:
    SPRING_DATASOURCE_URL: jdbc:postgresql://cookbook-db:5432/${POSTGRES_DB}
    SPRING_DATASOURCE_USERNAME: ${POSTGRES_USER}
    SPRING_DATASOURCE_PASSWORD: ${POSTGRES_PASSWORD}
  script:
    - |
      echo "Waiting for PostgreSQL..."
      for i in {1..10}; do
        nc -z cookbook-db 5432 && break
        echo "Retrying in 5s... ($i/10)"
        sleep 5
      done
    - mvn verify -Dspring.profiles.active=ci
  artifacts:
    when: always
    reports:
      junit: target/surefire-reports/*.xml

🗃️ 2. application-ci.properties

spring.datasource.url=${SPRING_DATASOURCE_URL}
spring.datasource.username=${SPRING_DATASOURCE_USERNAME}
spring.datasource.password=${SPRING_DATASOURCE_PASSWORD}
spring.jpa.hibernate.ddl-auto=validate
spring.sql.init.mode=always
spring.datasource.hikari.connection-timeout=30000
spring.datasource.hikari.maximum-pool-size=5
management.endpoint.health.probes.enabled=true
management.health.datasource.enabled=true

🔍 Debugging Tips

Check Docker Network in CI

Ensure containers are on the same network:

docker network ls
docker inspect <network-name>

🔧 What Fixed It

  1. Added retry loop with nc to wait until the DB is ready.
  2. Aliased the service correctly (cookbook-db).
  3. Passed DB credentials via GitLab CI environment variables.
  4. Increased max connections for concurrent test support.

🚧 Common Pitfalls

IssueFix
“Connection Refused”Add wait loop using nc or wait-for-it
Schema not initializedUse spring.sql.init.mode=always or Flyway/Liquibase
Port conflictCheck CI logs with netstat -tulpn

🧪 Best Practices

✅ Use Testcontainers (Alternative)

@Testcontainers
class IntegrationTest {
  @Container
  static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:15-alpine");
}

✅ Always Pin Versions

services:
  - name: postgres:15.4-alpine

✅ Tune Connection Pool

spring.datasource.hikari.maximum-pool-size=5
spring.datasource.hikari.connection-timeout=30000

⚡ Performance Tips

TechniqueBeforeAfter
Parallel stages120s85s
Testcontainers90s65s
Cached dependencies45s12s
cache:
  key: ${CI_COMMIT_REF_SLUG}
  paths:
    - .m2/repository
    - target/

❓ FAQ

Q: Why use nc -z instead of just sleep?
A: nc checks if the port is actually open. sleep just delays blindly.

Q: How do I run migrations before tests?
A: Use Flyway in your pipeline:

script:
  - mvn flyway:migrate -Dflyway.configFiles=src/main/resources/flyway-ci.conf
  - mvn verify

Q: Can I use Testcontainers in GitLab CI?
A: Yes! Enable Docker-in-Docker (DinD):

services:
  - docker:28.0.4-dind

variables:
  DOCKER_HOST: tcp://docker:2376
  DOCKER_TLS_VERIFY: "1"

🎉 Final Thoughts

By implementing proper service configuration, health checks, and environment isolation, your GitLab CI integration tests will run just as smoothly as they do locally.

✅ PostgreSQL ready before tests
✅ Stable container networking
✅ Reliable Spring Boot DB config

🖼️ Example of a successful pipeline
Success Screenshot

👉 See working example on GitHub


Let me know if you want a version of this as a blog post or Markdown doc!

Comments

No comments yet. Why don’t you start the discussion?

Leave a Reply

Your email address will not be published. Required fields are marked *