SonarQube Kurulumu ve Kod Kalitesi Analizi

Kod kalitesi meselesi çoğu zaman “sonra hallederiz” kategorisine giriyor. Sprint baskısı var, deadline yaklaşıyor, feature çıkması lazım. Sonunda teknik borç birikmeye başlıyor ve bir gün bakıyorsunuz ki codebase’in yarısı kimsenin dokunmak istemediği karanlık bir bölgeye dönmüş. SonarQube tam da bu noktada devreye giriyor; size hem anlık bir rapor hem de uzun vadeli kod sağlığı takibi sunuyor. Ben de bu yazıda sıfırdan kurulumdan gerçek anlamda kullanışlı bir analiz ortamı kurmaya kadar her şeyi aktaracağım.

SonarQube Nedir, Ne Değildir

Önce şunu netleştirelim: SonarQube bir sihir değil. Kodu sizin yerinize temizlemiyor, mimari kararlarınızı vermiyor. Ama şunları yapıyor: bug potansiyeli taşıyan kod bloklarını işaretliyor, güvenlik açıklarını (vulnerability) ve güvenlik hotspot’larını raporluyor, kod tekrarını (duplication) ölçüyor, test coverage’ınızı görselleştiriyor ve teknik borcu sayısal olarak ifade ediyor.

Community Edition ücretsiz ve birçok dil için yeterli. Java, JavaScript, TypeScript, Python, C#, PHP, Go ve daha fazlasını destekliyor. Enterprise ihtiyaçlarınız varsa Developer veya Enterprise Edition’a geçebilirsiniz ama çoğu ekip için Community Edition başlangıç için fazlasıyla yeterli.

Sistem Gereksinimleri

SonarQube, Elasticsearch üzerine kurulu olduğu için kaynak gereksinimlerine dikkat etmek gerekiyor. Kurulum öncesi şunlara bakın:

  • RAM: Minimum 2 GB, önerilen 4 GB. Elasticsearch tek başına 512 MB ile 2 GB arasında bellek kullanıyor.
  • CPU: 2 core yeterli başlangıç için, yoğun analiz ortamında 4 core önerilir.
  • Disk: Proje sayısına göre değişir, başlangıç için 20 GB yeterli.
  • Java: SonarQube 10.x sürümleri JDK 17 gerektiriyor.
  • Veritabanı: PostgreSQL 13+ önerilen. H2 embedded sadece test için kullanılmalı, production’da kesinlikle kullanmayın.
  • OS: Linux için vm.max_map_count ve fs.file-max değerlerini ayarlamak şart.

Sistem Hazırlığı

Önce kernel parametrelerini ayarlayalım. Bu adımı atladığınızda Elasticsearch başlamıyor:

# /etc/sysctl.conf dosyasına ekleyin
sudo sysctl -w vm.max_map_count=524288
sudo sysctl -w fs.file-max=131072

# Kalıcı hale getirmek için
echo "vm.max_map_count=524288" | sudo tee -a /etc/sysctl.conf
echo "fs.file-max=131072" | sudo tee -a /etc/sysctl.conf
sudo sysctl -p

Kullanıcı limitleri için /etc/security/limits.conf dosyasına şunları ekleyin:

sudo tee -a /etc/security/limits.conf << 'EOF'
sonarqube   -   nofile   131072
sonarqube   -   nproc    8192
EOF

SonarQube için ayrı bir kullanıcı oluşturun, root ile çalıştırmayın:

sudo useradd -r -m -U -d /opt/sonarqube -s /bin/bash sonarqube

PostgreSQL Kurulumu ve Yapılandırması

# Ubuntu/Debian için
sudo apt update
sudo apt install -y postgresql postgresql-contrib

sudo systemctl enable postgresql
sudo systemctl start postgresql

# Veritabanı ve kullanıcı oluşturma
sudo -u postgres psql << 'EOF'
CREATE USER sonarqube WITH ENCRYPTED PASSWORD 'guclu_bir_sifre_koyun';
CREATE DATABASE sonarqube OWNER sonarqube;
GRANT ALL PRIVILEGES ON DATABASE sonarqube TO sonarqube;
EOF

SonarQube Kurulumu

En güncel Community Edition sürümünü indirip kuralım:

SONAR_VERSION="10.4.1.88267"

cd /tmp
wget https://binaries.sonarsource.com/Distribution/sonarqube/sonarqube-${SONAR_VERSION}.zip

