SonarQube GitLab 연동 (react, springboot)

2026. 1. 13. 17:18[오픈소스_라이브러리]

728x90
반응형

전체 구성 요약

  • SonarQube 서버 (Docker Compose): SonarQube + PostgreSQL + Nginx(HTTPS Reverse Proxy)
    • 접속: https://<SONAR_HOST>/
    • 서버 접근 계정: <SONAR_SERVER_USER> / <SONAR_SERVER_PASSWORD>
  • GitLab 서버: GitLab CE <GITLAB_VERSION> (http://<GITLAB_HOST>:<GITLAB_PORT>/)
  • GitLab Runner (Docker): GitLab CI Job 실행 담당 (Docker executor)
    • 설치 위치: GitLab 서버 동일(또는 별도 서버)
  • Spring Boot 프로젝트: .gitlab-ci.yml로 Maven 분석 실행 → SonarQube로 결과 업로드

 

. SonarQube 설치 (<SONAR_HOST>)

1.1 서버 사전 설정

SonarQube(내부 Elasticsearch) 때문에 리눅스 커널 파라미터 요구가 있음

#Elasticsearch(내부 검색엔진) 요구값 반영: vm.max_map_count / 파일 디스크립터 상향
$ sudo tee /etc/sysctl.d/99-sonarqube.conf > /dev/null << 'EOF'
vm.max_map_count=524288
fs.file-max=131072
EOF
 
#sysctl 설정 즉시 적용
$ sudo sysctl --system
 
# 확인용
$ sysctl vm.max_map_count
$ sysctl fs.file-max

1.2 서버에 Docker / compose 설치

$ sudo apt-get update -y
$ sudo apt-get install -y ca-certificates curl gnupg lsb-release
 
# Docker 공식 repo 등록
$ sudo install -m 0755 -d /etc/apt/keyrings curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
$ sudo chmod a+r /etc/apt/keyrings/docker.gpg
 
$ echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.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 -y
$ sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
 
$ sudo systemctl enable --now docker
 
#확인용
$ docker version
$ docker compose version

1.3 SonarQube 설치(Docker Compose + Postgres + Nginx HTTPS)

 
#SonarQube 관련 파일(nginx, certs, compose)을 표준 경로로 관리
$ sudo mkdir -p /srv/sonarqube/nginx /srv/sonarqube/certs
$ cd /srv/sonarqube
 
#sonarQube DB 비밀번호를 compose 파일에서 분리해 노출 위험 최소화
$ sudo tee /srv/sonarqube/.env > /dev/null << 'EOF'
SONAR_DB_PASSWORD="dpsxpftm@)20"
EOF
 
#권한 최소화(소유자만 읽기) - 비밀번호 파일 보호
$ sudo chmod 600 /srv/sonarqube/.env
 
#인증서 CN/SAN에 실제 SonarQube 서버 IP를 넣어 HTTPS 접속 가능하게 함
#<VM_IP> 대상 소나큐브 서버ip 를 입력 172.20.0.114
$ export VM_IP="<VM_IP>"
$ cd /srv/sonarqube/certs
 
#자체서명 인증서 생성 (1) / IP subjectAltName에 넣어 브라우저/클라이언트 호환성 확보
$ sudo openssl req -x509 -newkey rsa:2048 -sha256 -days 365 -nodes \
  -keyout sonar.key -out sonar.crt \
  -subj "/CN=${VM_IP}" \
-addext "subjectAltName=IP:${VM_IP}"
 
#Nginx 설정(HTTPS 종료 → SonarQube로 프록시)
#SonarQube는 내부 포트(9000) 외부는 HTTPS(443)만 오픈.
$ sudo tee /srv/sonarqube/nginx/sonarqube.conf > /dev/null << 'EOF'
server {
  listen 443 ssl;
  server_name _;
 
  ssl_certificate     /etc/nginx/certs/sonar.crt;
  ssl_certificate_key /etc/nginx/certs/sonar.key;
 
  ssl_protocols TLSv1.2 TLSv1.3;
 
  location / {
    proxy_pass http://sonarqube:9000;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-Proto https;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  }
}
 
server {
  listen 80;
  server_name _;
  return 301 https://$host$request_uri;
}
EOF
 
#docker-compose.yml 생성
#SonarQube + Postgres + Nginx를 한 번에 관리/기동하기 위해 compose 사용
$ sudo tee /srv/sonarqube/docker-compose.yml > /dev/null << 'EOF'
services:
  db:
    image: postgres:17
    container_name: sonarqube-db
    environment:
      POSTGRES_USER: sonar
      POSTGRES_PASSWORD: ${SONAR_DB_PASSWORD}
      POSTGRES_DB: sonar
    volumes:
      - postgresql:/var/lib/postgresql/data
    restart: unless-stopped
 
  sonarqube:
    image: sonarqube:26.1.0.118079-community
    container_name: sonarqube
    depends_on:
      - db
    environment:
      SONAR_JDBC_URL: jdbc:postgresql://db:5432/sonar
      SONAR_JDBC_USERNAME: sonar
      SONAR_JDBC_PASSWORD: ${SONAR_DB_PASSWORD}
    volumes:
      - sonarqube_data:/opt/sonarqube/data
      - sonarqube_extensions:/opt/sonarqube/extensions
      - sonarqube_logs:/opt/sonarqube/logs
      - sonarqube_temp:/opt/sonarqube/temp
    expose:
      - "9000"
    ulimits:
      nofile:
        soft: 131072
        hard: 131072
      nproc: 8192
    restart: unless-stopped
 
  nginx:
    image: nginx:alpine
    container_name: sonarqube-nginx
    depends_on:
      - sonarqube
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx/sonarqube.conf:/etc/nginx/conf.d/default.conf:ro
      - ./certs/sonar.crt:/etc/nginx/certs/sonar.crt:ro
      - ./certs/sonar.key:/etc/nginx/certs/sonar.key:ro
    restart: unless-stopped
 
volumes:
  postgresql:
  sonarqube_data:
  sonarqube_extensions:
  sonarqube_logs:
  sonarqube_temp:
EOF
 
#docker 기동
$ cd /srv/sonarqube
$ docker compose up -d
$ docker compose ps
 
#방화벽 허용(필요 시)
$ sudo ufw allow 80/tcp
$ sudo ufw allow 443/tcp
$ sudo ufw status

이후 기동테스트 172.20.0.114/

최초 접속시 비밀번호를 초기화 합니다. (최초 admin/admin)


2. GitLab Runner 설치/등록 (<GITLAB_HOST>:<GITLAB_PORT>)

2.1 Git UI로 Runner 등록

  • 태그: docker, linux
  • 토큰: 최초 1회만 표시됨 → 안전한 곳에 저장

토큰은 한번만 보여주니 최초에 저장하여 추후 사용합니다.

 

2.2 서버에서 Runner 컨테이너 실행 및 등록

 
#runner 설정 파일 저장 경로
$ sudo mkdir -p /srv/gitlab-runner/config
 
#gitlab-runner 컨테이너 실행 + 도커 소켓 공유(Docker executor)
$ docker run -d --name gitlab-runner --restart always \
  -v /srv/gitlab-runner/config:/etc/gitlab-runner \
  -v /var/run/docker.sock:/var/run/docker.sock \
gitlab/gitlab-runner:latest
 
#아래 명령어에 token 부분이 위의 ui 에서 받은 토큰의 값을 넣으면 됩니다.
$ docker exec -it gitlab-runner gitlab-runner register \
  --non-interactive \
  --url "http://192.168.110.202:8080/" \
  --token "glrt-****** " \
  --executor "docker" \
--docker-image "maven:3.9-eclipse-temurin-17"

웹페이지에서 확인하기.


3. SonarQube GitLab 연동

3.1 SonarQube에서 Local Project 생성

  • SonarQube Web UI: https://<SONAR_HOST>/

3.2 Token 발급

  • 우측 상단 프로필 → My Account → Security → Generate Token
  • 결과: <SONAR_TOKEN>

3.3 GitLab 변수 등록

프로젝트 → Settings → CI/CD → Variables

  • SONAR_HOST_URL = https://<SONAR_HOST>
  • SONAR_TOKEN = <SONAR_TOKEN>
  • SONAR_PROJECT_KEY = <SONAR_PROJECT_KEY>
  • (예: my-service-backend, my-service-frontend 등)

3.4 인증서(crt) 레포 포함

CI 컨테이너(Java)가 SonarQube HTTPS(자체서명)를 신뢰하지 못하므로, 인증서를 레포에 포함시키고 CI에서 truststore에 import함.

  • 파일 위치: .ci/sonar/sonar.crt.
  • SonarCube ssh 접속 혹은 파일질라 활용하여 해당 파일을 local 에 복사.
  •  

복사한 인증서를 springboot project root 의 해당 경로에 복사함.

3.5 Spring Boot .gitlab-ci.yml

 
stages: [analyze]
 
sonarqube_backend:
  stage: analyze
  tags: ["docker", "linux"]
  image: maven:3.9-eclipse-temurin-17
 
  variables:
    # Git history 깊이를 충분히 가져오면 Sonar 분석 품질(블레임/변경 추적)이 좋아짐
    GIT_DEPTH: "0"
 
    # Maven 로컬 저장소를 프로젝트 내부로 두어 캐시 가능하게 함(빌드 시간 단축)
    MAVEN_OPTS: "-Dmaven.repo.local=.m2/repository"
 
  cache:
    # 매번 dependency 다운로드를 방지
    paths:
      - .m2/repository
 
  before_script:
    # 인증서 파일 존재 여부/경로 확인(문제 발생 시 즉시 원인 파악)
    - ls -al .ci/sonar || true
    - test -f .ci/sonar/sonar.crt
 
    # 자체서명 인증서를 JVM truststore(cacerts) import하여 SSL 신뢰 오류 제거
    - |
      set -e
      CACERTS_1="$JAVA_HOME/lib/security/cacerts"
      CACERTS_2="/etc/ssl/certs/java/cacerts"
      for KS in "$CACERTS_1" "$CACERTS_2"; do
        if [ -f "$KS" ]; then
          echo "Importing cert into $KS"
          keytool -importcert -noprompt -alias sonarqube -file .ci/sonar/sonar.crt \
            -keystore "$KS" -storepass changeit || true
          keytool -list -keystore "$KS" -storepass changeit | grep -i sonarqube || true
        fi
      done
 
  script:
    # 테스트는 CI 환경(DB ) 의존성 때문에 실패할 수 있어 스킵
    # sonar:sonar prefix 문제 방지 위해 플러그인을 풀좌표로 호출
    - |
      mvn -B -DskipTests verify org.sonarsource.scanner.maven:sonar-maven-plugin:sonar \
        -Dsonar.host.url="${SONAR_HOST_URL}" \
        -Dsonar.projectKey="${SONAR_PROJECT_KEY}" \
        -Dsonar.token="${SONAR_TOKEN}" \
        -Dsonar.qualitygate.wait=true
 
  rules:
    # main 브랜치에만 분석 수행 (원하면 master/feature 규칙으로 확장 가능)
    - if: $CI_COMMIT_BRANCH == "main"

Commit 이후 파이프라인 확인

 

성공시 sonarQube 에서 확인 가능.


4. 동일 Runner, sonarQube 에 다른 spring 소스 올리기.

같은 서버에 다른 소스파일도 올릴 수 있습니다.

일부 설정만 바꾸면 됩니다.

4.1 SonartQube 에서 localproject 생성 및 키 생성

키는 잃어버리지 않게 저장해둡니다.

이후

3.3 / 3.4 의 과정을 따라가면 됩니다.

그리고 Runner 부분에서 할당하기 버튼으로 활성화 이후 커밋.

5. React SonarQube 연동

5.1 필요한 파일

  • .gitlab-ci.yml
  • sonar-project.properties
  • .ci/sonar/sonar.crt (백엔드와 동일 파일 사용 가능)

5.1.1 React .gitlab-ci.yml

 
stages: [analyze]

sonarqube_frontend:
  stage: analyze
  tags: ["docker", "linux"]

  # Debian
계열 + Node 20
 
image: node:20-bullseye

  variables:
    GIT_DEPTH: "0"
    # sonar-scanner
캐시를 프로젝트 내부에 두고 GitLab cache로 재사용
   
SONAR_USER_HOME: "$CI_PROJECT_DIR/.sonar"

    # (
선택) truststore 패스워드 상수화
    
TRUSTSTORE_PASS: "changeit"

  cache:
    key: sonar-cache
    paths:
      - .sonar/cache

  before_script:
    - echo "SONAR_HOST_URL=$SONAR_HOST_URL"
    - echo "SONAR_PROJECT_KEY=$SONAR_PROJECT_KEY"

    # Debian
패키지 설치 (openssl + keytool + unzip + curl)
   
- apt-get update
    - apt-get install -y --no-install-recommends ca-certificates openssl default-jre-headless unzip curl
    - update-ca-certificates

    # Node
버전 확인 (toReversed 문제 방지)
   
- node -v

    # sonar-scanner
설치 (CLI 5.0.1)
   
- |
      set -e
      SCANNER_VER="5.0.1.3006"
      curl -sSLo /tmp/sonar-scanner.zip \
        "https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-${SCANNER_VER}-linux.zip"
      unzip -q /tmp/sonar-scanner.zip -d /opt
      export PATH="/opt/sonar-scanner-${SCANNER_VER}-linux/bin:$PATH"
      sonar-scanner -v

    # (
기존 그대로) SonarQube SSL 인증서 뽑아서 truststore.p12 생성
   
