Complete Guide: Setting Up SonarQube with PostgreSQL Using Docker

Master the setup of SonarQube with PostgreSQL backend using Docker and Docker Compose. Learn step-by-step configuration, troubleshooting, production optimization, and best practices for code quality analysis.

Complete Guide: Setting Up SonarQube with PostgreSQL Using Docker

Table of Contents

Introduction

SonarQube is an industry-leading static code analysis platform that continuously inspects code quality, detects bugs, security vulnerabilities, and code smells across multiple programming languages. When combined with a robust PostgreSQL database backend and Docker containerization, it creates a powerful, scalable solution for maintaining code quality in development teams.

This comprehensive guide will walk you through setting up a production-ready SonarQube instance with PostgreSQL using Docker and Docker Compose. We’ll cover everything from basic setup to advanced configuration, monitoring, and production deployment strategies.

Why SonarQube with PostgreSQL?

Benefits of This Stack

SonarQube Advantages:

  • Multi-language Support: Analyzes 25+ programming languages
  • Comprehensive Analysis: Detects bugs, vulnerabilities, code smells, and technical debt
  • Quality Gates: Automated pass/fail criteria for code quality
  • IDE Integration: Real-time feedback during development
  • DevOps Integration: Seamless CI/CD pipeline integration

PostgreSQL Benefits:

  • ACID Compliance: Ensures data integrity and consistency
  • Scalability: Handles large datasets efficiently
  • Performance: Optimized for read-heavy workloads
  • Reliability: Battle-tested in production environments
  • Advanced Features: JSON support, full-text search, and complex queries

Docker Advantages:

  • Consistency: Identical environments across development, staging, and production
  • Isolation: Containerized services prevent conflicts
  • Scalability: Easy horizontal and vertical scaling
  • Portability: Deploy anywhere Docker runs
  • Maintenance: Simplified updates and rollbacks

Prerequisites and System Requirements

Hardware Requirements

Minimum Requirements:

  • RAM: 4GB (2GB for SonarQube + 2GB for PostgreSQL)
  • Storage: 10GB free space for data persistence
  • CPU: 2 cores minimum (4 cores recommended)

Recommended for Production:

  • RAM: 8GB or more
  • Storage: SSD with 50GB+ for optimal performance
  • CPU: 4+ cores for better analysis performance

Software Prerequisites

Required Software:

  • Docker Engine 20.10+ or Docker Desktop
  • Docker Compose 1.27+ (or docker-compose plugin)
  • Operating System: Linux, macOS, or Windows with WSL2

Network Requirements:

  • Port 9000 available for SonarQube web interface
  • Port 5432 available for PostgreSQL (if exposing externally)
  • Internet access for downloading Docker images

Pre-installation Checks

Verify your environment meets the requirements:

# Check Docker installation
docker --version
docker-compose --version

# Check available memory
free -h

# Check available disk space
df -h

# Check port availability
netstat -tuln | grep -E ':9000|:5432'

Understanding the Architecture

Component Overview

SonarQube Server: The main application server that provides the web interface, processes analysis results, and manages projects and users.

PostgreSQL Database: Stores all SonarQube data including:

  • Project configurations and metrics
  • Analysis results and history
  • User accounts and permissions
  • Quality gate definitions
  • Plugin configurations

Docker Volumes: Persistent storage for:

  • SonarQube data directory
  • PostgreSQL data files
  • SonarQube extensions and plugins
  • Application logs

Network Architecture

[Client Browser] → [Port 9000] → [SonarQube Container]
                                        ↓
                              [Internal Network]
                                        ↓
                                [PostgreSQL Container]

Step 1: Project Structure Setup

Creating the Project Directory

Organize your SonarQube deployment with a proper directory structure:

# Create project directory
mkdir sonarqube-docker
cd sonarqube-docker

# Create subdirectories for organization
mkdir -p {config,scripts,backups}

# Create environment configuration
touch .env docker-compose.yml

Environment Variables Configuration

Create .env file for secure credential management:

# Database Configuration
POSTGRES_USER=sonar
POSTGRES_PASSWORD=sonar_secure_password_2024
POSTGRES_DB=sonarqube

# SonarQube Configuration
SONAR_VERSION=community
SONAR_JDBC_USERNAME=sonar
SONAR_JDBC_PASSWORD=sonar_secure_password_2024
SONAR_JDBC_URL=jdbc:postgresql://db:5432/sonarqube

# Network Configuration
SONAR_PORT=9000
POSTGRES_PORT=5432

