Integrate SonarQube with Kubernetes and Helm charts for automated code quality scanning

Intermediate 45 min Apr 03, 2026 436 views
Ubuntu 24.04 Debian 12 AlmaLinux 9 Rocky Linux 9

Deploy SonarQube on Kubernetes using Helm charts with PostgreSQL database, configure automated code scanning workflows, and implement persistent storage for comprehensive code quality analysis in your CI/CD pipeline.

Prerequisites

  • Kubernetes cluster (1.24+)
  • kubectl configured
  • Helm 3.8+
  • 4GB RAM minimum
  • 20GB storage available

What this solves

SonarQube integration with Kubernetes provides automated code quality scanning for your applications directly in your container orchestration platform. This setup enables continuous code analysis, quality gates, and security vulnerability detection as part of your CI/CD workflows. You'll have a scalable, production-ready SonarQube deployment with persistent storage and database backend.

Step-by-step installation

Update system packages and install prerequisites

Start by updating your system and installing required tools including kubectl, helm, and curl for managing your Kubernetes cluster and deployments.

sudo apt update && sudo apt upgrade -y
sudo apt install -y curl wget gnupg software-properties-common
sudo dnf update -y
sudo dnf install -y curl wget gnupg2

Install kubectl and verify Kubernetes cluster access

Install the Kubernetes command-line tool and verify you can access your cluster. This assumes you have an existing Kubernetes cluster configured.

curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
chmod +x kubectl
sudo mv kubectl /usr/local/bin/
kubectl version --client
kubectl cluster-info

Install Helm 3

Install Helm package manager for Kubernetes to deploy SonarQube using official charts. This provides a streamlined deployment process with customizable configurations.

curl https://baltocdn.com/helm/signing.asc | gpg --dearmor | sudo tee /usr/share/keyrings/helm.gpg > /dev/null
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/helm.gpg] https://baltocdn.com/helm/stable/debian/ all main" | sudo tee /etc/apt/sources.list.d/helm-stable-debian.list
sudo apt update
sudo apt install -y helm
echo -e "[helm]\nname=Helm\nbaseurl=https://baltocdn.com/helm/stable/rpm/\nenabled=1\ngpgcheck=1\ngpgkey=https://baltocdn.com/helm/signing.asc" | sudo tee /etc/yum.repos.d/helm-stable.repo
sudo dnf install -y helm
helm version

Create SonarQube namespace and add Helm repository

Create a dedicated namespace for SonarQube deployment and add the official SonarQube Helm repository for accessing the latest charts.

kubectl create namespace sonarqube
helm repo add sonarqube https://SonarSource.github.io/helm-chart-sonarqube
helm repo update
helm search repo sonarqube

Create PostgreSQL database for SonarQube

Deploy PostgreSQL as the database backend for SonarQube using Helm. This provides persistent storage for code analysis data and configuration.

helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo update
auth:
  postgresPassword: "SonarQubeP@ssw0rd!"
  username: "sonarqube"
  password: "SonarQubeDBP@ss!"
  database: "sonarqube"
primary:
  persistence:
    enabled: true
    size: 20Gi
    storageClass: "standard"
  resources:
    requests:
      memory: 256Mi
      cpu: 250m
    limits:
      memory: 512Mi
      cpu: 500m
helm install postgresql bitnami/postgresql -f postgresql-values.yaml -n sonarqube

Configure SonarQube Helm values

Create a comprehensive configuration file for SonarQube deployment including database connection, resource limits, and persistent storage settings.

postgresql:
  enabled: false

jdbcOverwrite:
  enable: true
  jdbcUrl: "jdbc:postgresql://postgresql:5432/sonarqube"
  jdbcUsername: "sonarqube"
  jdbcPassword: "SonarQubeDBP@ss!"

sonarqube:
  image:
    tag: "10.3.0-community"
  resources:
    requests:
      memory: 2Gi
      cpu: 500m
    limits:
      memory: 4Gi
      cpu: 1000m
  persistence:
    enabled: true
    size: 10Gi
    storageClass: "standard"
  sonarProperties: |
    sonar.forceAuthentication=true
    sonar.security.realm=sonar