- |
      set -e

      URL_NO_PROTO="${SONAR_HOST_URL#http://}"
      URL_NO_PROTO="${URL_NO_PROTO#https://}"
      HOSTPORT="${URL_NO_PROTO%%/*}"

      if echo "$HOSTPORT" | grep -q ":"; then
        HOST="${HOSTPORT%%:*}"
        PORT="${HOSTPORT##*:}"
      else
        HOST="$HOSTPORT"
        PORT="443"
      fi

      echo "Extracting certificate from $HOST:$PORT"
      mkdir -p .ci/sonar

      echo | openssl s_client -connect "$HOST:$PORT" -servername "$HOST" -showcerts 2>/dev/null \
        | awk '/BEGIN CERTIFICATE/{p=1} p{print} /END CERTIFICATE/{exit}' \
        > .ci/sonar/server.pem

      TRUSTSTORE_P12="$CI_PROJECT_DIR/.ci/sonar/truststore.p12"
      rm -f "$TRUSTSTORE_P12"

      keytool -import -storetype PKCS12 -noprompt \
        -alias sonarqube \
        -keystore "$TRUSTSTORE_P12" \
        -file .ci/sonar/server.pem \
        -storepass "$TRUSTSTORE_PASS"

  script:
    - |
      set -e

      export SONAR_SCANNER_OPTS="-Djavax.net.ssl.trustStore=$CI_PROJECT_DIR/.ci/sonar/truststore.p12 -Djavax.net.ssl.trustStorePassword=$TRUSTSTORE_PASS"
      echo "SONAR_SCANNER_OPTS=$SONAR_SCANNER_OPTS"

      #
