[DevOps] SonarQube정적 분석 및 Jenkins Pipeline (feat. Windows)

10000JI·2024년 5월 13일

DevOps

목록 보기
11/14

🧊 SonarQube 사용하기

이번 포스팅에선 정적 분석 도구로 유명한 SonarQube 서비스 알아보고, Jenkins와 연동하는 방법에 대해 정리해보자.

SonarQube의 몇 가지 특징은 다음과 같다.

  • 지속적인 통합(Continuous Integration)분석(Analysis)을 할 때 사용되는 솔루션

    • 즉 코드에 대한 품질을 높이기 위해서 코드가 가지고 있는 이슈(Issues) 혹은 결함(Defect), 코드 복잡성(Code Complexity) 등을 분석하여 코드가 사용할 수 있는 가용 범위와 문제가 있는 코드를 분석

    • 버그(Bug)와 취약성(Vulnerabilites) 있는 코드를 찾아주는 용도로도 주로 사용

    • Code Smell 이라고 해서 코드 안에 불필요한 코드, 코드 이상 여부 탐지 가능

Build -> Test -> Package -> Deploy

전 과정 중에서 컴파일의 문제가 없고, 테스트 코드 문제가 없다고 해서 무조건 배포할 수 없다.

정적/동적 도구를 이용해 정적 테스트 / 동적 테스트를 거친 후 코드의 이상이 없는지 확인해야 한다.

정적 테스트 도구로 SonarQube에서는 불필요한 리소스 낭비라든가 코드의 품질을 높여주기 위해서 다양한 체크를 하고 거기에 대한 리포트를 해주는 툴로 많이 쓰인다.

이제 SonarQube 이미지를 가져와 컨테이너를 만들고 본격적으로 실행해보자.

docker pull sonarqube

먼저 SonaQube 이미지를 다운 받는다.

docker run --rm -p 9000:9000 --name sonarqube sonarqube

컨테이너가 중지되면 자동으로 제거될 수 있게 --rm 옵션을 주고, 9000번 포트를 통해 SonarQube에 접근할 수 있게 컨테이너를 만들었다.

웹 브라우저에서 http://localhost:9000 으로 접속하면 SonarQube 인터페이스를 확인 가능하다.

🍨 SonarQube + Maven 프로젝트 사용하기

https://docs.sonarsource.com/sonarqube/latest/analyzing-source-code/scanners/sonarscanner-for-maven/

SonaQube 설치 후 메이븐 프로젝트를 실제 SonaQube에서 분석해 보기 위해서 플러그인 하나를 설치해야 한다.

위 url로 이동하여 스크롤을 내리다 보면

Other settings 라고 해서 Maven plugin 코드가 나온다.

<plugin>
    <groupId>org.sonarsource.scanner.maven</groupId>
    <artifactId>sonar-maven-plugin</artifactId>
    <version>3.7.0.1746</version>
</plugin>

여기서 플러그인이라고 되어있는 항목만 복사하여

기존 포스팅에서 사용한 프로젝트의 pom.xml에 추가해준다.

버전 이슈가 있어 Maven Repository에 가서 버전을 확인해 준 뒤

3.9.1.2184로 버전을 변경해주었다.

http://localhost:9000

pom.xml에 플러그인을 추가하고 저장을 하였다면, SonarQube에 접속해보자.

9000번 포트번호로 접속하면 로그인 정보를 요청한다.

최초 로그인 시에 id, password 둘 다 admin이다.

id : admin
password : admin

최초 로그인 후 최초 접속 시엔 password를 변경해달라고 뜬다.

기존 password는 admin이라고 치면 되고, 새로운 password는 원하는대로 적어주면 되겠다.

로그인 후 오른쪽 상단을 클릭하면 My Account라는 메뉴가 나온다.

이를 클릭하면

Profile, Security, Notifications, Projects 등이 나오는데 Security를 클릭하면 Generate Tokens 라고 필요한 토큰 정보를 생성할 수 있다.

여기에 Name은 sonar-token이라고 적어주었고, Type은 User Token을 선택, Expries in은 1 years를 선택하였다.

만료일은 원하는대로 선택해주면 된다.

Generate를 클릭하면 토큰이 만들어지는데, 이 토큰 정보는 생성 당시만 보여지고 나중에는 다시 확인할 수 없기 때문에 복사하여 잘 보관해둬야 한다.