service:
  type: LoadBalancer
  ports:
    http: 9000

ingress:
  enabled: true
  annotations:
    kubernetes.io/ingress.class: nginx
    cert-manager.io/cluster-issuer: letsencrypt-prod
  hosts:
    - name: sonarqube.example.com
      path: /
  tls:
    - secretName: sonarqube-tls
      hosts:
        - sonarqube.example.com

plugins:
  install:
    - "https://github.com/dependency-check/dependency-check-sonar-plugin/releases/download/3.1.0/sonar-dependency-check-plugin-3.1.0.jar"

env:
  - name: SONAR_ES_BOOTSTRAP_CHECKS_DISABLE
    value: "true"

Deploy SonarQube with Helm

Install SonarQube using the configured values file. This creates all necessary Kubernetes resources including deployments, services, and persistent volumes.

helm install sonarqube sonarqube/sonarqube -f sonarqube-values.yaml -n sonarqube
kubectl get pods -n sonarqube -w
Note: Wait for both PostgreSQL and SonarQube pods to reach Running status before proceeding. This may take 3-5 minutes for initial startup.

Configure SonarQube scanner deployment

Create a reusable SonarQube scanner pod configuration for running code analysis jobs. This template can be used in CI/CD pipelines for automated scanning.

apiVersion: v1
kind: ConfigMap
metadata:
  name: sonar-scanner-config
  namespace: sonarqube
data:
  sonar-project.properties: |
    sonar.projectKey=my-project
    sonar.projectName=My Project
    sonar.projectVersion=1.0
    sonar.sources=src
    sonar.language=java
    sonar.java.binaries=target/classes
    sonar.coverage.jacoco.xmlReportPaths=target/site/jacoco/jacoco.xml
---
apiVersion: batch/v1
kind: Job
metadata:
  name: sonar-scanner-job
  namespace: sonarqube
spec:
  template:
    spec:
      containers:
      - name: sonar-scanner
        image: sonarsource/sonar-scanner-cli:5.0
        env:
        - name: SONAR_HOST_URL
          value: "http://sonarqube-sonarqube:9000"
        - name: SONAR_LOGIN
          valueFrom:
            secretKeyRef:
              name: sonar-token
              key: token
        volumeMounts:
        - name: source-code
          mountPath: /usr/src
        - name: scanner-config
          mountPath: /opt/sonar-scanner/conf/sonar-project.properties
          subPath: sonar-project.properties
        workingDir: /usr/src
        command: ["sonar-scanner"]
      volumes:
      - name: source-code
        persistentVolumeClaim:
          claimName: source-code-pvc
      - name: scanner-config
        configMap:
          name: sonar-scanner-config
      restartPolicy: Never
kubectl apply -f sonar-scanner-pod.yaml

Create persistent volume for source code

Set up persistent storage for source code that will be analyzed. This allows CI/CD systems to mount code repositories for analysis.

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: source-code-pvc
  namespace: sonarqube
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 5Gi
  storageClassName: standard
kubectl apply -f source-code-pvc.yaml
kubectl get pvc -n sonarqube

Configure RBAC for scanner pods

Create service account and RBAC permissions for SonarQube scanner pods to interact with Kubernetes API when needed for advanced integrations.

apiVersion: v1
kind: ServiceAccount
metadata:
  name: sonar-scanner
  namespace: sonarqube
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: sonarqube
  name: sonar-scanner-role
rules:
  • apiGroups: [""]
resources: ["pods", "configmaps", "secrets"] verbs: ["get", "list"]
  • apiGroups: ["batch"]
resources: ["jobs"] verbs: ["get", "list", "create"] --- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: sonar-scanner-binding namespace: sonarqube subjects:
  • kind: ServiceAccount
name: sonar-scanner namespace: sonarqube roleRef: kind: Role name: sonar-scanner-role apiGroup: rbac.authorization.k8s.io
kubectl apply -f scanner-rbac.yaml

Set up automated scanning workflow

