Skip to main content

Sonarqube - Docker Compose Stack, Code Inspection with GitLab Integration

988 words·
Sonarqube PostgreSQL Docker-Compose GitLab GitLab Application

I’m using a Debian 12 Bookworm server in this tutorial.

Prerequisites
#

vm.max_map_count
#

Adjust the vm.max_map_count of the Debian server, this setting controls the maximum number of memory map areas a process can have:

# Open sysctl.conf (Used for configuring kernel parameters at runtime)
sudo vi /etc/sysctl.conf

# Add the following line at the end of the file:
vm.max_map_count=262144

# Apply changes
sudo sysctl -p
  • Otherwise the following error appears and the container crashes:
# docker compose logs -f
sonarqube-1  | bootstrap check failure [1] of [1]: max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]; for more information see [https://www.elastic.co/guide/en/elasticsearch/reference/8.11/_maximum_map_count_check.html]

Sonarqube
#

Folder Structure
#

# Create the folder structure
sudo mkdir -p /opt/sonarqube/{sonarqube_data,sonarqube_extensions,sonarqube_logs} && cd /opt/sonarqube

Environment File
#

# Create environment file for Postgres password
sudo vi .env

# Define passwords
POSTGRES_PW=postgres-pw

Docker Compose YML
#

Note: I always prefer host mappings to Docker volumes because it’s easier to move the Docker stack to another host when necessary. With Sonarqube, I found that the easiest way to map the container storage to the host was to first use Docker volumes with a defined path and then switch to host mappings.

# Create Docker Compose file
sudo vi docker-compose.yml
  • Inital start with volumes
version: "3.9"
services:
  sonarqube:
    image: sonarqube:community
    depends_on:
      - db
    environment:
      - sonar.jdbc.username=sonarqubeuser
      - sonar.jdbc.password=${POSTGRES_PW}
      - sonar.jdbc.url=jdbc:postgresql://db:5432/sonarqube
    volumes:
      - sonarqube_data:/opt/sonarqube/data
      - sonarqube_extensions:/opt/sonarqube/extensions
      - sonarqube_logs:/opt/sonarqube/logs
    ports:
      - "9000:9000"

  db:
    image: postgres:12
    environment:
      - POSTGRES_DB=sonarqube
      - POSTGRES_USER=sonarqubeuser
      - POSTGRES_PASSWORD=${POSTGRES_PW}
    volumes:
      - ./postgresql:/var/lib/postgresql
      - ./postgresql_data:/var/lib/postgresql/data

volumes:
  sonarqube_data:
    driver: local
    driver_opts:
      type: none
      device: /opt/sonarqube/sonarqube_data
      o: bind
  sonarqube_extensions:
    driver: local
    driver_opts:
      type: none
      device: /opt/sonarqube/sonarqube_extensions
      o: bind
  sonarqube_logs:
    driver: local
    driver_opts:
      type: none
      device: /opt/sonarqube/sonarqube_logs
      o: bind
# Create / start Docker container
sudo docker compose up -d

# Stop Docker container & remove the volumes
sudo docker compose down --volumes
  • Replace the volumes with host mappings
version: "3.9"
services:
  sonarqube:
    image: sonarqube:community
    depends_on:
      - db
    environment:
      - sonar.jdbc.username=sonarqubeuser
      - sonar.jdbc.password=${POSTGRES_PW}
      - sonar.jdbc.url=jdbc:postgresql://db:5432/sonarqube
    volumes:
      - ./sonarqube_data:/opt/sonarqube/data
      - ./sonarqube_extensions:/opt/sonarqube/extensions
      - ./sonarqube_logs:/opt/sonarqube/logs
    ports:
      - "9000:9000"

  db:
    image: postgres:12
    environment:
      - POSTGRES_DB=sonarqube
      - POSTGRES_USER=sonarqubeuser
      - POSTGRES_PASSWORD=${POSTGRES_PW}
    volumes:
      - ./postgresql:/var/lib/postgresql
      - ./postgresql_data:/var/lib/postgresql/data
# Create / start Docker containers
sudo docker compose up -d

Traefik Reverse Proxy
#

# Create a Docker network for the reverse proxy
sudo docker network create traefik
version: "3.9"
services:
  sonarqube:
    image: sonarqube:community
    depends_on:
      - db
    environment:
      - sonar.jdbc.username=sonarqubeuser
      - sonar.jdbc.password=${POSTGRES_PW}
      - sonar.jdbc.url=jdbc:postgresql://db:5432/sonarqube
    volumes:
      - ./sonarqube_data:/opt/sonarqube/data
      - ./sonarqube_extensions:/opt/sonarqube/extensions
      - ./sonarqube_logs:/opt/sonarqube/logs
    ports:
      - "9000:9000"
    labels:
      - "traefik.enable=true"
      - "traefik.docker.network=traefik"
      - "traefik.http.services.sonarqube-service.loadbalancer.server.port=9000"
      # HTTPS Router
      - "traefik.http.routers.sonarqube.entrypoints=websecure"
      - "traefik.http.routers.sonarqube.tls=true"
      - "traefik.http.routers.sonarqube.rule=Host(`sonarqube.jklug.work`)"
      # HTTP Router
      - "traefik.http.routers.sonarqube-http.rule=Host(`sonarqube.jklug.work`)"
      - "traefik.http.routers.sonarqube-http.entrypoints=web"
      - "traefik.http.routers.sonarqube-http.middlewares=redirect-to-https"
      # Middleware for HTTP to HTTPS redirection
      - "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https"
    networks:
      - intern
      - traefik

  db:
    image: postgres:12
    environment:
      - POSTGRES_DB=sonarqube
      - POSTGRES_USER=sonarqubeuser
      - POSTGRES_PASSWORD=${POSTGRES_PW}
    volumes:
      - ./postgresql:/var/lib/postgresql
      - ./postgresql_data:/var/lib/postgresql/data
    labels:
      - "traefik.enable=false"
    networks:
      - intern

networks:
  traefik:
    external: true
  intern:

Webinterface
#

Login
#

# Sonarqube webinterface: HTTP
http://192.168.70.11:9000/

# Sonarqube webinterface: HTTPSx
https://sonarqube.jklug.work/

# Default user:
admin

# Default password:
admin

Server base URL
#

Go to Administration > General

  • Define the “Server base URL” https://sonarqube.jklug.work

GitLab Integration
#

DNS Resolution
#

I’m using a wildcard certificate for the GitLab and Sonarqube servers in my homelab and my domain “jklug.work” usually creates troubles with the DNS resolution, therefore a define a host entry for both the Sonarqube and GitLab Docker Compose YML files and also in the configuration of the GitLab Runner.

Sonarqube
#

Regarding to the GitLab and Sonarqube setup it could be necessary to define a DNS hosts entry for the GitLab server:

# For example
    extra_hosts:
      - "gitlab.jklug.work:192.168.70.4"
  • Here is the whole Docker Compose YML
version: "3.9"
services:
  sonarqube:
    image: sonarqube:community
    depends_on:
      - db
    environment:
      - sonar.jdbc.username=sonarqubeuser
      - sonar.jdbc.password=${POSTGRES_PW}
      - sonar.jdbc.url=jdbc:postgresql://db:5432/sonarqube
    volumes:
      - ./sonarqube_data:/opt/sonarqube/data
      - ./sonarqube_extensions:/opt/sonarqube/extensions
      - ./sonarqube_logs:/opt/sonarqube/logs
    ports:
      - "9000:9000"
    extra_hosts:
      - "gitlab.jklug.work:192.168.70.4"
    labels:
      - "traefik.enable=true"
      - "traefik.docker.network=traefik"
      - "traefik.http.services.sonarqube-service.loadbalancer.server.port=9000"
      # HTTPS Router
      - "traefik.http.routers.sonarqube.entrypoints=websecure"
      - "traefik.http.routers.sonarqube.tls=true"
      - "traefik.http.routers.sonarqube.rule=Host(`sonarqube.jklug.work`)"
      # HTTP Router
      - "traefik.http.routers.sonarqube-http.rule=Host(`sonarqube.jklug.work`)"
      - "traefik.http.routers.sonarqube-http.entrypoints=web"
      - "traefik.http.routers.sonarqube-http.middlewares=redirect-to-https"
      # Middleware for HTTP to HTTPS redirection
      - "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https"
    networks:
      - intern
      - traefik

  db:
    image: postgres:12
    environment:
      - POSTGRES_DB=sonarqube
      - POSTGRES_USER=sonarqubeuser
      - POSTGRES_PASSWORD=${POSTGRES_PW}
    volumes:
      - ./postgresql:/var/lib/postgresql
      - ./postgresql_data:/var/lib/postgresql/data
    labels:
      - "traefik.enable=false"
    networks:
      - intern

networks:
  traefik:
    external: true
  intern:

Gitlab-Runner
#

concurrent = 1
check_interval = 0
shutdown_timeout = 0
log_level = "debug"
log_format = "text"

[session_server]
  session_timeout = 1800

[[runners]]
  name = "Untagged-Build-Runner-01"
  url = "https://gitlab.jklug.work"
  id = 1
  token = "***"
  token_obtained_at = 2024-02-03T21:35:10Z
  token_expires_at = 0001-01-01T00:00:00Z
  executor = "docker"
  [runners.cache]
    MaxUploadedArchiveSize = 0
  [runners.docker]
    extra_hosts = ["gitlab.jklug.work:192.168.70.4","gitlab-registry.jklug.work:192.168.70.4","sonarqube.jklug.work:192.168.70.11"]
    tls_verify = false
    image = "docker:latest"
    privileged = true
    disable_entrypoint_overwrite = false
    oom_kill_disable = false
    disable_cache = false
    volumes = ["/cache"]
    shm_size = 0
    network_mtu = 0

Gitlab Access Token
#

Go to (User) > Preferences > Access Tokens

  • Click Add new token
  • Select api and click Create personal access token
  • Copy the access token

Sonarqube Project
#

Go to the Sonarqube Projects section

  • Click “Import from GitLab” Setup
  • Define a “Configuration name”

  • Define the “GITLAB API URL” https://gitlab.jklug.work/api/v4

  • Paste the GitLab Access Token and click Save configuration

  • Paste the GitLab Access Token again and click Save
  • Import initial project

GitLab User Authentication
#

GitLab Application
#

# Redirect URI
https://sonarqube.jklug.work/oauth2/callback/gitlab
  • Copy the Application ID and the Secret

  • Click Continue

Sonarqube Authentication
#

Go to Administration > Authentication > GitLab

  • Click Create configuration
  • Paste the GitLab Application ID

  • Define the GitLab URL https://gitlab.jklug.work

  • Paste the GitLab Application Secret

  • Enable Allow users to sign up
  • Logout from Sonarqube and you should be able to login via GitLab

Project Onboarding
#

Import Projects
#

Select With GitLab CI

  • Create the two GitLab CI/CD Variables as described
  • Select the code language
  • In the GitLab project, create the sonar-project.properties file and create or update the existing .gitlab-ci.yml pipeline file

  • Wait till the pipeline job has finished

  • Go to the Sonarqube project section of Sonarqube to find the code analysis

Links #

# Dockerhub
https://hub.docker.com/_/sonarqube

# Official Documentation
https://docs.sonarsource.com/sonarqube/latest/

# Official Documentation: Gitlab Authentication
https://docs.sonarsource.com/sonarqube/latest/instance-administration/authentication/gitlab/