ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [칵테일픽] SonarQube를 통해 정적분석을 적용해보자
    Project 2020. 11. 7. 22:19

    우아한테크코스에서 진행 중인 팀 프로젝트인 칵테일픽 서비스를 운영하며 생긴 에피소드를 다룬 글입니다.

     

    프로젝트에 적용한 정적분석 툴인 소나큐브의 로고

     

    정적 분석이란 무엇인가

    소프트웨어를 동작시키기 위해 뭐가 필요할까? 당연한 대답으로 소프트웨어가 필요하겠지. 그렇다면 소프트웨어를 잘 동작시키기 위해서는 뭐가 필요할까? 유연한 설계. 요구사항에 충족한 구현. 빠짐없는 테스트. 모두 맞다. 우리는 개발자로서 객체지향에 적합한 설계를 함으로 유연한 설계를 이뤄낼 수 있다. 또한 기획자와 충분히 협업을 하여 요구사항을 잘 뽑아내어 구현할 수 있다. 그리고 JUnit과 같은 테스트 프레임워크의 도움을 받아 테스트를 운영할 수 있다.

    이렇게 개발자의 노력과 툴의 도움을 받아 잘 돌아가는 소프트웨어를 만들었다면 더 이상의 개선은 없을까? 아니다. 비록 기능적으로는 잘 동작하지만 추가적인 개선의 여지가 있을 수 있다. 이를 찾기 위해 몹 프로그래밍으로 코드를 살펴본다거나, 흔히 말하는 코드 스멜을 제거하는 방식으로 코드를 개선할 수 있다. 쉽고 직관적인 방법이다. 이런 코드 스멜은 오랜 기간에 걸쳐 규칙처럼 만들어진 경우도 많다. 그렇지만 프로젝트의 크기가 무척 크다면? 개발팀이 기능 개발보다 코드 스멜을 탐지하는 일에 시간을 쏟게 되는 비효율이 발생할 수 있다. 이럴 경우 개발자가 직접 코드를 분석하지 않고, 정적 분석 도구를 이용하여 소프트웨어의 취약점이나 코드 스멜을 분석하는 것이 정적 분석이다.

     


     

    소나큐브(SonarQube)란 무엇인가

    위에서 정적 분석이란 무엇인지, 왜 필요한지에 대해 소개했고, 적용하는 방법으로 정적 분석 도구를 사용할 수 있다고 언급했다. 그렇다면 칵테일픽 프로젝트에 적용한 소나큐브라는 정적 분석 도구는 무엇인지 알아보도록 하자.

    소나큐브는 20개 이상의 프로그래밍 언어에서 버그, 코드 스멜, 보안 취약점을 발견하는 정적 코드 분석을 지원한다. 그리고 자동 리뷰를 수행하여 지속적인 코드 품질 검사를 가능하게 하는 오픈 소스 플랫폼이다. 출처 : 위키백과

    자바를 비롯하여 많은 언어에 대해 분석할 수 있는 도구다. 자바는 기본적으로 무료이나 다른 언어, 사용 방식에 대해서는 과금이 필요한 경우가 있다.

    소나큐브가 지원하는 언어 목록

     

    과금 방식 : 우리는 무료이고 오픈소스인 Community를 사용한다.

     

    추가적인 정보로는 CI 툴인 젠킨스와 연동되어 CI 과정에 포함시켜 정적 분석이 가능하다. 즉 깃헙에 특정 이벤트(머지)가 발생하면 젠킨스가 이를 탐지해 빌드 과정이 진행될 때에 소나큐브의 정적 분석 과정도 포함될 수 있다는 의미이다.

    마지막으로 깃헙과 연동되어 pr에 자동으로 댓글을 남기거나 해당 pr에 대한 정적 검사를 진행하고 결과를 표시한다.

    제목 우측에 초록색 체크는 통과했다는 의미다. 빨간 엑스는 통과하지 못함을 의미한다.

     


     

    소나큐브를 사용해보자

    소나큐브를 로컬에 설치해서 사용하는 방법도 있고 EC2 호스트에 설치해서 사용하는 방법도 있다. 하지만 우리 팀은 이식성을 고려하여 도커를 사용 중이기에 마찬가지로 소나큐브도 도커 컨테이너를 띄워서 사용하기로 한다.

     

    순서

    1. 도커를 이용하여 소나큐브 컨테이너를 띄운다.
      • 이미지가 없으면 이미지를 pull 받는다.
      • 컨테이너를 돌릴 때에 포트를 설정해줘야 한다.
      • 컨테이너를 돌릴 때에 볼륨을 설정해줘야 한다.
    2. 소나큐브를 접속하여 계정 설정을 한다.
      • 기본 계정으로 로그인한다.
      • 새로운 계정을 생성한다.
        • 토큰을 발급받는다.
      • 프로젝트를 시작한다.
    3. 프로젝트와 소나큐브를 연동하여 소나큐브 리포트를 확인한다.
      • 두 가지 방법이 있다. 하나는 터미널에 명령어를 직접 주고 옵션까지 주는 방법. 다른 하나는 build.gradle에 미리 설정을 해두고 단축어로 사용하는 방법. 둘 다 다뤄보자.

     

    1. 도커를 이용하여 소나큐브 컨테이너를 띄운다.

    맨 처음 컨테이너를 띄우고 돌리다가 부족한 부분이 발생해서 2차로 수정했다.

    1차 : run 명령어를 사용하기에 소나큐브 이미지가 없으면 다운로드하고 있으면 사용한다. 그냥 포트만 연결해준다 : volume으로 데이터를 연결 안 해줘서 컨테이너 내리고 다시 띄우면 기존 정보가 사라지는 문제가 있었다.

    docker run -d --name sonarqube -p 8080:9000 -p 8888:9092 sonarqube

     

    추가적인 설명

    • 9000이 소나큐브. 추후 EC2에 :8080으로 접속하면 소나큐브 페이지를 볼 수 있다.
    • 9092는 소나큐브가 사용하는 h2 (우리가 실제로 사용할 일은 별로 없으니까 굳이 연결할 필요는 없을 것 같다)
      • 컨테이너에 올려둔거라 추후에 우리가 컨테이너를 내리거나 하면 토큰 같은걸 재발급받고 그래야 하는 불편함이 있다.
        이를 해결하기 위해 볼륨을 이용했다.

     

    2차 : 볼륨도 연결해준다.

    docker run -d -v /sonarqube:/opt/sonarqube/data -v /sonarqube/extensions:/opt/sonarqube/extensions --name sonarqube -p 8080:9000 -p 8888:9092 sonarqube

     

    2. 소나큐브를 접속하여 계정 설정을 한다.

    위의 과정을 통해 소나큐브 컨테이너를 띄웠으니 8080 포트로 접속할 수 있다.
    접속한 후에는 우측 상단의 로그인을 누르다.
    맨 처음 기본 계정은 id: admin, password: admin이다.

    로그인 후에는 아래의 경로로 가서 새로운 유저를 추가한다. (Security > Users > 우측 상단의 Create User 버튼)

    우측 상단의 create user 버튼을 눌러서 계정을 생성한다.

    그리고 토큰을 발급 받는다.

    발급 받은 토큰은 잘 관리하자.

    그리고 소나큐브 프로젝트를 하나 만든다. 이러면 정적 분석을 위한 외적인 준비는 끝났다.

     

    3. 프로젝트와 소나큐브를 연동하여 소나큐브 리포트를 확인한다.

    외적인 준비를 완료했으니 실제 프로젝트(칵테일픽)에서 정적 분석을 요청해야 한다.

    id "org.sonarqube" version "2.7"

    build.gradle에 의존성을 추가한다. 

    ./gradlew sonarqube \
    	-Dsonar.projectKey=cocktailpick \
    	-Dsonar.host.url=http://소나큐브가_띄워져있는_서버_ip:8080 \
    	-Dsonar.login=발급_받은 _토큰 \
    	-Dsonar.coverage.jacoco.xmlReportPaths=build/reports/jacoco/test/jacocoTestReport.xml

    마지막 줄은 Jacoco를 활용할 경우 소나큐브가 자코코 테스트 리포트를 읽어서 테스트 커버리지에 대한 정적분석을 실행하는데 xml 형태로 리포팅을 해줘야하고 해당 경로를 지정해줘야 동작한다.

    해당 명령어를 이용한 후 동작이 완료되면 소나큐브가 올라가 있는 EC2(혹은 로컬)의 지정한 포트(해당 포스트에서는 8080)로 접속해서 확인이 가능하다.

     

    멀티모듈 적용 이후의 소나큐브 활용

    멀티모듈을 적용하기 전에는 위에서 처럼만 해도 잘 동작했다. 그러나 멀티모듈이 적용된 후에는 jacocoTestReport.xml이 저 경로에 있지 않아서 코드 커버리지 분석 기능이 동작하지 않았다. 이를 해결하기 위해서 우테코의 다른 프로젝트인 송파피플의 깃헙 위키를 참고했다.

    root 모듈의 build.gradle에서 작업이 진행되었다. 바로 위에서 적어준 plugins에 있는 소나큐브 2.7 의존성을 제거하고

    buildscript { 
    	repositories { 
        	maven { url "<https://plugins.gradle.org/m2/>" } 
        } 
        dependencies { 
        	classpath "org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:3.0" 
        }
    }

    를 추가한다.

    그리고 같은 root 모듈의 build.gradle

    apply plugin: "org.sonarqube"

    를 추가한다.

    그리고 마찬가지로 같은 root 모듈의 build.gradle에 소나큐브 명령어를 만들어 준다

    sonarqube { 
    	properties { 
        	property "sonar.host.url", "<http://소나큐브가_설치된_서버_ip:8080>" 
            property "sonar.login", "발급_받은_토큰" 
            property "sonar.source", "src" 
            property "sonar.language", "java" 
            property "sonar.sourceEncoding", "UTF-8" 
            property "sonar.coverage.jacoco.xmlReportPaths", "${buildDir}/reports/jacoco/test/jacocoTestReport.xml" 
        } 
    }

     

    추가적으로 멀티모듈 중 자코코를 체킹해주는 하위모듈(칵테일픽 프로젝트에서는 cocktailpick-api 모듈)의 build.gradle에 소나큐브에서 자코코 리포트를 활용할 경우 테스트 커버리지에서 제외할 파일이나 폴더를 설정해준다.

    sonarqube {
        properties {
            property "sonar.exclusions", "*.dto, *.dto.*, *.BackApplication, *.config.*, *.security.*, *.exceptions.*, *.util.*, *.EmptyUser"
        }
    }

    이렇게 설정을 마치면 ./gradlew clean build sonarqube 명령어를 이용하여 클린 빌드 후 소나큐브를 통한 정적분석을 자동으로 실행할 수 있게 된다.

     

    실제 정적 분석이 완료된 후에는 소나큐브에 접속하여 분석 내용을 확인할 수 있다.

    총 세개의 모듈로 이뤄진 칵테일픽의 소나큐브 분석 대쉬보드

    기존에 코드 스멜이 45개 정도였는데 팀원인 무늬가 힘써줘서 많이 들었다. 또한 버그도 두 개 정도 있었는데 팀원들과 몹 프로그래밍을 통해 제거했기에 하나도 없는 모습을 확인할 수 있다.

     


     

    Trouble Shooting

    문제

    • 기존에는 CI-EC2에 젠킨스와 소나큐브 컨테이너를 함께 올렸었다. 하지만 계속 EC2가 터지는 일이 발생했다.

     

    원인

    • EC2 용량이 4기가인데 소나큐브가 2기가, 젠킨스가 750메가를 차지한다. 이 상황에서 젠킨스가 웹 훅을 감지해서 빌드될 때 용량을 초과했다. 그래서 매번 머지될 때에 EC2가 터진다.

     

    해결법

    • 각자 로컬에 소나큐브를 설치하자 => 팀원 각각이 아니라 팀에서 하나로 관리하는게 더 낫기에 기각.
    • 현재 활용 중인 EC2 중 DB를 돌리기 위한 EC2의 메모리가 많이 남아있기에 여기에 소나큐브를 설치하자 => DB용 EC2라는 목적에 맞지 않고 추후 DB에 데이터가 많이 쌓인다면 이 또한 용량이 부족할 수 있기에 기각.
    • 결과적으로는 우테코에서 EC2 자원을 제공해주시기에 소나큐브를 위한 EC2를 하나 더 파는 방향을 선택했다.

     

     


     

    글을 마치며

    우테코 미션을 진행하며 칵테일픽에 소나큐브를 적용해봤다. 아직 젠킨스와 연동시키지 않아서 수동으로 정적 분석을 해줘야 하는 단계이다. 코드 스멜을 제거하고 분석 결과를 빠르게 확인하기 위해서 이렇게 간단하게 적용해두었다. 추후에는 젠킨스와 연동하여 pr이 올라올 때나 머지가 될 때에 정적 분석을 실행하고 리포트를 낼 수 있도록 수정해보겠다.

    프로젝트를 진행하며 놓쳤던 버그들이나 자잘한 최적화를 도와주는 정적 분석 도구를 사용하여 보다 나은 프로젝트를 만들어감에 즐거웠던 시간이었다. 앞으로도 잘 활용하여 프로젝트 발전을 도모해보겠다.

     

     

    댓글

Toneyparky Blog