sudo apt install -y unzip
sudo unzip sonarqube-${SONAR_VERSION}.zip -d /opt
sudo mv /opt/sonarqube-${SONAR_VERSION} /opt/sonarqube

# Sahipliği sonarqube kullanıcısına ver
sudo chown -R sonarqube:sonarqube /opt/sonarqube

Şimdi temel yapılandırmayı yapalım. /opt/sonarqube/conf/sonar.properties dosyasını düzenleyin:

sudo -u sonarqube tee /opt/sonarqube/conf/sonar.properties << 'EOF'
# Veritabanı bağlantısı
sonar.jdbc.username=sonarqube
sonar.jdbc.password=guclu_bir_sifre_koyun
sonar.jdbc.url=jdbc:postgresql://localhost:5432/sonarqube

# Web sunucu ayarları
sonar.web.host=0.0.0.0
sonar.web.port=9000
sonar.web.context=/

# Elasticsearch
sonar.search.javaOpts=-Xmx512m -Xms512m -XX:MaxDirectMemorySize=256m

# Web JVM
sonar.web.javaOpts=-Xmx512m -Xms128m

# Compute Engine
sonar.ce.javaOpts=-Xmx512m -Xms128m

# Log dizini
sonar.path.logs=logs
sonar.path.data=data
sonar.path.temp=temp
EOF

Systemd Servisi Oluşturma

sudo tee /etc/systemd/system/sonarqube.service << 'EOF'
[Unit]
Description=SonarQube service
After=syslog.target network.target postgresql.service

[Service]
Type=forking
ExecStart=/opt/sonarqube/bin/linux-x86-64/sonar.sh start
ExecStop=/opt/sonarqube/bin/linux-x86-64/sonar.sh stop
User=sonarqube
Group=sonarqube
Restart=always
LimitNOFILE=131072
LimitNPROC=8192

[Install]
WantedBy=multi-user.target
EOF

sudo systemctl daemon-reload
sudo systemctl enable sonarqube
sudo systemctl start sonarqube

Başlamasını bekleyin, Elasticsearch yüzünden ilk açılış 2-3 dakika sürebilir:

# Log takibi
sudo tail -f /opt/sonarqube/logs/sonar.log
sudo tail -f /opt/sonarqube/logs/web.log

# Servis durumu
sudo systemctl status sonarqube

Kurulum başarılıysa http://sunucu_ip:9000 adresine gidin. Varsayılan kullanıcı adı ve şifre admin/admin. İlk girişte şifre değiştirmenizi isteyecek, bunu kesinlikle yapın.

Nginx ile Ters Proxy Yapılandırması

Production ortamında SonarQube’u direkt 9000 portunda açık bırakmak yerine Nginx arkasına almak daha doğru:

sudo apt install -y nginx

sudo tee /etc/nginx/sites-available/sonarqube << 'EOF'
server {
    listen 80;
    server_name sonar.sirketiniz.com;

    # HTTP'yi HTTPS'ye yönlendir
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl;
    server_name sonar.sirketiniz.com;

    ssl_certificate /etc/letsencrypt/live/sonar.sirketiniz.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/sonar.sirketiniz.com/privkey.pem;

    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;

    client_max_body_size 50M;

    location / {
        proxy_pass http://localhost:9000;
        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;
        proxy_connect_timeout 300;
        proxy_send_timeout 300;
        proxy_read_timeout 300;
    }
}
EOF

sudo ln -s /etc/nginx/sites-available/sonarqube /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx

SonarScanner Kurulumu

SonarQube sunucusu hazır, şimdi analizi çalıştıracak aracı kuralım. SonarScanner’ı kod analizi yapılacak makinelere veya CI/CD agent’larına kuruyoruz:

SCANNER_VERSION="5.0.1.3006"

cd /tmp
wget https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-${SCANNER_VERSION}-linux.zip
unzip sonar-scanner-cli-${SCANNER_VERSION}-linux.zip
sudo mv sonar-scanner-${SCANNER_VERSION}-linux /opt/sonar-scanner

# PATH'e ekle
echo 'export PATH=$PATH:/opt/sonar-scanner/bin' | sudo tee /etc/profile.d/sonar-scanner.sh
source /etc/profile.d/sonar-scanner.sh

# Test
sonar-scanner --version

İlk Proje Analizi

Bir Java Maven projesi için örnek sonar-project.properties dosyası:

# Proje kimliği - SonarQube'da görünecek isim
sonar.projectKey=my-java-app
sonar.projectName=My Java Application
sonar.projectVersion=1.0

