코알못

[Docker] Sonarqube(with.jacoco) 활용 - 설치 및 연동 본문

ETC

[Docker] Sonarqube(with.jacoco) 활용 - 설치 및 연동

코린이s 2023. 3. 19. 19:43
728x90

전체 프로젝트 품질 측정하는 도구로 소나 큐브가 있다.

소나 큐브란 코드 컨벤션(코드 작성 Role)을 정의 할 수 있고 지켜지고 있는지 수치로 확인 할 수 있다.

소나 큐브에 jacoco 라이브러리 분석 결과도 포함 할 수 있어 같이 연동하여 사용하는데

jacoco 란 코드 커버리지를 측정하는 라이브러리이며 소나 큐브랑 연동하면 소나 큐브 내부에 jacoco 분석 결과를 표현할 수 있다.

코드 커버리지란 테스트 코드 실행시 전체 프로젝트 코드의 몇 퍼센트가 실행 되었는지 보고 테스트 코드가 적절하게 작성이 되었는지 확인하는 방법중에 하나이다!

지금 부터 소나큐브 설치를 진행해보자!

EC2 인스턴스를 생성하며 아래 스펙 이상이여야 하며

CPU Memory
2Core 4GB

방화벽은 아래와 같이 인바운드 오픈 되어야 한다.

포트 설명
22 SSH
9000 SonarQube UI

이제 EC2 를 생성해보자! 

저자는 t3medium 으로 생성하였으며 보안 그룹은 원하는 대역으로 열고 저자는 테스트 용도이므로 모든 IP 대역에 대해 오픈 한다.

우선 docker 를 설치 하고 일반 유저에게 권한을 부여하고 설치 정상 여부 확인한다.

$ sudo apt update
$ sudo apt install docker.io
$ sudo chmod 666 /var/run/docker.sock
$ docker ps -a
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES

이제 소나큐브 이미지를 가져와서 실행 하도록 한다.

$ docker run --name sonarqube -d -p 9000:9000 sonarqube:latest

정상적으로 떠있으므로 접속 해보자!

$ docker ps -a
CONTAINER ID   IMAGE              COMMAND                  CREATED         STATUS         PORTS                                       NAMES
b3c99e782331   sonarqube:latest   "/opt/sonarqube/dock…"   5 seconds ago   Up 3 seconds   0.0.0.0:9000->9000/tcp, :::9000->9000/tcp   sonarqube

http://[EC2 IP]:9000 으로 접속하면 아래와 같이 로그인 화면이 나오며 기본 admin 계정으로 로그인하며 (비번은 admin 이다.)  패스워드 변경창이 뜨니 변경 하면 된다.

이제 메인 화면이 뜨며 일반 유저 계정을 생성해보자!

상단에 Administration 을 클릭하고 Security > Users 를 클릭한다.

관리자 계정인 Administrator를 볼 수 있으며 Create를 눌러 유저를 생성한다.

원하는 유저를 생성하고 Create 를 누른뒤 로그인 하면 정상적으로 접속 되지만

 Administration 탭이 보이지 않기에 관리자 권한을 부여 하도록 한다. 우선 관리자로 로그인 한다.

Administration > Global Permissions 로 이동하고 원하는 권한을 선택한다.

권한 관련 설명은 상단 '?' 위에 마우스를 두면 설명이 나오니 확인하여 권한을 부여하며 저자는 관리자와 동일하게 권한을 부여하고 싶어 모든 권한을 체크한다.

이제 일반 유저로 로그인하면 정상적으로 admin 관련 탭이 보인다.

소스코드에서 소나큐브, jacoco 를 사용하기 위해서는 Bulid.gradle 에 플러그인을 추가한다.

plugins {
  ..
  id 'org.sonarqube' version '2.7.1'
  id 'jacoco'
}

jacoco 버전을 명시하며 결과를 html, xml, csv 모두 내려 받기위해 true로 설정한다.

finalizedBy 는 리포트 결과를 생성한뒤 아래 검증 Task 인 'jacocoTestCoverageVerification' 를 진행하라는 의미로 해당 코드는 뒤에 언급할 예정이다. 

jacoco{
  toolVersion = '0.8.7'
}

jacocoTestReport {
    reports {
        html.enabled=true
        xml.enabled=true
        csv.enabled=true
    }
    finalizedBy 'jacocoTestCoverageVerification'
}

소나 큐브 설정을 한다.

sonarqube {
  properties {
      property "sonar.projectName","App"
      property "sonar.exclusions", "**/generated-*/**/*"
      property "sonar.projectKey", "org.sonarqubeJacocoCodeCoverage"
      property "sonar.reportPath" , "${project.buildDir}/jacoco/test.exec"
      property "sonar.host.url", "http://<SonarQube Private IP>:9000"
      property "sonar.sources", "src/main/java"
      property "sonar.tests", "src/test/java"
      property "sonar.login", "<SonarQube ID>"
      property "sonar.password", "<SonarQube PW>"
  }
}

이제 테스트를 위해 빌드를 진행한다.

$ gradlew clean build --info

jacoco 를 이용하여 코드 커버리지를 측정 한다. (build > reports > jacoco > test 경로에 저장 된다.)

$ ./gradlew jacocoTestReport --info

실제 코드 분석 결과가 있는 경로는 아래와 같으며

