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
반응형