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 clickCreate 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 theSecret
-
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/