Post

SonarQube in Docker

In this post I will cover the basics of getting SonarQube running in a Docker container and walk you through setting up a simple ci-cd script to build and analyse a .net core project.

Requirements

JDK

You will need java installed on your system in order to run SonarQube, you can download the latest version of Java from here.

Install or extract the Java package to a known location on your system, in my case I went with installing the JDK which ended up unpacking it’s contents to C:\Program Files\Java\jdk-21.

Add a new System Environment variable called JAVA_HOME with the following path: C:\Program Files\Java\jdk-21.

Add the following path to the systems PATH environment variable: C:\Program Files\Java\jdk-21\bin.

Open up a console and type java -version to ensure that everything is working as expected.

Docker Desktop

Download and install Docker Desktop from the following link.

Ensure that you have WSL enabled and all the other guff needed for Docker to run.

You will most likely need to restart your computer.

SSMS or Equivalent

You will need SSMS or something similar to connect to the created Docker SQL instance and create the initial SonarQube database, if you would like to you can download SSMS at the following link.

.NET SDK

You will need the .net SDK along with any targeted frameworks installed, you can download the .net SDK if you need it from here.

Docker Environment Setup

Docker Compose File

The complete Docker compose file is shown below, to follow along copy the below to a file on your system called docker-compose.yaml.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
version: "3.6"

services:
  db:
    image: mcr.microsoft.com/mssql/server:2019-latest
    restart: always
    environment:
      ACCEPT_EULA: "Y"
      SA_PASSWORD: "saP@ssw0rd"
      MSSQL_PID: "Developer"
    volumes:
      - ./mssql/data:/var/opt/mssql/data
      - ./mssql/log:/var/opt/mssql/log
      - ./mssql/secrets:/var/opt/mssql/secrets
    ports:
      - 1433:1433

  sonarqube:
    image: sonarqube
    restart: always
    environment:
      SONAR_ES_BOOTSTRAP_CHECKS_DISABLE: true
      SONAR_JDBC_URL: jdbc:sqlserver://db;databaseName=SonarQube;trustServerCertificate=true;
      SONAR_JDBC_USERNAME: sa
      SONAR_JDBC_PASSWORD: "saP@ssw0rd"
    volumes:
      - ./sonarqube/data:/opt/sonarqube/data
      - ./sonarqube/logs:/opt/sonarqube/logs
      - ./sonarqube/extensions:/opt/sonarqube/extensions
    ports:
      - 9000:9000
    depends_on:
      - "db"

Initial Container Configuration

Open a terminal window and navigate to the folder where you saved your docker-compose.yaml file, to start the container run the below command.

1
docker-compose up

This will take some time for the initial start (subsequent starts will be a lot quicker), also note that the initial start of the container will result in a lot of errors being logged to the console - mainly due to the fact that SonarQube is unable to find the configures SQL database (we are about to resolve that issue now).

Using SSMS or something similar connect to your containers SQL instance using the sa password of saP@ssw0rd.

Once connected run the below query to create the expected SonarQube database:

1
2
3
4
5
6
7
USE [master]
GO
CREATE DATABASE [SonarQube]
 COLLATE SQL_Latin1_General_CP1_CS_AS
GO
ALTER DATABASE [SonarQube] SET RECOVERY SIMPLE
GO

You should now have a SonarQube database in the SQL_Latin1_General_CP1_CS_AS coalition and a recovery mode of simple.

After a while SonarQube should start to run its initial seeding of the DB, this is due to the fact that the SonarQube docker service is configured to always restart. If SonarQube does not seed the database you can try restarting the container to see if that helps.

You should now be able to navigate to SonarQube on http://localhost:9000/ and log in with the default user admin and password admin - make sure that you change your password to something that you can remember.

Subsequent Starting and Stopping

Once you have completed the initial setup as instructed above subsequent starting and stopping of the container can be done using the following commands.

These commands need to be run from the folder that you saved your docker-compose.yaml file in.

To start the container:

1
docker-compose up -d

To stop the container:

1
docker-compose down

SonarQube Setup

Create Project

To create a new project navigate to: http://localhost:9000/projects/create?mode=manual.

Enter in the details for your project and click next, choose your preferred settings when prompted on the next screen - generally I just use the global settings.

You should now have a test project to work with.

Token Generation

To generate tokens head over to your accounts security page: http://localhost:9000/account/security.

Complete the form to generate a token - feel free to select a different token type when prompted (I am just using a global analysis token for brevity).

Be sure to save the token returned as you won’t be able to see it again!

In my case the generated token is: sqa_6ac0644c998766a46a0f11ee0205cad162e5318d.

Build Process Setup

Once Off Setup

You will need to have the sonarscanner dotnet tool installed globally, if you do not have it installed you can use the following command to rectify that:

1
dotnet tool install --global dotnet-sonarscanner

Build Scripts

sonarqube.ps1

To make the build process a lot simpler I tend to use a helper script aptly named sonarqube.ps1 with the following body:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
param (
  [Parameter(Mandatory=$false)]
  [string] $project = "test",
  [Parameter(Mandatory=$false)]
  [string] $sqUrl = "http://localhost:9000",
  [Parameter(Mandatory=$true)]
  [string] $sqToken
)
$rootDir        = $PSScriptRoot;
$artifactsDir   = [IO.Path]::GetFullPath((Join-Path $rootDir "../artifacts/"));
$coverageDir    = [IO.Path]::GetFullPath((Join-Path $artifactsDir "test-coverage/"));
$sqReportPaths  = ($coverageDir + "**/coverage.opencover.xml");
dotnet sonarscanner begin /k:$project /d:sonar.host.url=$sqUrl  /d:sonar.login=$sqToken /d:sonar.cs.opencover.reportsPaths=$sqReportPaths
./ci-test.ps1
dotnet sonarscanner end /d:sonar.login=$sqToken

ci-test.ps1

I generally make use of a ci-test.ps1 file to orchestrate the build and test pipeline (it is a bit long winded and may not work for everyone), an example of the build script can be seen here.

In all honesty, a simple dotnet build should suffice in place of the call to ci-test.ps1 in the sonarqube.ps1 file - you will lose the coverage reports etc. though, but with some determination you should be able to create a custom build script that works for you.

Running Build Process

Armed with your build script and now running SonarQube instance you can kick off your first build and analyse using the sonarqube.ps1 file and your generated token.

1
.\sonarqube.ps1 -sqToken "sqa_6ac0644c998766a46a0f11ee0205cad162e5318d"

Once the process has completed your test project should now be updated with the results of the code analysis run.

This post is licensed under CC BY 4.0 by the author.

Comments powered by Disqus.