What Is SonarQube
SonarQube, before 2013 known as Sonar, is a tool for inspecting code quality with static analysis, bug detection, code smells, and security vulnerabilities. It's best to run these scans at build time with your CI/CD tools such as Jenkins or GitLab CI/CD. There are plenty of tools with which SonarQube can integrate seamlessly.
Why Should I Use SonarQube
SonarQube has a few advantages over its alternatives. Namely, it has a long history as it's been continuously developed since 2008 as an open-source tool. Additionally, if you are integrating SonarQube within your CI/CD pipelines, you can automatically stop build and deployments if any of the analyses run don't meet your pre-defined thresholds. It supports over 25 programming languages, including Java, Swift, JavaScript, and C#. The full list can be found here.
TL;DR It's free automated code review for every single push, merge, and deployment!
Why Docker
For most use cases, a Docker container running SonarQube will be ample for testing if you want to bring a SAST tool into your main production pipelines. Docker makes it easy to build and destroy images with minimal impact on your systems.
Installation
Installing Docker and Docker Compose
Be sure to have Docker installed and running on your system. See the guide tagged above for help!
I'll cover the installation steps for a bare minimum test instance and also a more reliable solution that can be torn down and rebuilt with no data loss (well you still can lose data if you wipe the database and volumes).
Test Instance
To pull the official SonarQube Docker image, run the following command.
docker run -d \
--name sonarqube \
-e SONAR_ES_BOOTSTRAP_CHECKS_DISABLE=true \
-p 9000:9000 \
sonarqube:latest
Somewhat Reliable Test Instance
You need a running instance of one of the supported databases. I opted for PostgreSQL. Then you'll need to create three new Docker volumes.
docker volume create --name sonarqube_data
docker volume create --name sonarqube_logs
docker volume create --name sonarqube_extensions
Now pull the image and bind it to the database and volumes.
If using Oracle, you will have to install the JDBC driver extension first. Find it here. Download it and move it to the sonarqube_extensions/jdbc-driver/oracle
location.
docker run -d \
--name sonarqube \
-e SONAR_JDBC_URL={INSERT JDBC URL} \
-e SONAR_JDBC_USERNAME={INSERT JDBC USERNAME} \
-e SONAR_JDBC_PASSWORD={INSERT JDBC PASSWORD} \
-v sonarqube_data:/opt/sonarqube/data \
-v sonarqube_extensions:/opt/sonarqube/extensions \
-v sonarqube_logs:/opt/sonarqube/logs \
-p 9000:9000 \
sonarqube:latest
Don't include the curly braces.
Breakdown
I'll dissect each of the Docker commands and flags above if you're new to this.
docker
simply invokes the Docker daemon that you have installed.
run
has three use cases:
- Pull the image from Docker Hub. You can specify other locations from Docker Hub, but that's not for this tutorial.
- Create a container based on the image. Think of the image as a class and the container as an instance of that class i.e. an object.
- Start the container based on the parameters provided as flags to Docker.
-d
is shorthand for detached. This will keep your terminal on its current instance instead of porting you into a new container's terminal instance.
--name sonarqube
is, well, the name you want to assign the container. If you don't include it, Docker will assign it a random name like jubilant_powerwasher. In this case, it will be sonarqube. Much better.
-e SONAR_ES_BOOTSTRAP_CHECKS_DISABLE=true
is adding and setting the environment variable SONAR_ES_BOOTSTRAP_CHECKS_DISABLE
. This will disable some checks that a production level SonarQube determines are necessary with its ElasticSearch integration and could otherwise break your build. Generally, these are memory checks to make sure there's enough available for smooth operation. When using an external database, this setting will be ignored. Bootstrap checks will run every time and probably fail your build. Check the troubleshooting steps for how to configure your system for an external database.
-p 9000:9000
binds the localhost's port 9000 to the Docker container's port of 9000. The localhost port (the first number) can be changed to any open port you have, but the container port (the second number, after the colon) is pre-determined by whoever created the image. Do not change the second port number.
sonarqube:latest
is the final parameter passed. It tells Docker which image to pull and what version (identified as tags after the colon). In this case, it's pulling the latest version, which at the time of writing this article is 9.0.1-community. You could replace the latest tag with this explicit version or lts which is 8.9.2-community.
Final Steps
You can now navigate to localhost:9000 in your web browser and be presented with the login screen. The default log-in credentials for SonarQube are username: admin and password: admin.
A Note About Databases
SonarQube runs with an embedded H2 instance for its database on initial creation after these specific steps. This is okay for the actual testing of SonarQube but bad in a real-world scenario. Be sure to bind it to a persistent relational database. Support exists for Oracle, Microsoft SQL Server, and PostgreSQL.
Troubleshooting
To see the logs for your container, run the following. This section of the document will be updated as I find more errors (or readers tell me about them!)
docker logs sonarqube
Bootstrap checks failed
If you're getting this or a similar error message, follow the below steps.
ERROR: [1] bootstrap checks failed. You must address the points described in the following [1] lines before starting Elasticsearch.
bootstrap check failure [1] of [1]: max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]
You will need to increase the memory areas available. However, be sure to understand the risks associated with doing so.
sudo vim /etc/sysctl.conf
Add the following line.
vm.max_map_count=262144
Source the new settings.
sysctl --system
Everything Docker is frozen
Restart the Docker daemon. Worst case, restart the machine. With volumes and databases set up, you shouldn't lose any data.
sudo service docker restart