mvn sonar:sonar -Dsonar.host.url=http://IP_address:9000 -Dsonar.login=[the-sonar-token]

Maven을 사용하여 SonarQube 서버에 프로젝트 코드를 분석하도록 요청하는 명령어이다.

  • sonar:sonar : Maven SonarQube 플러그인의 goals 중 하나로, 프로젝트 코드를 분석하도록 요청

  • Dsonar.host.url=http://IP_address:9000 : SonarQube 서버의 URL을 지정한다.

    필자는 IP주소를 localhost로 지정하였기에 호스트 pc의 9000 포트에서 컨테이너로 실행 중인 SonarQube 서버를 가리킨다.

  • Dsonar.login=[the-sonar-token] : 위에서 발급받는 토큰을 [the-sonar-token] 부분에 적어주면 된다.

참고로 Maven와 Java가 호스트 pc에 깔려있지 않다면 미리 깔아둬야 한다.

Build SUCCESS가 뜨면 SonarQube 사이트로 이동하여 결과를 볼 수 있다.

여기선 특별한 문제가 없기 때문에 Passed가 떴다.

만약에 이 프로젝트 안에 문제가 발견이 된다고 하면 해당 문제가 어느 정도 영향력이 있는지, 몇 개 정도 발견했는지 수치화해서 표시를 하게 된다.

🍧 Bad Code 조사하기

위에선 문제 없이 Passed되었지만, 이번엔 코드에 문제가 있다면 어떻게 나오는지 확인해보자.

프로젝트 파일에 WelcomeController를 열고, logger 대신 프린트 문장을 삽입하였다.

프린트 문장 자체가 특별하게 문제가 있는 건 아니지만 실제 운영 서버에서 많은 코드가 있을 경우에 io에 대한 리소스를 계속 사용하고 있기 때문에 프로젝트에 대한 성능 자체를 높여줄 수 없다.

가능하면 우리가 필요로 하는 모든 로그에 대해서는 정확하게 Logger를 출력하는게 좋다.

일단 코드를 변경하였으니 저장 후 빌드를 완료해준 뒤 다시 코드를 분석하도록 요청해보자.

mvn clean compile package -DskipTests=true

Maven Build를 진행할 때는 pom.xml 파일이 보이는 위치에서 실행해야 한다.

필자는 프로젝트 폴더에 바로 pom.xml에 존재함으로 프로젝트 폴더에서 명령어를 실행했다.

-D 옵션에 skipTests=true를 넣는 이유는 현재 테스트 코드를 실행하지 않으려고 넣어주었다.

문제 없이 빌드가 되는 것을 확인할 수 있다.

mvn sonar:sonar -Dsonar.host.url=http://IP_address:9000 -Dsonar.login=[the-sonar-token]

SonarQube로 코드를 분석하도록 요청하기 위해 위 명령어를 다시 입력해주었다.

성공적으로 빌드가 되었으므로 사이트로 이동해 결과를 확인해보자

Passed라고 떴던 게 Failed로 변경되었다.

들어가서 확인해보면 무엇이 문제였는지 상세히 기술되어 있다.

  • logger를 선언시켜 놓고 사용하지 않았다.

  • 이 주석이 달린 코드 행의 블록은 제거되어야 한다.

  • System.out을 logger로 대체해야 한다.

라고 자세히 라인마다 알려주고 있는 것을 확인할 수 있다.

🥤 Jenkins + SonarQube 연동

Jenkins와 SonarQube를 연동하기 위해 도커 컨테이너로 가동중인 Jenkins 사이트로 이동한다.

대시보드 -> Jenkins관리 -> Plugins에서 SonarQube 관련되어 있는 플러그인을 설치를 한다

Available plugins에서 SonarQube Scanner를 install 해준다.

설치를 완료했으면 Jenkins관리 -> Credentials로 이동해

SonarQube에 관련된 Token을 등록해 주어야 한다.

도메인의 global 화살표를 누르면 Add credentials가 나온다.

클릭해주면 New Credentials로 이동한다.

Kind에 Secret text를 선택하고, Secret에 위에서 발급받았던 토큰 정보를 붙여넣어준다.

Id는 sonarqube-token으로 적어주었다.

Create를 눌러주면 Credentials이 등록된다.

