Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/infra-neo/CICD/llms.txt

Use this file to discover all available pages before exploring further.

SonarQube provides automated code quality and security analysis across every build. The Jenkins pipeline submits analysis results to SonarQube after the build and test stages using mvn sonar:sonar, and a dedicated Quality Gate stage blocks deployment if the code fails the configured quality thresholds. This means a build with too many bugs, security vulnerabilities, or insufficient test coverage will never make it to Nexus or the application servers.

Quick Reference

PropertyValue
Port9000
Imagesonarqube:community
Container Namesonarqube
Default Credentialsadmin / admin
DatabasePostgreSQL 13 (postgres container)
Data Volumesonarqube_data
Extensions Volumesonarqube_extensions
Logs Volumesonarqube_logs

Quality Gate Integration

The pipeline integrates with SonarQube through two Jenkinsfile stages. First, the SonarQube Analysis stage runs Maven inside a withSonarQubeEnv block, which injects the server URL and authentication token automatically. Second, the Quality Gate stage polls SonarQube and aborts the pipeline if analysis results do not pass.
stage('SonarQube Analysis') {
    steps {
        script {
            withSonarQubeEnv('SonarQube') {
                sh """
                    mvn sonar:sonar \
                    -Dsonar.projectKey=${env.JOB_NAME} \
                    -Dsonar.projectName=${env.JOB_NAME} \
                    -Dsonar.host.url=${SONARQUBE_URL}
                """
            }
        }
    }
}

stage('Quality Gate') {
    steps {
        timeout(time: 5, unit: 'MINUTES') {
            waitForQualityGate abortPipeline: true
        }
    }
}
The waitForQualityGate abortPipeline: true call pauses the build for up to five minutes, polling the SonarQube webhook. If the Quality Gate returns ERROR, the pipeline is immediately aborted and the deployment stages are skipped. The SonarQube server name 'SonarQube' must match the name registered in Jenkins by 04-configure-sonarqube.groovy.

Analysis Capabilities

Code Quality

Detects bugs, code smells, and duplicated blocks. Measures cyclomatic complexity and provides per-file and per-module breakdowns.

Security Vulnerabilities

Identifies OWASP Top 10 vulnerabilities, injection flaws, and insecure API usage using built-in security rules and optional security packs.

Test Coverage

Integrates with JaCoCo and other coverage tools to enforce minimum line and branch coverage thresholds as part of the Quality Gate.

Technical Debt

Calculates remediation effort in hours for all issues and tracks debt ratio over time, helping teams prioritize refactoring work.

Database Configuration

SonarQube requires a relational database for its data store. The stack uses a dedicated PostgreSQL 13 container with the following connection settings defined in docker-compose.yml:
postgres:
  image: postgres:13
  container_name: postgres
  environment:
    - POSTGRES_USER=sonar
    - POSTGRES_PASSWORD=sonar
    - POSTGRES_DB=sonarqube

sonarqube:
  image: sonarqube:community
  depends_on:
    - postgres
  environment:
    - SONAR_JDBC_URL=jdbc:postgresql://postgres:5432/sonarqube
    - SONAR_JDBC_USERNAME=sonar
    - SONAR_JDBC_PASSWORD=sonar
  volumes:
    - sonarqube_data:/opt/sonarqube/data
    - sonarqube_extensions:/opt/sonarqube/extensions
    - sonarqube_logs:/opt/sonarqube/logs
If you change the PostgreSQL credentials, you must update both the postgres service environment block and the matching SONAR_JDBC_* variables in the sonarqube service block. A mismatch will cause SonarQube to fail with a database connection error on startup.
To use production-grade credentials, create a docker-compose.override.yml (see docker-compose.override.yml.example) and override the environment variables there rather than editing the base docker-compose.yml directly:
postgres:
  environment:
    - POSTGRES_USER=sonar_prod
    - POSTGRES_PASSWORD=${DB_PASSWORD:-changeme}
    - POSTGRES_DB=sonarqube_prod