경로 파일 설명
build/jacoco/test.exec test.exec 컴퓨터가 읽을 수 있는 바이너리 코드로 된 커버리지 분석 결과 파일
build/reports/jacoco/test html/index.html
jacocoTestReport.csv
jacocoTestReport.xml
사람이 읽을 수 있는 커버리지 분석 결과 파일 (html, csv, xml)

정상적으로 생성 된 것을 볼 수 있다.

$ cd build/jacoco
$ ll
drwxrwxr-x 2 ubuntu ubuntu  4096 Mar 19 08:12 ./
drwxrwxr-x 9 ubuntu ubuntu  4096 Mar 19 08:12 ../
-rw-rw-r-- 1 ubuntu ubuntu 26711 Mar 19 08:13 test.exec
$ cd [project dir]/build/reports/jacoco/test
$ ll
drwxrwxr-x 3 ubuntu ubuntu 4096 Mar 19 08:14 ./
drwxrwxr-x 3 ubuntu ubuntu 4096 Mar 19 08:14 ../
drwxrwxr-x 4 ubuntu ubuntu 4096 Mar 19 08:14 html/
-rw-rw-r-- 1 ubuntu ubuntu  217 Mar 19 08:14 jacocoTestReport.csv
-rw-rw-r-- 1 ubuntu ubuntu 2301 Mar 19 08:14 jacocoTestReport.xml

이제 소나 큐브를 실행하여 코드 품질을 스캔(jacoco 결과 포함)한다.

$ ./gradlew sonarqube --info

소나 큐브에 들어가보면 기본 기준으로는 품질 통과 되었으며 jacoco 를 통해 분석된 내용도 coverage 라는 수치로 표기 됨을 확인 할 수 있으며 code smell은 코드 품질을 낮추는 코드라는 의미로 이 점수가 낮다면 클릭해서 확인도 가능하다.

이제 코드 커버리지가 특정 기준에 맞지 않다면 빌드 되지 않도록 하는 실습을 진행한다.

위에 언급한 Task인 'jacocoTestCoverageVerification' 부분을 커스텀하게 지정하면 되며 아래 제한 조건을 정의해보자!

  • 메소드별 라인수 최대 1줄
  • 클래스별 라인수의 최소 80%가 테스트 코드에 포함 되어야 한다.
jacocoTestCoverageVerification {
  violationRules {
    // method per line maximum 1
    rule {
      enabled = true
      element = 'METHOD'
      limit {
        counter = 'LINE'
        value = 'TOTALCOUNT'
        maximum = 1
      }
    }
    // calss per line minimum 80%
    rule {
      enabled = true
      element = 'CLASS'
      limit {
        counter = 'LINE'
        value = 'COVEREDRATIO'
        minimum = 0.80
      }
    }
  }
}

 아래 코드를 보면  커버리지 50% (min 80), 라인수 2(max 1) 이므로 두 사항 모두 위반하였다.

$ ./gradlew clean build
$ ./gradlew jacocoTestCoverageVerification --info
> Rule violated for class com.corin.App: lines covered ratio is 0.50, but expected minimum is 0.80
  Rule violated for method com.corin.App.main(java.lang.String[]): lines total count is 2, but expected maximum is 1

이제 Jenkins 위 코드 체크 부분 'Code Verification by Sonarqube' 을 넣어 보자! ([이전 시간] 글과 이어집니다.)

Jenkinsfile

pipeline {
    agent any

    stages {
        stage('Pull Codes from Github'){
            steps{
                checkout scm
            }
        }
        stage('Build Codes by Gradle') {
            steps {
                sh """
                cd ${mainDir}
                ./gradlew clean build
                """
            }
        }
        stage('Code Verification by Sonarqube') {
            steps {
                sh """
                cd ${mainDir}
                ./gradlew jacocoTestReport
                ./gradlew sonarqube
                """
            }
        }
        ...

이제 Jenkins로 빌드해보자!

아래 보면 코드 검증 과정에서 실패가 발생 하여 도커에 이미지 빌드가 진행되지 않았다.

해당 단계에 로그 버튼을 클릭하여 어떤 검증에 실패하였는지 볼 수 있다.

이제 검증을 일부는 비활성화 일부는 수치를 낮추어 검증을 통과하는지 확인한다.

jacocoTestCoverageVerification {
  violationRules {
    // method per line maximum 1
    rule {
      enabled = false
      element = 'METHOD'
      limit {
        counter = 'LINE'
        value = 'TOTALCOUNT'
        maximum = 1
      }
    }
    // calss per line minimum 80%
    rule {
      enabled = true
      element = 'CLASS'
      limit {
        counter = 'LINE'
        value = 'COVEREDRATIO'
        minimum = 0.50
      }
    }
  }
}

젠킨스 다시 빌드하면 정상적으로 배포 된 것을 볼 수 있다.

추가 사항으로 소스 코드에 소나 큐브 ID/PW 를 기재 하지 않고 토큰을 입력하는 방법이 있다.

토큰의 경우 만료 기한을 줄 수 있고 삭제도 할 수 있기에 유출 될시 쉽게 제거 가능 하다.

소스 코드에서 sonar.password 부분을 제거하고 sonar.login 부분에 id 대신 토큰을 입력하면 된다.

sonarqube {
  properties {
      ...
      property "sonar.login", "[token]"
  }
}

테스트시 정상적으로 된다.

끝!!

728x90
Comments