재시도는 하되, 마지막엔 반드시 실패로 종료(exit 1)
      success=0
      for i in 1 2 3; do
        echo "Sonar scan attempt $i..."
        if sonar-scanner \
          -Dsonar.host.url="${SONAR_HOST_URL}" \
          -Dsonar.projectKey="${SONAR_PROJECT_KEY}" \
          -Dsonar.token="${SONAR_TOKEN}" \
          -Dsonar.qualitygate.wait=true; then
          success=1
          break
        fi
        echo "Scan failed. retrying..."
        sleep 5
      done

      if [ "$success" -ne 1 ]; then
        echo "Sonar scan failed after 3 attempts."
        exit 1
      fi

  rules:
    - if: '$CI_COMMIT_BRANCH == "main"'

5.1.2 sonar-project.properties

 
#프로젝트 이름에 맞게 계속 변경.
sonar.projectKey=<projectKey>
sonar.projectName=<projectName>

#
소스 위치
sonar.sources=src
sonar.sourceEncoding=UTF-8

#
불필요 제외
sonar.exclusions=**/node_modules/**,**/dist/**,**/build/**,**/*.d.ts

이후 3의 과정을 반복.

 

 

sonarQube를 사용하여

gitlab - 파이프라인 - sonarQube CI/CD 환경 구축으로 

보안 요구사항을 만족하였습니다.

728x90
반응형