photocard backend server 개발일기

정적 코드 분석 AWS EC2 SonarQube 사용하여 Github Action CI 하기

한둥둥 2024. 12. 20. 18:01

🤗 정적 코드 분석 vs  동적 코드 분석

정적 코드 분석은 코드가 실행 되기 전 소스 코드 또는 바이너리 코드를 분석해 코드를 직접 실행하지 않고 코드의 구조, 문법, 스타일, 잠재적인 버그, 코드 복잡도, 보안 취약점등을 분석한다. 

정적 코드 분석은 코드 실행 없이 오류를 조기에 발견할 수 있는 장점이 있으나, 코드의 실제 실행 환경에서 발생하는 런타임 오류나 메모리 누수와 같은 동적인 문제는 감지할 수 없다는 단점

 

동적 코드 분석은 코드를 실제로 실행하는 동안 수행된다. 프로그램을 실행하면서 그 동작을 모니터링하고, 런타임에서 발생할 수 있는 메모리 누수, 성능 문제 , 예외 처리, 보안 문제 등을 분석 

 

정적 코드 분석 SonarQube를 도입하는 이유는 코드의 구조, 문법, 스타일 등등을 확인하기 위해서입니다. 

 

 광범위한 언어 지원 , 다양한 플러그인을 제공, 다양한 품질 게이트 등을 확인 할 수 있어 SonarQube를 도입했습니다. 이외에도 CI툴에 적용 할 수 있다. 

 

다른 정적 분석 도구 비교

1. ESLint (JavaScript/TypeScript 전용)

  • 장점: JavaScript와 TypeScript 강력한 린팅 도구, 커스터마이징이 용이하고, 다양한 플러그인을 통해 기능을 확장
  • 단점: JavaScript / TypeScript에 특화되어 있어 다른 언어 지원은 부족 
  • 결론 : 현재 진행하는 프로젝트가 Java 기반 프로젝트이기 때문에 채택하지 않음.

2. FindBugs / SpotBugs (Java 전용) : 

  • 장점: Java 코드의 버그를 찾는 데 특화된 도구. 효율적이고 정확한 분석 제공
  • 단점: Java 전용이므로 다른 언어에서 적용 불가능 
  • 결론: SonarQube에서 FindBugs/SpotBugs와 통합하여 사용할 수 있음. 채택 x 

3. PMD(Java, javaScript, APex등) : 

  • 장점: 다양한 언어를 지원함. 코드 스타일과 버그를 검출하는 데 유용합니다. 
  • 단점 사용자 인터페이스 직관적이지 않음
  • 결론: Sonarqube 인터페이스가 훨씬 좋기 때문에 sonarqube 채택하게됨. 

환경 선택

sonarqube를 사용하기 위해서는 설치가 필요함. sonarqube는 기본적으로 h2 db 사용합니다. 

H2 다수의 사용자 대량의 데이터 처리가 필요하고 고가용성이 필요한 프로덕션 환경에 적합하지 않음. 

 

저는 postgresql 하게 된 이유는 중단 없는 운영을 하고 싶은 생각이 컸습니다. << 해당 이유 때문에 postgresql을 선택하게 되었습니다. 

 

sonarqube

services:
  sonarqube:
    image: sonarqube:community
    hostname: sonarqube
    container_name: sonarqube
    read_only: true
    depends_on:
      db:
        condition: service_healthy
    environment:
      SONAR_JDBC_URL: jdbc:postgresql://db:5432/sonar
      SONAR_JDBC_USERNAME: sonar
      SONAR_JDBC_PASSWORD: sonar
    volumes:
      - sonarqube_data:/opt/sonarqube/data
      - sonarqube_extensions:/opt/sonarqube/extensions
      - sonarqube_logs:/opt/sonarqube/logs
      - sonarqube_temp:/opt/sonarqube/temp
    ports:
      - "9000:9000"
    networks:
      - ${NETWORK_TYPE:-ipv4}
  db:
    image: postgres:15
    healthcheck:
      test: ["CMD-SHELL", "pg_isready"]
      interval: 10s
      timeout: 5s
      retries: 5
    hostname: postgresql
    container_name: postgresql
    environment:
      POSTGRES_USER: sonar
      POSTGRES_PASSWORD: sonar
      POSTGRES_DB: sonar
    volumes:
      - postgresql:/var/lib/postgresql
      - postgresql_data:/var/lib/postgresql/data
    networks:
      - ${NETWORK_TYPE:-ipv4}