# Resource Limits
SONAR_MEMORY=2g
POSTGRES_MEMORY=1g

Security Note: Use strong, unique passwords in production and consider using Docker secrets for enhanced security.

Step 2: Docker Compose Configuration

Complete Docker Compose Setup

Create docker-compose.yml with comprehensive configuration:

version: "3.8"

services:
  sonarqube:
    image: sonarqube:${SONAR_VERSION:-community}
    container_name: sonarqube
    hostname: sonarqube
    depends_on:
      db:
        condition: service_healthy
    ports:
      - "${SONAR_PORT:-9000}:9000"
    environment:
      SONAR_JDBC_URL: ${SONAR_JDBC_URL}
      SONAR_JDBC_USERNAME: ${SONAR_JDBC_USERNAME}
      SONAR_JDBC_PASSWORD: ${SONAR_JDBC_PASSWORD}
      SONAR_ES_BOOTSTRAP_CHECKS_DISABLE: true
    volumes:
      - sonarqube_data:/opt/sonarqube/data
      - sonarqube_extensions:/opt/sonarqube/extensions
      - sonarqube_logs:/opt/sonarqube/logs
      - sonarqube_conf:/opt/sonarqube/conf
    ulimits:
      nofile:
        soft: 65536
        hard: 65536
    deploy:
      resources:
        limits:
          memory: ${SONAR_MEMORY:-2g}
        reservations:
          memory: 1g
    restart: unless-stopped
    networks:
      - sonarqube-network

  db:
    image: postgres:15-alpine
    container_name: sonarqube_db
    hostname: sonarqube-db
    environment:
      POSTGRES_USER: ${POSTGRES_USER}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
      POSTGRES_DB: ${POSTGRES_DB}
      POSTGRES_INITDB_ARGS: "--encoding=UTF8 --locale=C"
    volumes:
      - postgresql_data:/var/lib/postgresql/data
      - ./config/init-db.sql:/docker-entrypoint-initdb.d/init-db.sql:ro
    ports:
      - "${POSTGRES_PORT:-5432}:5432"
    deploy:
      resources:
        limits:
          memory: ${POSTGRES_MEMORY:-1g}
        reservations:
          memory: 512m
    restart: unless-stopped
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]
      interval: 30s
      timeout: 10s
      retries: 5
      start_period: 30s
    networks:
      - sonarqube-network

volumes:
  sonarqube_data:
    driver: local
  sonarqube_extensions:
    driver: local
  sonarqube_logs:
    driver: local
  sonarqube_conf:
    driver: local
  postgresql_data:
    driver: local

networks:
  sonarqube-network:
    driver: bridge
    ipam:
      config:
        - subnet: 172.20.0.0/16

Configuration Breakdown

Service Dependencies: The depends_on with condition: service_healthy ensures SonarQube waits for PostgreSQL to be fully ready.

Health Checks: PostgreSQL health check verifies database readiness before starting dependent services.

Resource Limits: Memory limits prevent containers from consuming excessive system resources.

Ulimits: Increased file descriptor limits for SonarQube’s Elasticsearch component.

Networks: Custom network provides isolated communication between services.

Restart Policies: unless-stopped ensures containers restart automatically unless manually stopped.

Step 3: Database Initialization

Optional Database Initialization Script

Create config/init-db.sql for custom database setup:

-- Create additional schemas if needed
CREATE SCHEMA IF NOT EXISTS sonar_extensions;

-- Set optimal PostgreSQL settings for SonarQube
ALTER SYSTEM SET shared_preload_libraries = 'pg_stat_statements';
ALTER SYSTEM SET max_connections = 200;
ALTER SYSTEM SET shared_buffers = '256MB';
ALTER SYSTEM SET effective_cache_size = '1GB';
ALTER SYSTEM SET maintenance_work_mem = '64MB';
ALTER SYSTEM SET checkpoint_completion_target = 0.9;
ALTER SYSTEM SET wal_buffers = '16MB';
ALTER SYSTEM SET default_statistics_target = 100;
ALTER SYSTEM SET random_page_cost = 1.1;

-- Create a monitoring user (optional)
CREATE USER sonar_monitor WITH PASSWORD 'monitor_password';
GRANT CONNECT ON DATABASE sonarqube TO sonar_monitor;
GRANT USAGE ON SCHEMA public TO sonar_monitor;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO sonar_monitor;

-- Add comments for documentation
COMMENT ON DATABASE sonarqube IS 'SonarQube application database';

Step 4: Deployment and Startup

Starting the Services

Deploy your SonarQube stack using Docker Compose:

# Start services in detached mode
docker-compose up -d

# View startup logs
docker-compose logs -f

# Check service status
docker-compose ps

Monitoring Startup Process

Watch the logs to ensure proper startup:

# Monitor SonarQube startup
docker-compose logs -f sonarqube

# Monitor PostgreSQL startup
docker-compose logs -f db

# Check resource usage
docker stats sonarqube sonarqube_db

Expected Startup Sequence:

  1. PostgreSQL container starts and initializes database
  2. Health check confirms PostgreSQL is ready
  3. SonarQube starts and connects to database
  4. SonarQube web interface becomes available

Verification Steps

Verify successful deployment:

# Check container status
docker-compose ps

# Test database connectivity
docker-compose exec db psql -U sonar -d sonarqube -c "\l"

# Test SonarQube web interface
curl -I http://localhost:9000

# Check SonarQube system status
curl http://localhost:9000/api/system/status

Step 5: Initial Configuration

First-Time Setup

1. Access Web Interface

  • Open browser to http://localhost:9000
  • Wait for initial setup to complete (may take 2-3 minutes)

2. Default Credentials

  • Username: admin
  • Password: admin

3. Mandatory Password Change

  • You’ll be prompted to change the default password
  • Use a strong password following security best practices

4. Setup Wizard

  • Follow the initial setup wizard
  • Configure organization settings
  • Set up your first project

Admin Configuration Tasks

Security Configuration:

# Access SonarQube container for advanced configuration
docker-compose exec sonarqube bash

# View SonarQube configuration
cat /opt/sonarqube/conf/sonar.properties

Database Verification:

# Connect to PostgreSQL to verify schema creation
docker-compose exec db psql -U sonar -d sonarqube

# List SonarQube tables
\dt

# Check database size
SELECT pg_size_pretty(pg_database_size('sonarqube'));

Troubleshooting Common Issues

Issue 1: Database Connection Failures

Symptoms: SonarQube fails to start with database connection errors.

Common Causes and Solutions:

1. PostgreSQL Not Ready

# Check PostgreSQL logs
docker-compose logs db

# Verify health check status
docker-compose ps

# Manual connection test
docker-compose exec db pg_isready -U sonar

2. Incorrect Credentials

# Verify environment variables
docker-compose config

# Check database user exists
docker-compose exec db psql -U postgres -c "\du"

3. Network Issues

# Check network connectivity
docker-compose exec sonarqube ping db

# Verify DNS resolution
docker-compose exec sonarqube nslookup db

Issue 2: Memory and Performance Issues

Symptoms: Slow startup, frequent crashes, or out-of-memory errors.

Solutions:

1. Increase Memory Allocation

# In docker-compose.yml
deploy:
  resources:
    limits:
      memory: 4g
    reservations:
      memory: 2g

2. Elasticsearch Configuration

# Set VM max map count (Linux)
sudo sysctl -w vm.max_map_count=262144

# Make permanent
echo 'vm.max_map_count=262144' >> /etc/sysctl.conf

3. Monitor Resource Usage

# Real-time monitoring
docker stats sonarqube sonarqube_db

# Memory usage breakdown
docker-compose exec sonarqube free -h

Issue 3: Port Conflicts

Symptoms: Cannot bind to ports 9000 or 5432.

Solutions:

1. Check Port Usage

# Find processes using ports
sudo netstat -tulpn | grep -E ':9000|:5432'
sudo lsof -i :9000
sudo lsof -i :5432

2. Change Ports

# In .env file
SONAR_PORT=9001
POSTGRES_PORT=5433

Issue 4: Volume Permission Issues

Symptoms: Permission denied errors when accessing volumes.

Solutions:

1. Fix Volume Permissions

# Check volume ownership
docker-compose exec sonarqube ls -la /opt/sonarqube/

# Fix permissions if needed
sudo chown -R 999:999 /var/lib/docker/volumes/sonarqube-docker_sonarqube_data

2. SELinux Issues (RHEL/CentOS)

# Set SELinux context
sudo setsebool -P container_manage_cgroup on

Advanced Configuration

Production Optimization

1. Reverse Proxy Configuration

Create nginx.conf for SSL termination:

upstream sonarqube {
    server localhost:9000;
}