Create a sample CI/CD integration script that demonstrates how to trigger SonarQube analysis from your build pipeline using Kubernetes jobs.

#!/bin/bash

CI/CD Integration Script for SonarQube Scanning

PROJECT_KEY="${1:-my-project}" PROJECT_NAME="${2:-My Project}" SOURCE_PATH="${3:-/tmp/source}" SONAR_TOKEN="${4}" if [ -z "$SONAR_TOKEN" ]; then echo "Error: SONAR_TOKEN environment variable is required" exit 1 fi

Create secret for SonarQube token

kubectl create secret generic sonar-token \ --from-literal=token="$SONAR_TOKEN" \ -n sonarqube \ --dry-run=client -o yaml | kubectl apply -f -

Update scanner job with project details

cat > /tmp/scanner-job.yaml << EOF apiVersion: batch/v1 kind: Job metadata: name: sonar-scan-$(date +%s) namespace: sonarqube spec: template: spec: serviceAccountName: sonar-scanner containers: - name: sonar-scanner image: sonarsource/sonar-scanner-cli:5.0 env: - name: SONAR_HOST_URL value: "http://sonarqube-sonarqube:9000" - name: SONAR_LOGIN valueFrom: secretKeyRef: name: sonar-token key: token - name: SONAR_PROJECT_KEY value: "$PROJECT_KEY" - name: SONAR_PROJECT_NAME value: "$PROJECT_NAME" volumeMounts: - name: source-code mountPath: /usr/src workingDir: /usr/src command: - sonar-scanner - "-Dsonar.projectKey=$PROJECT_KEY" - "-Dsonar.projectName=$PROJECT_NAME" - "-Dsonar.sources=." volumes: - name: source-code persistentVolumeClaim: claimName: source-code-pvc restartPolicy: Never EOF

Apply the job

kubectl apply -f /tmp/scanner-job.yaml echo "SonarQube scan job created for project: $PROJECT_NAME"

Monitor job status

echo "Monitoring scan progress..." kubectl wait --for=condition=complete job/sonar-scan-$(date +%s) -n sonarqube --timeout=600s
chmod +x scan-workflow.sh

Verify your setup

Check that all components are running correctly and SonarQube is accessible for code analysis.

# Check all pods are running
kubectl get pods -n sonarqube

Check services and endpoints

kubectl get svc -n sonarqube

Get SonarQube external IP or LoadBalancer status

kubectl get svc sonarqube-sonarqube -n sonarqube

Check persistent volumes

kubectl get pv,pvc -n sonarqube

View SonarQube logs

kubectl logs -l app=sonarqube -n sonarqube --tail=50

Test database connection

kubectl exec -it postgresql-0 -n sonarqube -- psql -U sonarqube -d sonarqube -c "SELECT version();"

Port forward to access SonarQube UI locally (if LoadBalancer not available)

kubectl port-forward svc/sonarqube-sonarqube 9000:9000 -n sonarqube

Access SonarQube at http://localhost:9000 (or your LoadBalancer IP) with default credentials admin/admin. Change the password immediately after first login.

Common issues

Symptom Cause Fix
SonarQube pod stuck in pending Insufficient resources or PVC not bound kubectl describe pod -n sonarqube and check resource requests vs cluster capacity
Database connection failed Wrong PostgreSQL credentials or service name Verify postgresql service: kubectl get svc postgresql -n sonarqube
Scanner job fails with 401 Invalid or missing SonarQube token Generate new token in SonarQube UI: Administration > Security > Users > Tokens
Out of memory errors in scanner Large codebase exceeds scanner memory Increase scanner pod memory: resources.limits.memory: 4Gi in job spec
Persistent volumes not mounting StorageClass not available or misconfigured Check available storage classes: kubectl get storageclass
LoadBalancer IP pending forever Cloud provider doesn't support LoadBalancer Change service type to NodePort or configure Ingress controller

Next steps

Automated install script

Run this to automate the entire setup

Need help?

Don't want to manage this yourself?

We handle managed devops services for businesses that depend on uptime. From initial setup to ongoing operations.