# Kaynak kodun yolu
sonar.sources=src/main/java
sonar.tests=src/test/java

# Java için bytecode yolu (coverage için gerekli)
sonar.java.binaries=target/classes
sonar.java.test.binaries=target/test-classes

# JaCoCo coverage raporu
sonar.coverage.jacoco.xmlReportPaths=target/site/jacoco/jacoco.xml

# Encoding
sonar.sourceEncoding=UTF-8

# SonarQube sunucu adresi
sonar.host.url=https://sonar.sirketiniz.com

Analizi çalıştırmak için:

# Token ile kimlik doğrulama (önerilen yöntem)
sonar-scanner 
  -Dsonar.projectKey=my-java-app 
  -Dsonar.sources=. 
  -Dsonar.host.url=https://sonar.sirketiniz.com 
  -Dsonar.token=sqp_xxxxxxxxxxxxxxxxxxxxxxxxx

GitLab CI Entegrasyonu

Gerçek hayatta analizi elle çalıştırmıyorsunuz. CI/CD pipeline’ınıza entegre etmek asıl hedef. İşte GitLab CI için bir .gitlab-ci.yml örneği:

stages:
  - build
  - test
  - sonar-analysis

variables:
  MAVEN_OPTS: "-Dmaven.repo.local=$CI_PROJECT_DIR/.m2/repository"
  SONAR_USER_HOME: "${CI_PROJECT_DIR}/.sonar"

cache:
  paths:
    - .m2/repository
    - .sonar/cache

build:
  stage: build
  image: maven:3.9-eclipse-temurin-17
  script:
    - mvn compile

test:
  stage: test
  image: maven:3.9-eclipse-temurin-17
  script:
    - mvn test jacoco:report
  artifacts:
    paths:
      - target/

sonar-analysis:
  stage: sonar-analysis
  image: maven:3.9-eclipse-temurin-17
  script:
    - mvn sonar:sonar
      -Dsonar.projectKey=$CI_PROJECT_NAME
      -Dsonar.host.url=$SONAR_HOST_URL
      -Dsonar.token=$SONAR_TOKEN
      -Dsonar.coverage.jacoco.xmlReportPaths=target/site/jacoco/jacoco.xml
  only:
    - main
    - merge_requests

GitLab’da SONAR_HOST_URL ve SONAR_TOKEN değişkenlerini Settings > CI/CD > Variables altına ekleyin. Token’ı SonarQube arayüzünden My Account > Security > Generate Tokens bölümünden alabilirsiniz. Token’ı protected ve masked olarak işaretlemeyi unutmayın.

Quality Gate Yapılandırması

Quality Gate, analizin “geçti mi geçmedi mi” kararını veren kural setidir. Varsayılan “Sonar way” gate’ini production için biraz sıkılaştırabilirsiniz. SonarQube arayüzünden Quality Gates > Create ile yeni bir gate oluşturun.

Tipik bir production Quality Gate kriterleri şöyle olabilir:

  • Coverage on New Code: 80%’den az ise başarısız
  • Duplicated Lines on New Code: 3%’den fazla ise başarısız
  • Maintainability Rating on New Code: A veya B değilse başarısız
  • Reliability Rating on New Code: A değilse başarısız
  • Security Rating on New Code: A değilse başarısız
  • Security Hotspots Reviewed on New Code: 100% değilse başarısız

“New Code” kavramı önemli: SonarQube, son analiz tarihinden itibaren değişen satırları yeni kod olarak değerlendiriyor. Bu sayede legacy bir projeyi baştan mükemmel yapmaya çalışmak yerine, sadece yeni yazdığınız kodun kalitesini korumak üzerine odaklanabiliyorsunuz. Hem daha gerçekçi hem de ekip motivasyonu açısından çok daha sağlıklı bir yaklaşım.

Önemli Güvenlik Ayarları

Kurulumu bitirdikten sonra bazı güvenlik adımları şart:

# Anonim erişimi kapatın - sonar.properties dosyasına ekleyin
echo "sonar.forceAuthentication=true" >> /opt/sonarqube/conf/sonar.properties

# Servis tokenları için ayrı hesaplar oluşturun
# Administration > Security > Users bölümünden
# "ci-bot" gibi bir service account oluşturun
# ve bu hesaba sadece "Execute Analysis" yetkisi verin

sudo systemctl restart sonarqube