server {
    listen 80;
    server_name sonarqube.yourcompany.com;
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    server_name sonarqube.yourcompany.com;

    ssl_certificate /path/to/certificate.crt;
    ssl_certificate_key /path/to/private.key;

    location / {
        proxy_pass http://sonarqube;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

2. Database Performance Tuning

Create config/postgresql.conf:

# Memory settings
shared_buffers = 512MB
effective_cache_size = 2GB
work_mem = 16MB
maintenance_work_mem = 128MB

# Checkpoint settings
checkpoint_completion_target = 0.9
checkpoint_timeout = 15min

# WAL settings
wal_buffers = 16MB
wal_level = replica

# Query planner settings
random_page_cost = 1.1
default_statistics_target = 100

3. Backup and Recovery

Create backup script scripts/backup.sh:

#!/bin/bash

BACKUP_DIR="/backups"
DATE=$(date +%Y%m%d_%H%M%S)

# Create backup directory
mkdir -p $BACKUP_DIR

# Backup PostgreSQL database
docker-compose exec -T db pg_dump -U sonar sonarqube | gzip > $BACKUP_DIR/sonarqube_db_$DATE.sql.gz

# Backup SonarQube data
docker-compose exec -T sonarqube tar czf - /opt/sonarqube/data > $BACKUP_DIR/sonarqube_data_$DATE.tar.gz

# Cleanup old backups (keep 7 days)
find $BACKUP_DIR -name "*.gz" -mtime +7 -delete

echo "Backup completed: $DATE"

Monitoring and Maintenance

Health Monitoring

1. Container Health Checks

# Monitor container health
watch docker-compose ps

# Check system resources
docker-compose exec sonarqube cat /proc/meminfo
docker-compose exec db cat /proc/meminfo

2. Application Monitoring

# SonarQube system status
curl http://localhost:9000/api/system/status

# Database connection count
docker-compose exec db psql -U sonar -d sonarqube -c "SELECT count(*) FROM pg_stat_activity;"

# Check SonarQube logs for errors
docker-compose logs sonarqube | grep -i error

Regular Maintenance Tasks

1. Database Maintenance

-- Vacuum and analyze database
VACUUM ANALYZE;

-- Check database size
SELECT pg_size_pretty(pg_database_size('sonarqube'));

-- Monitor table sizes
SELECT schemaname,tablename,attname,n_distinct,correlation
FROM pg_stats WHERE schemaname = 'public';

2. Log Rotation

# Setup logrotate for Docker logs
cat > /etc/logrotate.d/docker << EOF
/var/lib/docker/containers/*/*.log {
    rotate 7
    daily
    compress
    missingok
    delaycompress
    copytruncate
}
EOF

Upgrading SonarQube

1. Backup Before Upgrade

# Stop services
docker-compose down

# Create backup
./scripts/backup.sh

# Update version in .env
echo "SONAR_VERSION=9.9-community" >> .env

2. Perform Upgrade

# Pull new images
docker-compose pull

# Start with new version
docker-compose up -d

# Monitor upgrade process
docker-compose logs -f sonarqube

Security Best Practices

Access Control

1. Database Security

  • Use strong, unique passwords
  • Limit PostgreSQL network access
  • Enable SSL for database connections in production

2. SonarQube Security

  • Change default admin credentials immediately
  • Configure proper user authentication (LDAP/SAML)
  • Enable force user authentication
  • Configure proper project permissions

3. Network Security

  • Use reverse proxy with SSL/TLS
  • Implement firewall rules
  • Use private networks for internal communication

Secrets Management

1. Docker Secrets (Swarm Mode)

version: "3.8"
services:
  sonarqube:
    image: sonarqube:community
    secrets:
      - sonar_db_password
    environment:
      SONAR_JDBC_PASSWORD_FILE: /run/secrets/sonar_db_password

secrets:
  sonar_db_password:
    external: true

2. External Secret Management

  • Use HashiCorp Vault for enterprise environments
  • Implement credential rotation policies
  • Monitor secret access and usage

Conclusion

Setting up SonarQube with PostgreSQL using Docker provides a robust, scalable foundation for continuous code quality analysis. This containerized approach offers several key advantages:

  • Consistency: Identical environments across all stages of deployment
  • Scalability: Easy horizontal scaling for growing teams
  • Maintainability: Simplified updates and dependency management
  • Reliability: Battle-tested components with proper health checks and restart policies

The configuration presented in this guide provides a production-ready setup that can be adapted for various environments, from local development to enterprise production deployments.

Remember to regularly monitor your SonarQube instance, perform maintenance tasks, and keep both SonarQube and PostgreSQL updated to the latest stable versions for optimal security and performance.

By following the practices outlined in this guide, you’ll have a robust code quality analysis platform that helps maintain high standards across your development projects while providing valuable insights into code health and technical debt.

Additional Resources

Table of Contents