Jenkins&Springboot CI/CD 정리(2)
우선 지난 1편에서는 위의 서비스 아키텍쳐의 gradle build와 함께 Jacoco, CheckStyle 설정 및 report 파일 생성 까지 모두 마무리 하였습니다. 이제는 Jacoco와 CheckStyle report를 Sonarqube로 넘겨준 후 Quality Gate를 진행하도록 하겠습니다.=)
현재 SonarQube의 분석결과를 오픈소스인 Sonar-Bot을 통해 간단하게 Gitea의 PR comment로 남겨주는 방식이 추가 되었는데 이부분은 설정할 부분이 생각보다 많아 다음편에서 소개를 해드리도록 하겠습니다. =)
1. SonarQube 설치 및 셋팅
필자의 경우 Sonarqube를 AWS EC2 프리티어에서 실행시키기에는 버거운 Tool 이라는 것을 알게되어 로컬환경에 도커 컨테이너로 띄우는 방식을 채택하였습니다. 단점은 실제 서버로 사용하려면 필자의 노트북 또는 데스크톱을 계속해서 켜놔야 한다는 점이지만 필자의 경우 연습을 위한 환경이였기에 로컬환경에서 구축을 하기로 하였습니다. =)
먼저 필자는 노트북으로 윈도우 운영체제를 사용하고 있기에 Docker Desktop을 설치하여 SonarQube 이미지를 Docker hub로 부터 다운받은 후 Docker Container 로 띄우는 방식을 사용하였습니다.
이후 공유기 포트포워딩을 통해 필자의 공인 IP 주소의 9000포트를 열어주어 다른 공인 IP에서도 접속이 가능하도록 하였고, 이를 통해 jenkins와 연동을 할 수 있게 하였습니다. =)
우선 Docker를 로컬 환경에 설치해주어야 하는데 이 부분은 필자가 정리한 글을 통해 대체를 하도록 하겠습니다. =)
모든 설치가 완료 되었다면 이제 docker pull을 통해 SonarQube 이미지를 다운받아 보도록 하겠습니다.
Docker hub의 홈페이지에 들어와 SonarQube를 검색하면 공식 이미지를 확인 할 수 있습니다. Tags를 누르면 버전별 이미지를 확인할 수 있습니다.=)
Gitabash, Terminal, PowerShell을 이용해 $ docker pull sonarqube를 하면 최신 버전의 SonarQube 이미지를 받을 수 있으나 필자의 경우 다음편에서 설명 할 Sonar-bot을 사용하는데 필요한 Plugin 설치 및 셋팅에 최신버전이 호환이 되지 않는 문제가 발생하여 8.4 버전을 채택하였고 해당 이미지를 받았습니다. =)
docker pull sonarqube:8.4.2-community
필자는 해당 이미지를 다운 받았으며 우측의 복사 버튼을 클릭하면 이미지를 받기위한 명령어가 복사되어집니다.
docker images
설치가 완료되었으면 다음과 같이 명령어를 입력하여 다운받은 이미지를 확인해줍니다.
필자의 경우 Docker desktop을 사용하고 있어 다음처럼 확인을 할 수 도 있습니다.
이제 해당 이미지를 실행시켜 Docker Container로 띄워 보도록 하겠습니다.=)
docker run -d -it --name sonarqube -p 9000:9000 sonarqube
여기서 -d 옵션은 백그라운드 실행합니다. -it 옵션은 -i 와 -t 옵션을 분리해서 사용할 수 도 있지만 대게 함께 사용합니다. -it 옵션은 컨테이너를 종료하지 않고 컨테이너로 명령어를 전달할 수 있게 해줍니다.
--name 옵션을 통해 사용자가 해당 컨테이너의 이름을 지정해줄 수 있으며 컨테이너 ID 값이 아닌 해당 이름으로 컨테이너 제어 명령어를 사용할 수 있게됩니다.
-p는 포트번호이며 좌측은 사용자가 url에 입력하여 붙을 수 있는 포트번호이고, 우측은 컨테이너의 내부 포트 번호를 뜻합니다. =)
docker ps
이제 컨테이너를 실행시키고 docker ps 명령어를 통해 띄워진 컨테이너를 확인해주도록 하겠습니다.
SonarQube 컨테이너가 잘 띄워진 것 같군요 !
그럼 이제 실행을 시켜봐야 겠죠 ?!
localhost:9000
필자의 경우 로컬 환경에 구축을 하였으므로 localhost:9000 으로 접속을 하였습니다. 버전마다 로그인 화면이 조금씩 다르나 해당 8.4.2 버전의 경우 좌측과 우측 상단에 로그인 버튼이 존재하고 로그인을 해보도록 하겠습니다. =)
SonarQube의 경우 초기 로그인 아이디와 비밀번호는 모두 admin 입니다. =)
로그인을 하면 다음과 같은 창이 나올텐데 필자의 경우 이미 프로젝트 생성과 셋팅이 모두 끝난 상태라 프로젝트가 3개 있는 것을 확인 할 수 있습니다. =)
이제 셋팅에 앞서 공유기 포트포워딩을 진행하여 9000 포트를 열어주도록 하겠습니다. =)
만약 로컬환경이 아닌 AWS EC2 환경에 SonarQube 컨테이너를 띄웠다면 아래 내용은 넘어가셔도 무방합니다.
필자의 경우 로컬환경에 구축을 하였기 때문에 다른 IP에서 필자의 로컬 환경에 접속을 할 수 없는 상태입니다.
이를 해결하기 위해선 필자가 사용하고 있는 공유기의 설정에서 9000 포트를 개방하여 다른 IP에서도 필자가 사용하고 있는 공유기의 공인 IP 9000포트로 접속을 할 수 있게 하면 됩니다. =)
이부분은 사설망과 공인망에 대한 이해가 필요한 부분인데 필자가 공부를 하며 작성을 해둔 글이 있으니 궁금하신 분은 아래 글을 확인해주시기 바랍니다. =)
먼저 필자의 경우 kt 공유기를 사용하고 있어 kt 공유기 주소로 접근해주도록 하겠습니다. 만약 다른 공유기를 사용하고 있으시다면 ex) Iptime 공유기 포트워딩 하는법 을 검색하시면 됩니다. =)
KT의 경우 http://homehub.olleh.com 을 주소창에 입력하면 쉽게 접속하실 수 있습니다.
처음 초기 아이디와 비밀번호는 다음과 같습니다.
ID: ktuser
PW: homehub
로그인을 진행한 후 장치설정 - 트래픽 관리 로 이동을 해줍니다.
필자의 경우 이미 9000포트와 추가적으로 9001 포트를 열어 주었는데 9001 포트는 Sonar-bot 컨테이너가 사용중인 포트입니다. 만약 필자와 같이 Gitea를 사용하고 PR comment를 Sonar-bot이 달아주는 것을 원하신다면 미리 9001번 포트도 개방하여 주세요. =)
다음과 같이 입력을 한 후 추가를 해주면 되는데 내부 IP 주소의 경우 cmd 또는 gitbash 등 자신이 사용하는 CLI 툴을 이용해 ipconfig 명령어를 입력하여 아래와 같이 확인할 수 있습니다.
해당 내부 IP주소를 위와 같이 입력을 해준 후 추가를 해주도록 하겠습니다. =)
위와 같이 추가된 목록을 확인 하신 후 시스템정보의 인터넷 연결정보에서 자신이 사용하는 공유기의 공인 IP 주소를 확인할 수 있습니다.=)
이제 정말 다른 공인 IP에서도 자신이 개방한 9000포트로 접속을 할 수 있는지 확인해 봐야 겠죠?!
필자는 필자의 휴대폰으로 {내 공인IP}:9000 으로 접속하여 로컬환경에서 띄운 SonarQube 사이트로 접속이 되는지 확인을 해보았습니다.
접속이 정상적으로 잘 이루어졌습니다 ! 이제 포트포워딩 작업은 끝이 났고 Jenkins와 연결을 해주도록 하겠습니다. =)
먼저 Sonarqube에서 프로젝트를 하나 생성하도록 하겠습니다.
이름은 자신이 사용하고 싶은 이름을 사용하시면 됩니다. =)
Project Key와 Display이름은 동일하게 맞추어지는데 key 값을 다르게 하셔도 상관없습니다. 다만 jenkins와 연동 시 SonarQube properties 설정에서 해당 key값과 name을 입력해주어야 하는데 헷갈리지 않으려면 함께 사용하는게 좋습니다.
이제 token을 생성해주어야 하는데 처음 사용을 하였더라면 설정된 token 값이 없을 겁니다. 그러므로 원하는 이름을 입력한 후 token 생성을 해주도록 하겠습니다.
generate 버튼을 누르면 token이 생성되는데 해당 토큰은 Jenkins credential에 등록해주어야 하니 꼭 메모장이나 어딘가에 token 값을 저장해 주세요. =)
다시 Sonarqube의 home으로 돌아오면 방금 생성한 프로젝트를 확인할 수 있습니다.
이제 Jenkins에 대한 webhook을 설정해주어야 하는데 Administration - Configuration - Webhook 으로 들어와주도록 하겠습니다.
http://{자신의 젠킨스서버 public IP}:{젠킨스포트번호}/sonarqube-webhook/
create를 눌러준 후 다음과 같이 입력을하고 생성을 해주도록 하겠습니다. =)
이처럼 설정을 하면 글로벌 설정이 되어 Sonarqube의 모든 프로젝트에 해당 webhook이 적용되어 지는데 필자는 dev환경 분석과 PR 분석을 위한 프로젝트 모두 같은 Jenkins를 바라보기 때문에 해당 웹훅은 글로벌로 설정을 해두었습니다.
만약 프로젝트 별 웹훅 설정을 원하는 경우 아래와 같이 프로젝트 내에서 Project Setting - Webhook 에 들어가 프로젝트별로 webhook 설정을 다르게 할 수 있습니다.
다음은 Jenkins에 들어가 SonarQube 설정을 해주도록 하겠습니다. =)
Jenkins관리 - 플러그인 관리 에 들어와 Sonar Quality Gates Plugin과 SonarQube Scanner for Jenkins 플러그인을 설치해주도록 합니다.
이제 SonarQube에 대한 credential 을 등록해주도록 하겠습니다. Manage Credentials로 들어와
grobal의 add credentials를 눌러주고 kind는 Secret text로 설정해주겠습니다. =)
Secret = Sonarqube 프로젝트 생성시 발급한 토큰 입력
ID = Jenkins 파이프라인에서 사용할 ID (해당 ID로 Jenkinsfile에서 Sonarqube token값을 전달 받습니다.)
Description = 해당 키에 대한 설명
다음은 SonarQube관련 플러그인이 모두 설치 되었다는 가정하에 설정을 진행해주도록 하겠습니다.
Jenkins관리 - Configure System에 들어오면 SonarQube Server 라는 부분이 생성된 것을 확인 할 수 있습니다.
Name = Jenkinsfile 에서 installtionName으로 사용될 값입니다.
Server URL= 필자의 경우 공유기 포트포워딩을 해두었기 때문에 http://필자의 공유기 IP:9000 으로 지정해주었습니다.
Server authentication token = 위에서 생성한 sonarqube crendential 을 등록해줍니다.
고급 버튼을 누르면 위처럼 Sonarqube의 properties를 설정할 수 있는 부분이 있는데 필자는 projectKey와 projectName만 여기에서 등록을 해주었습니다.
필자처럼 위 값을 jenkins에서 관리를 하여도 되고, 모든 sonarQube 설정을 springboot 프로젝트의 루트 디렉토리에 sonar.properties를 생성하여 관리를 하여도 무방합니다. =)
다음은 Sonar-Scanner 설정을 진행해보도록 하겠습니다.
Sonar-Scanner 플러그인이 정상적으로 설치 되었다면 Global Tool Configuration 에 위와 같은 설정 항목이 생겼을 겁니다.
위와 같이 설정을 진행해주는데 SonarQube Scanner 의 Name 부분은 자신이 사용하고자 하는 이름을 사용해주면 됩니다.
이것도 마찬가지로 Jenkinsfile에서 Sonnar-analysis Stage의 Sonnar-Scanner tool 에 명시해줄 이름입니다. =)
jenkinsfile에서 위 이름으로 sh 을 실행하면 Jenkins에서 등록한 Sonar-Scanner 를 사용하게 됩니다.
이제 Jenkins와 SonarQube에서의 작업은 모두 끝났습니다.
Jenkinsfile에 pipeline을 작성해보도록 하죠!
2. Jenkinsfile 작성 (SonarQube)
이전 1편 에서는 gradle build 단계까지 작성을 하였고 이어서 SonarQube Stage를 작성하겠습니다.
Jenkinsfile 풀 소스코드는 필자의 깃헙에서 확인하실 수 있으니 아래 링크를 통해 확인해주세요. =)
//Sonarqube Scanner - dev
stage("sonarqube analysis-dev") {
when {
branch "develop"
}
steps{
script{
def scannerHome = tool 'jenkins에서 등록한 Sonnar-Scanner Name';
withSonarQubeEnv(credentialsId:"Jenkins에서 등록한 SonarQube Crendential ID",installationName:'Jenkins SonarQube Server설정의 Name') {
sh "${scannerHome}/bin/sonar-scanner \
-Dsonar.branch.name=master \
-Dsonar.language=java \
-Dsonar.java.source=1.8 \
-Dsonar.sources=src/main/java \
-Dsonar.test=src/test/java \
-Dsonar.test.inclusion=**/*Test.java \
-Dsonar.issuesReport.console.enable=true \
-Dsonar.junit.reportPaths=build/test-results/test \
-Dsonar.java.binaries=build/classes \
-Dsonar.java.coveragePlugin=jacoco \
-Dsonar.coverage.jacoco.xmlReportPaths=build/jacoco/jacoco.xml \
-Dsonar.java.libraries.empty=true \
-Dsonar.sourceEncoding=UTF-8 \
-Dsonar.exclusions=**/dto/**,**/exception/**,**/constant/**,**/SpringInitProjectApplication.java,**/WebRestController.java,**/FileUploadYaml.java \
-Dsonar.java.checkstyle.reportPaths=build/reports/checkstyle-output/checkstyle-report.xml \
-Dsonar.web.javaAdditionalOpts=-javaagent:./extensions/plugins/sonarqube-community-branch-plugin-1.5.0.jar=web \
-Dsonar.ce.javaAdditionalOpts=-javaagent:./extensions/plugins/sonarqube-community-branch-plugin-1.5.0.jar=ce \
"
}
}
}
post{
success {
slackSend (
channel: SLACK_CHANNEL,
color: SLACK_SUCCESS_COLOR,
message: "Dev branch SonarQube Scanning 을 성공하였습니다."
)
echo "Success sonarqube analysis"
}
failure {
slackSend (
channel: SLACK_CHANNEL,
color: SLACK_FAIL_COLOR,
message: "Dev branch SonarQube Scanning 을 실패하였습니다.\n" +
"\n" +
"<-More info->\n" +
"${env.BUILD_URL}console\n" +
"=================================================================="
)
echo "Fail sonarqube analysis"
}
}
}
위 코드에 대한 설명을 드리자면 해당 Stage는 SonarQube-Scanner 를 이용하여 설정된 파일을 읽고 분석을 하는 과정입니다.
Stage안의 when{develop} 은 Jenkins build가 develop branch로의 merge 또는 push가 일어났을 때만 해당 Stage가 작동하도록 해줍니다. prod 환경이 배포될 main branch의 경우 이미 develop branch에서 모든 분석과 수정 및 테스트가 끝나고 배포되는 환경이기에 SonarQube Stage를 Skip 하게 됩니다. =)
Stage 안의 sh ' ' 부분을 보시면 -Dsonar. 으로 시작하는 설정들이 존재하는데 이 설정들은 SonarQube 분석 시 사용될 설정들을 말합니다. 분석을 할 패키지의 위치를 명시해주고 inclusion 과 exclusion 설정을 통해 분석 시 포함할 항목과 배제할 항목을 지정해줄 수 있습니다.
-Dsonar.branch.name=master 는 SonarQube에서 생성한 프로젝트에 분석결과를 등록할 branch name인데 SonarQube설정을 통해 default branch 이름을 변경하지 않는 한 master로 잡혀 있습니다. 또한 이 설정은 sonar-bot의 pr commnet 를 사용하지 않을 것 이라면 지워주셔도 무방합니다.
jacoco를 사용하고 있다면
-Dsonar.java.coveragePlugin=jacoco \
-Dsonar.coverage.jacoco.xmlReportPaths=build/jacoco/jacoco.xml \ 여기에서 jacoco.xml report가 생성되는 위치를
정확히 명시해주어야 SonarQube에서 해당 report를 읽어들일 수 있습니다.
CheckStyle을 통해 코드 컨벤션 분석 결과를 SonarQube로 보내기 위해 생성된 xml 파일의 위치를 명시해줍니다.
-Dsonar.java.checkstyle.reportPaths=build/reports/checkstyle-output/checkstyle-report.xml \
-Dsonar. 으로 시작하는 설정들은 필자가 Jenkins에서 SonarQube 설정 시 말한 것 처럼 프로젝트 root경로에 sonar.properties를 만들어 따로 관리하여도 상관이 없습니다. 위 코드가 지져분해 보인다면 입맛에 맞추어 관리하여도 문제가 되지 않을 것 같습니다. =)
-Dsonar의 맨 밑 2줄을 보시면 -Dsonar.web 과 -Dsonar.ce 부분은 다음번에 설명할 Sonar-bot 을 사용할 때 Community-branch-plugin 을 직접 설치하여 설정하는 부분인데 Sonar-bot을 사용하지 않을 것 이라면 위 두 줄은 지워도 됩니다. =)
//SonarQube Quality Gate
stage('SonarQube Quality Gate'){
when {
branch "develop"
}
steps{
timeout(time: 1, unit: 'MINUTES') {
script{
echo "Start~~~~"
def qg = waitForQualityGate()
echo "Status: ${qg.status}"
if(qg.status != 'OK') {
echo "NOT OK Status: ${qg.status}"
error "Pipeline aborted due to quality gate failure: ${qg.status}"
} else{
echo "OK Status: ${qg.status}"
}
echo "End~~~~"
}
}
}
post{
success {
echo "Success sonarqube analysis"
slackSend (
channel: SLACK_CHANNEL,
color: SLACK_SUCCESS_COLOR,
message: "SonarQube Quality Gate 를 통과하였습니다."
)
}
failure {
echo "Fail sonarqube analysis"
slackSend (
channel: SLACK_CHANNEL,
color: SLACK_FAIL_COLOR,
message: "SonarQube Quality Gate 를 통과하지 못하였습니다.\n" +
"\n" +
"<-More info->\n" +
"${env.BUILD_URL}console\n" +
"=================================================================="
)
}
}
}
SonarQube의 마지막 Stage는 SonarQube Quality Gate 입니다.
qg 라는 변수에 waitForQualityGate() 라는 설정을 담아주었는데 이는 SonarQube analysis가 끝날 때 까지 기다린 후 결과 값을 반환하게 됩니다.
qg.status 가 ok 즉, 모든 분석 결과가 SonarQube Quality Gate를 통과하게 된다면 ok 를 반환하게 되고 해당 Stage를 통과 하게 됩니다. =)
SonarQube Quality Gate 는 default로 잡혀 있는 설정이 있지만 만약 이 설정 값이 자신이 진행하고자 하는 프로젝트에 너무 높은 기준치라 판단되거나 좀 더 수정이 필요하다면 Quality Gates 설정에서 커스텀이 가능합니다. 위는 default로 잡혀 잇는 SonarWay 라는 이름의 Quality Gate 입니다.
Quality Gate 설정에서 좌측의 create 버튼을 누른 후 사요할 Quality Gate의 이름을 입력해줍니다.
Add Condition을 누르면 다음과 같은 창이 뜨는데 여기에서 자신이 Quality Gate에서 사용할 항목들을 하나하나 추가하고 수치들을 설정할 수 있습니다. =)
자신이 사용할 항목들을 모두 추가한 Quality Gates 를 만들었다면 이제 프로젝트 내의 Project Setting의 Quality Gate 설정에서 생성한 Quality Gate를 지정할 수 있습니다. 이렇게 하면 SonarQube의 해당 프로젝트는 지정된 Quality Gate를 통해 분석결과를 실패시키거나 성공시키게 됩니다. =)
생각보다 SonarQube 설정과 setting 설명이 길어져 여기서 끊고 다음 Stage인 docker image build 와 Docker hub 연동, nginx 를 이용한 blue & green 배포는 3편에서 이어 가도록 하겠습니다. =(
'DailyStudy > CI CD' 카테고리의 다른 글
Jenkins&Springboot CI/CD 정리 마지막(4) [Gitea & Sonar-bot] (0) | 2022.11.12 |
---|---|
Jenkins&Springboot CI/CD 정리(3) (0) | 2022.11.11 |
Jenkins&Springboot CI/CD 정리(1) (0) | 2022.11.05 |
Jenkins&Sonaqube&Checkstyle 을 이용한 코드컨벤션 적용기(Naver Code Convention) (3) | 2022.11.03 |
Jenkins & Slack 연동하기(Slack Notification) 및 파이프라인 작성 (0) | 2022.10.27 |