volumes:
  sonarqube_data:
  sonarqube_temp:
  sonarqube_extensions:
  sonarqube_logs:
  postgresql:
  postgresql_data:

networks:
  ipv4:
    driver: bridge
    enable_ipv6: false
  dual:
    driver: bridge
    enable_ipv6: true
    ipam:
      config:
        - subnet: "192.168.2.0/24"
          gateway: "192.168.2.1"
        - subnet: "2001:db8:2::/64"
          gateway: "2001:db8:2::1"

 

docker-compose를 사용한 구성 파일이다. 

 

1. SonarQube 서비스

 

이미지:

sonarqube:community: SonarQube 커뮤니티 버전 이미지를 사용.

 

컨테이너 이름:

container_name: sonarqube: SonarQube 컨테이너 이름을 sonarqube로 지정.

 

종속성:

depends_on: SonarQube가 PostgreSQL 서비스(db)가 건강 상태를 확인한 후에만 시작됨.

 

환경 변수:

SONAR_JDBC_URL: SonarQube가 PostgreSQL 데이터베이스에 연결하기 위한 JDBC URL.

jdbc:postgresql://db:5432/sonar: PostgreSQL 컨테이너(db)의 호스트네임과 포트 정보.

SONAR_JDBC_USERNAME: PostgreSQL 사용자 이름 (sonar).

SONAR_JDBC_PASSWORD: PostgreSQL 비밀번호 (sonar).

 

볼륨:

SonarQube 데이터를 컨테이너 외부에 저장하여 데이터 영속성을 유지.

sonarqube_data: SonarQube 데이터 디렉토리.

sonarqube_extensions: SonarQube 확장 플러그인 디렉토리.

sonarqube_logs: SonarQube 로그 파일 디렉토리.

sonarqube_temp: 임시 데이터 디렉토리.

 

포트 매핑:

9000:9000: 호스트의 9000번 포트를 컨테이너의 9000번 포트에 매핑(SonarQube UI에 접근).

 

네트워크:

${NETWORK_TYPE:-ipv4}: 네트워크 타입을 ipv4로 설정하며, 환경 변수로 동적으로 변경 가능.

 

2. PostgreSQL 서비스

 

이미지:

postgres:15: PostgreSQL 15 버전 이미지를 사용.

 

컨테이너 이름:

container_name: postgresql: PostgreSQL 컨테이너 이름을 postgresql로 지정.

 

헬스체크:

PostgreSQL의 상태를 확인하여 SonarQube가 데이터베이스가 정상 상태인지 확인 가능.

pg_isready 명령어로 PostgreSQL 상태 점검.

 

헬스체크 설정:

interval: 10s: 10초 간격으로 상태 확인.

timeout: 5s: 5초 동안 응답 없으면 실패로 간주.

retries: 5: 최대 5번 재시도.

 

환경 변수:

POSTGRES_USER: PostgreSQL 사용자 이름 (sonar).

POSTGRES_PASSWORD: PostgreSQL 비밀번호 (sonar).

POSTGRES_DB: 기본 데이터베이스 이름 (sonar).

 

 볼륨:

PostgreSQL 데이터를 컨테이너 외부에 저장하여 데이터 영속성을 유지.

postgresql: PostgreSQL의 일반 데이터.

postgresql_data: PostgreSQL의 주요 데이터 파일.

 

네트워크:

${NETWORK_TYPE:-ipv4}: 네트워크 타입을 ipv4로 설정하며, 환경 변수로 동적으로 변경 가능.

 

볼륨 구성

 

Docker 볼륨을 사용하여 데이터를 유지합니다:

1. sonarqube_data: SonarQube의 데이터 디렉토리.

2. sonarqube_temp: SonarQube의 임시 파일 디렉토리.

3. sonarqube_extensions: SonarQube 확장 플러그인.

4. sonarqube_logs: SonarQube 로그 파일.

5. postgresql: PostgreSQL 일반 데이터.

6. postgresql_data: PostgreSQL 데이터 파일.

 

초창기 아이디/ 비밀번호 admin 입니다.

 

 

github app 설정

http://<EC2_PUBLIC_IP>:9000에 sonarqube

 

 

setting> developer setting > new github app 으로 들어가면 github app 세팅 가능 

 

 

 

callback url의 경우 public ip 설정하면 된다. 

http://ec2-13-124-217-23.ap-northeast-2.compute.amazonaws.com:9000 이런식으로 접근하면 됨.

 

  • Checks : Read & write 로
  • GitHub Enterprise 인 경우 : Repository metadata를
  • GitHub.com 인 경우(일반 계정인 경우) : Metadata 를 Read-only 로
  • Pull Requests : Read & writ

 