SonarQube를 연동하기 위한 서버를 등록하기 위해 대시보드 -> Jenkins 관리 -> System으로 이동해 SonarQube servers의 Environment variables 체크박스 클릭해주고, Add SonarQube를 눌러준다.

Name은 SonarQube-server, Server URL은 http://172.17.0.5:9000, Server authentication token은 위에서 만든 sonarqube-token을 선택해주었다.

docker network inspect bridge

http://172.17.0.5:9000로 적은 이유는 위 명령어로 docker의 네트워크를 확인해보면 sonarqube 서버가 172.17.0.5 주소로 가동되고 있기 때문이다.

SonarQube 자체가 도커 컨테이너로 기동되고 있어서 젠킨스에서 소나큐브로 접속 시도 시 컨테이너 간의 호출이기 때문에 실제 컨테이너가 가지고 있는 IP 주소를 적으면 되는 것이다.

여기까지 설정했다면 Jenkins와 SonarQube 연동은 끝이다.

🧃 SonarQube 사용을 위한 Pipeline 사용하기

연동시킨 후 Jenkins Pipeline에 적용시켜보자.

이전 프로젝트 중 My-Third-Pipeline을 선택해주었다.

구성을 눌러 수정해줘야 하는데, Pipeline Script만 변경해줄 것이다.

stage에서 github clone, build, deploy, ssh publisher 작업을 해줬었는데 deploy, ssh publisher 는 잠시 사용하지 않을 것이므로 주석처리 해주고 새로운 stage를 추가해줬다.

pipeline {
    agent all
    tools {
        maven 'Maven 3.8.5'
    }
    stages {
        stage('github clone'){
            steps {
                git branch: 'main', url: 'https://github.com/10000JI/cicd-web-project'
            }
        }
        
        stage('build'){
            steps {
                sh '''
                    echo build start 
                    mvn clean compile package -Dskiptests=true
                '''
            }
        }
        
        stage('SonarQube analysis'){
            steps{
                withSonarQubeEnv('SonarQube-server'){
                    sh 'mvn sonar:sonar'
                }
             
            }
        }
        
        // stage('deploy'){
        //     steps{
        //         deploy adapters: [tomcat9(credentialsId: 'deployer_user', path: '', url: 'http://172.30.1.52:8088')], contextPath: null, war: '**/*.war'
        //     }
        // }
        
        // stage('ssh publisher'){
        //     steps {
        //         sshPublisher(publishers: [sshPublisherDesc(configName: 'docker-server', transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand: 'docker build --tag 10000ji/devops_exam1 -f Dockerfile .', execTimeout: 120000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: '.', remoteDirectorySDF: false, removePrefix: 'target', sourceFiles: 'target/*.war')], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: false)])
        //     }
        // }
    }
}

위 코드에서 stage SonarQube analysis 를 추가해주었다.

steps에는 위에서 추가해준 SonarQube 서버 이름을 적어주었다.

SonarQube-server 안에다 url값은 다시 한번 말하지만 해당하는 SonarQube 자체가 도커 컨테이너로 기동되고 있기 때문에 젠킨스에서 SonarQube로 접속을 시도할 때 컨테이너 간의 호출이기에 실제 컨테이너가 가지고 있는 IP 주소를 적어줬었다.

localhost라고 적으면 Jenkins가 자기 자신에 대한 정보를 호출할 것이기에 오류가 뜰 수 있다.

반드시 다른 서버를 호출하실 때는 컨테이너 IP 주소를 입력해야 된다는 것을 명심하자.

컨테이너에서 실행할 땐 'mvn sonar:sonar'에 url, 로그인 정보를 입력했었는데 이를 입력하지 않아도 된다.

이유는 SonarQube-server 안에 url 정보도 있고 토큰 정보도 있기 때문에 간단하게 서버의 이름만 지정하시면 되는 것이다.

설정이 끝나면 저장을 누르고 지금 빌드를 눌러 시작해준다.

콘솔을 확인해보니 SUCCESS가 떴다.

SonarQube 사이트로 들어가면 빌드가 성공적으로 완료되어 최근 시간으로 다시 한번 결과를 출력했음을 알려준다.

출처

Jenkins를 이용한 CI/CD Pipeline 구축

profile
Velog에 기록 중

0개의 댓글