sonarqube:
  environment:
    - SONAR_JDBC_URL=jdbc:postgresql://postgres:5432/sonarqube_prod
    - SONAR_JDBC_USERNAME=sonar_prod
    - SONAR_JDBC_PASSWORD=${DB_PASSWORD:-changeme}

Memory Tuning

SonarQube runs two JVM processes internally: the Web Server and the Compute Engine (CE). Each has its own JVM options. The override example configures them for production-grade workloads:
sonarqube:
  environment:
    - SONAR_WEB_JAVAOPTS=-Xmx2048m -Xms1024m
    - SONAR_CE_JAVAOPTS=-Xmx2048m -Xms1024m
For development environments where memory is constrained, these can be reduced:
sonarqube:
  environment:
    - SONAR_WEB_JAVAOPTS=-Xmx1024m -Xms256m
    - SONAR_CE_JAVAOPTS=-Xmx1024m -Xms256m

vm.max_map_count Requirement

SonarQube embeds Elasticsearch, which requires the host kernel parameter vm.max_map_count to be at least 262144. On most default Linux installations this value is too low, causing SonarQube to crash-loop with an Elasticsearch bootstrap error.Apply the fix before starting the stack:
# Apply immediately (not persistent across reboots)
sudo sysctl -w vm.max_map_count=262144

# Make it permanent
echo "vm.max_map_count=262144" | sudo tee -a /etc/sysctl.conf
sudo sysctl -p
On macOS with Docker Desktop, this is handled automatically inside the Linux VM. On Windows with WSL2, set it inside the WSL2 instance.

Troubleshooting

The most common cause is vm.max_map_count being too low. Check the container logs for an Elasticsearch bootstrap error:
docker compose logs sonarqube | grep -i "max_map_count\|bootstrap\|elasticsearch"
Apply the fix:
sudo sysctl -w vm.max_map_count=262144
echo "vm.max_map_count=262144" | sudo tee -a /etc/sysctl.conf
Then restart the container:
docker compose restart sonarqube
If the crash is unrelated to vm.max_map_count, check whether PostgreSQL is healthy — SonarQube depends on the postgres container being fully ready before it can initialize.
  1. Verify that the postgres container is running and accepting connections:
    docker exec postgres psql -U sonar -d sonarqube -c "SELECT 1;"
    
  2. Confirm that SONAR_JDBC_USERNAME and SONAR_JDBC_PASSWORD in the sonarqube service exactly match POSTGRES_USER and POSTGRES_PASSWORD in the postgres service.
  3. If the credentials were changed after the database was initialized, the database user will need to be updated separately inside PostgreSQL. The simplest recovery path is to drop and recreate the database:
    docker exec postgres psql -U sonar -c "DROP DATABASE sonarqube;"
    docker exec postgres psql -U sonar -c "CREATE DATABASE sonarqube;"
    docker compose restart sonarqube
    
SonarQube requires you to change the default password on first login. Navigate to http://localhost:9000, log in with admin/admin, and you will be immediately prompted to set a new password. After changing it, update the sonarqube-token credential in Jenkins:
  1. Go to Jenkins → Manage Jenkins → Credentials.
  2. Find the sonarqube-token secret text credential.
  3. Update the secret value to match the new SonarQube token or password.
  1. Verify the sonarqube-token credential exists in Jenkins:
    docker exec jenkins cat /var/jenkins_home/credentials.xml | grep sonarqube-token
    
  2. Confirm SonarQube is reachable from within the Jenkins container:
    docker exec jenkins curl http://sonarqube:9000/api/system/status
    
    A healthy response looks like {"id":"...","version":"...","status":"UP"}.
  3. Run a manual analysis to isolate the problem:
    mvn sonar:sonar \
      -Dsonar.projectKey=test \
      -Dsonar.host.url=http://localhost:9000 \
      -Dsonar.login=admin \
      -Dsonar.password=admin
    
  4. Check that the SonarQube server name in 04-configure-sonarqube.groovy ("SonarQube") matches the name used in withSonarQubeEnv('SonarQube') in the Jenkinsfile.

Build docs developers (and LLMs) love