oatuh로그인 설정을 할 경우 Account permission

  • Email addresses Read-only 를 추가하고

Organization permissions

  • Members Read-only
  • Projects Read-only

깃허브 앱 설정을 하고 나면 프로젝트 setting>integration>githb app에서 방금 설정한 github app을 설치

 

https://docs.sonarsource.com/sonarqube-server/9.9/devops-platform-integration/github-integration/

 

GitHub integration

SonarQube's integration with GitHub Enterprise and GitHub.com allows you to maintain code quality and security in your GitHub repositories.

docs.sonarsource.com

 

sonar 설정하기

사진은 이미.. 다 설정을 하여 못찍어서 패스하겠습니다. 

 

api url의 경우 github enterprise를 사용하는 경우 위쪽, 아닌 경우 아래쪽 url 적어주기 

 

 

깃허브  app 있는거 적어서 넣어주자..! 

gihub app id, client id, client secret, private key의 경우 속해있는 조직에서 setting> developer setting> github app setting > edit 

 

 

위에 페이지가 나오는데 맞춰서 설정 

 

name: Capo-SonarQube

on:
  pull_request:
    branches:
      - '*'

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout
        uses: actions/checkout@v3
        with:
          fetch-depth: 0

      - name: Set up JDK 17
        uses: actions/setup-java@v3
        with:
          java-version: '17'
          distribution: 'temurin'

      - name: Grant execute permission for gradlew
        run: chmod +x gradlew

      - name: Build with Gradle
        run: ./gradlew build

  sonarqube:
    needs: build
    permissions:
      issues: write
      pull-requests: write
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Set up JDK 17
        uses: actions/setup-java@v1
        with:
          java-version: 17

      - name: Cache SonarQube packages
        uses: actions/cache@v1
        with:
          path: ~/.sonar/cache
          key: ${{ runner.os }}-sonar
          restore-keys: ${{ runner.os }}-sonar

      - name: Cache Gradle packages
        uses: actions/cache@v1
        with:
          path: ~/.gradle/caches
          key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }}
          restore-keys: ${{ runner.os }}-gradle

      - name: Grant execute permission for gradlew
        run: chmod +x ./gradlew

      - name: Build and analyze
        env:
          SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
          SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}
          SONAR_PROJECT_KEY: ${{ secrets.SONAR_PROJECT_KEY }}
          SONAR_PROJECT_NAME: ${{ secrets.SONAR_PROJECT_NAME }}
          PR_NUMBER: ${{github.event.pull_request.number}}
        run: ./gradlew build sonarqube -Dsonar.login=${{ secrets.SONAR_TOKEN }} -Dsonar.host.url=${{ secrets.SONAR_HOST_URL }} -Dsonar.projectKey=${{ secrets.SONAR_PROJECT_KEY }} -Dsonar.projectName=${{ secrets.SONAR_PROJECT_NAME }} 
      
      - name: Comment Sonarqube URL
        uses: actions/github-script@v4
        env:
          SONAR_PROJECT_KEY: ${{ secrets.SONAR_PROJECT_KEY }}
          SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}
          PR_NUMBER: ${{ github.event.pull_request.number }}
        with: 
          script: |
            const { SONAR_PROJECT_KEY, SONAR_HOST_URL, PR_NUMBER } = process.env;
            github.issues.createComment({
              issue_number: context.issue.number,
              owner: context.repo.owner,
              repo: context.repo.repo,
              body: `📊 ${ SONAR_PROJECT_KEY }-${ PR_NUMBER } 분석 결과 확인하기 [링크] (${SONAR_HOST_URL})`
            });

 

 

[참고사이트]:

https://chaewsscode.tistory.com/255

 

[Spring] SonarQube로 프로젝트 정적 코드 분석

SonarQube란?SonarQube는 클린 코드를 구현하기 위한 정적 코드 분석 도구이다. 🤔 정적 코드 분석 vs 동적 코드 분석정적 코드 분석은 코드가 실행되기 전 소스 코드 또는 바이너리 코드를 분석해 코

chaewsscode.tistory.com

https://docs.sonarsource.com/sonarqube-server/9.9/devops-platform-integration/github-integration/

https://velog.io/@blacknwhites/docker-compose%EB%A5%BC-%EC%9D%B4%EC%9A%A9%ED%95%9C-SonarQube-%EB%8F%84%EC%9E%85%EA%B8%B0