Deploy SonarQube 8.9 with Docker on Ubuntu, and set Gitlab CI integration
Tags: codequality, docker, devops, sonarqube
Published: 2021-08-02 10:17:52

**SonarQube** is one the most popular [static analysis tool](https://dev.to/promyze/a-collection-of-106-open-source-linters-32o1), mainly because it exists since 2008 and is open-source, easing its adoption in the IT industry. 

In this post, we'll show how to deploy the latest **SonarQube LTS Community Edition** so far (8.9), with a **PostgreSQL** DB and using Docker. We're using Ubuntu 20.04 but, as we use Docker, you may only have to adapt the **Docker** installation and hardware requirements sections. We'll finally demonstrate how to *run a SonarQube analysis* using **Gitlab CI** for a Java project. 


## 🚢 Install Docker and Docker Compose

If not already done, the first step is to install Docker and Docker Compose. The official [documentation](https://docs.docker.com/engine/install/ubuntu/) already has everything you need, but we'll give you the basics steps for a fresh install of Docker on your server : 

```bash
$> sudo apt-get update
$> sudo apt-get install \
    apt-transport-https \
    ca-certificates \
    curl \
    gnupg \
    lsb-release
$> curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
$> echo \
  "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \
  $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
$> sudo apt-get update
$> sudo apt-get install docker-ce docker-ce-cli containerd.io
$> sudo groupadd docker
$> sudo usermod -aG docker $USER
```

Logout and Login again to your server, you should be able to run 

```bash
$> docker run hello-world
```

And now you can install **Docker Compose** :

```bash
$> sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
$> sudo chmod +x /usr/local/bin/docker-compose
```


## 🏵️ Adjust OS settings

SonarQube has some hardware requirements : you should increase the values for those 2 OS settings :

- **[fs.file-max](https://www.kernel.org/doc/Documentation/sysctl/fs.txt)**: "*The value in file-max denotes the maximum number of file- handles that the Linux kernel will allocate. When you get lots of error messages about running out of file handles, you might want to increase this limit*."
- [**vm.max_map_count**](https://www.kernel.org/doc/Documentation/sysctl/vm.txt): "*the maximum number of memory map areas a process may have. Memory map areas are used as a side-effect of calling malloc, directly by mmap and mprotect, and also when loading shared libraries."*

You should modifiy as **root** user the */etc/sysctl.conf* file to set permanently the values for these 2 parameters : 

```bash
$> sudo nano /etc/sysctl.conf
```

Then add this content to the file :

```bash
# can be added at the end of the file
fs.file-max=131072
vm.max_map_count=524288
```

Save, close, and then reload the settings : 

```bash
$> sudo sysctl --system
```

## 🚀 Run SonarQube

Set the following **docker-compose.yml** file to run both SonarQube and PostgreSQL 12 containers : 

```yaml
version: "3"

services:
  sonarqube:
    image: sonarqube:8.9.2-community
    depends_on:
      - db
    environment:
      SONAR_JDBC_URL: jdbc:postgresql://db:5432/sonar
      SONAR_JDBC_USERNAME: sonar
      SONAR_JDBC_PASSWORD: sonar #tochange
    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_USER: sonar
      POSTGRES_PASSWORD: sonar #tochange
    volumes:
      - postgresql:/var/lib/postgresql
      - postgresql_data:/var/lib/postgresql/data

volumes:
  sonarqube_data:
  sonarqube_extensions:
  sonarqube_logs:
  postgresql:
  postgresql_data:
```

⚠️ It would be best if you changed the default password.

You're now ready to run your SonarQube 🚀

```bash
$> docker-compose up -d
```

You can check the evolution of the logs using **docker-compose logs -f** command. SonarQube is ready when the following logs are displayed : 

```bash
$> docker-compose logs -f
...
sonarqube_1  | 2021.08.02 07:05:05 INFO  ce[][o.s.ce.app.CeServer] Compute Engine is operational
sonarqube_1  | 2021.08.02 07:05:05 INFO  app[][o.s.a.SchedulerImpl] Process[ce] is up
sonarqube_1  | 2021.08.02 07:05:05 INFO  app[][o.s.a.SchedulerImpl] SonarQube is up
```

Wait a little bit and you should get the following screen on http://localhost:9000 :  


![SonarQube Login Page](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qmwbh0s6yzpb6aan5nwr.png)

The next steps will to change the default password for the *admin* account, and now you'll be ready to start. 


## 🧪 Run analysis on GitLab CI for a Java project

We're now going to run a SonarQube analysis on a project example written in **Java 11** and configured with **Maven**. We also use **[JUnit](https://junit.org/junit5/)** and **Jacoco** to produce code coverage reports. Here is the **pom.xml** file :

```xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>promyze</groupId>
    <artifactId>java-example-sonarqube</artifactId>
    <version>1.0</version>

    <properties>
        <sonar.core.codeCoveragePlugin>jacoco</sonar.core.codeCoveragePlugin>
        <sonar.jacoco.reportPath>${project.basedir}/../target/jacoco.exec</sonar.jacoco.reportPath>
        <sonar.language>java</sonar.language>
    </properties>

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.0</version>
                <configuration>
                    <source>11</source>
                    <target>11</target>
                    <release>11</release>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>

            <plugin>
                <groupId>org.sonarsource.scanner.maven</groupId>
                <artifactId>sonar-maven-plugin</artifactId>
                <version>3.7.0.1746</version>
            </plugin>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-report-plugin</artifactId>
                <version>2.18.1</version>
            </plugin>

            <!-- Jacoco for code coverage -->
            <plugin>
                <groupId>org.jacoco</groupId>
                <artifactId>jacoco-maven-plugin</artifactId>
                <version>0.8.3</version>
                <configuration>
                    <append>true</append>
                </configuration>
                <executions>
                    <execution>
                        <goals>
                            <goal>prepare-agent</goal>
                        </goals>
                    </execution>
                    <execution>
                        <id>post-unit-test</id>
                        <phase>test</phase>
                        <goals>
                            <goal>report</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>
```

Here is the **.gitlab-ci.yml** file to be put at the root of the repository. We have two steps here : one to compile the project and run the unit tests, and the second to run SonarQube analysis. Note that the image *maven:3.6.3-jdk-11* is publicly available. If you're not using Maven, you should browse the SonarQube documentation to check how to run analysis from your context.

```yaml
stages:
  - test
  - codequality

variables:
  MAVEN_OPTS: "-Dmaven.repo.local=.m2/repository"

cache:
  paths:
    - .m2/repository/

test:
  stage: test
  image: maven:3.6.3-jdk-11
  script:
    - mvn install
  artifacts:
    expire_in: 10 min
    paths:
      - target/

sonarqube:
  stage: codequality
  image: maven:3.6.3-jdk-11
  variables:
    SONAR_USER_HOME: "${CI_PROJECT_DIR}/.sonar"  # Defines the location of the analysis task cache
  script:
    - mvn sonar:sonar
  only:
    - master #you should change this part depending on the context
```

On GitLab CI, you should set 2 environment variables : 

- **SONAR_HOST_URL** : This is the full URL of your SonarQube instance.
- **SONAR_TOKEN** : An API token, follow this [documentation](https://docs.sonarqube.org/8.9/user-guide/user-token/) to generate one.

To achieve that GitLab, go to your project/group settings → CI/CD → Variables section. Then you can add the 2 values. 

![Gitlab_CI_Config](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/quta40d30rv60z5duscb.png)

Once you've pushed your *.gitlab-ci.yml*, your first SonarQube analysis should start, and you should get something like this : 🤗

![SonarQubeResult](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/shs3ru7gq8ipnvpg6vx1.png)

That was quite simple, don't you think? 🙂 


## Going further with SonarQube

At [Promyze](https://promyze.com?utm_source=DevTo), we commonly help our customers with their projects using SonarQube: setup, migration of versions, configuration, integration with CI/CD, and so on. Such code quality platforms help to define coding rules repositories shared across teams. 

Unfortunately, automatic tools can't detect all kinds of issues. That's why developers are doing **code reviews** and create custom best practices wikis. Promyze is designed for such a purpose; take a tour and check how Promyze can help you to **define and share your best coding practices!** 🚀

Also, feel free to comment to ask for clarification or suggest improvements to this post. 🙏🏽