SonarQube’u internet’e açık tutuyorsanız, arayüzde Administration > Security bölümünden şunları kontrol edin:

  • Force user authentication: Açık olmalı
  • Anyone group: Hiçbir şeye erişimi olmamalı
  • Default admin şifresi değiştirilmiş olmalı

Performans Sorunlarında Yapılacaklar

Ekip büyüdükçe ve proje sayısı arttıkça SonarQube yavaşlayabiliyor. Yaşadığım senaryolarda şu çözümler işe yaradı:

Compute Engine queue’u doluyorsa (Administration > Projects > Background Tasks) birden fazla CE worker açabilirsiniz. Bunun için lisans gerekiyor ancak şunu da yapabilirsiniz: büyük projeleri gece analiz edilecek şekilde schedule’layın, küçük projeleri gündüz.

Elasticsearch disk I/O problemi sık karşılaşılan bir durum. Mümkünse SonarQube data dizinini SSD’ye alın:

# sonar.properties dosyasında data dizinini değiştirin
sonar.path.data=/mnt/ssd-disk/sonarqube/data
sonar.path.temp=/mnt/ssd-disk/sonarqube/temp

# Dizinleri oluşturun ve izinleri ayarlayın
sudo mkdir -p /mnt/ssd-disk/sonarqube/{data,temp}
sudo chown -R sonarqube:sonarqube /mnt/ssd-disk/sonarqube

Log rotasyonu için /opt/sonarqube/conf/sonar.properties dosyasına:

# Log seviyeleri - production'da INFO yeterli
sonar.log.level=INFO
sonar.log.level.web=INFO
sonar.log.level.ce=INFO
sonar.log.level.es=INFO

# Log rotation - her biri max 20MB, 5 dosya tut
sonar.log.maxFiles=5
sonar.log.maxFileSize=20MB

Docker ile Hızlı Test Ortamı

Production’a geçmeden önce ya da geliştirici makinelerinde hızlıca denemek için Docker Compose kullanabilirsiniz:

# docker-compose.yml
version: "3.8"

services:
  sonarqube:
    image: sonarqube:10.4-community
    container_name: sonarqube
    depends_on:
      - sonarqube-db
    environment:
      SONAR_JDBC_URL: jdbc:postgresql://sonarqube-db:5432/sonar
      SONAR_JDBC_USERNAME: sonar
      SONAR_JDBC_PASSWORD: sonar
    volumes:
      - sonarqube_data:/opt/sonarqube/data
      - sonarqube_logs:/opt/sonarqube/logs
      - sonarqube_extensions:/opt/sonarqube/extensions
    ports:
      - "9000:9000"
    ulimits:
      nofile:
        soft: 131072
        hard: 131072

  sonarqube-db:
    image: postgres:15
    container_name: sonarqube-db
    environment:
      POSTGRES_USER: sonar
      POSTGRES_PASSWORD: sonar
      POSTGRES_DB: sonar
    volumes:
      - sonarqube_db:/var/lib/postgresql/data

volumes:
  sonarqube_data:
  sonarqube_logs:
  sonarqube_extensions:
  sonarqube_db:
# vm.max_map_count ayarını unutmayın, Docker için de gerekli
sudo sysctl -w vm.max_map_count=524288

docker-compose up -d
docker-compose logs -f sonarqube

Sonuç

SonarQube’u kurmak aslında hikayenin küçük bir parçası. Asıl mesele ekibin bu aracı benimsemesi ve Quality Gate kriterlerini ciddiye alması. “Analiz kırmızı ama biz yine de merge ettik” durumu yaşanmaya başlarsa, tool’un hiçbir değeri kalmıyor.

Benim önerim şu: ilk kurulumda Quality Gate’i çok sıkı tutmayın. Mevcut projeyi sıfır hata ile geçirecek şekilde ayarlayın, sonra her sprint’te biraz daha sıkılaştırın. Ekip “kalite = engel” yerine “kalite = standart” olarak görmeye başladığında iş değişiyor.

Teknik borç raporlamasını sprint planning toplantılarına dahil edin. “Bu sprint 2 gün teknik borç ödeyeceğiz” diyebilmek için önce onu sayısal olarak görebilmeniz gerekiyor. SonarQube bunu sağlıyor. Geri kalanı ekip kültürü meselesi.

Son bir not: sürüm güncellemelerini takip edin. SonarQube güvenlik yamaları ve dil desteği güncellemeleri açısından sık güncelleniyor. Her major versiyon upgrade öncesi mutlaka backup alın; PostgreSQL dump’ı ve SonarQube data dizininin yedeği hayat kurtarıyor.

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir