CI를 구축해보자

SeokHwan An·2023년 8월 31일
1

shook

목록 보기
6/15

팀 작업을 진행하면서 각자 맡은 부분이 생기고 이를 나누어서 작업을 진행하다보니 작업 결과물을 통합(통합 속에는 빌드를 하는 과정과 테스트를 하는 과정이 포함됩니다.)하는 과정이 필요했습니다.

이를 수행하기 위해서 CI(Continuos Integration)작업이 필요했고 이를 자동으로 처리하기 위해 CI Tool을 이용했습니다.

💡 git은 CI 툴이 아닌가요?
일단 git은 CI툴이 아닙니다.
처음 CI라는 용어를 접했을 때 git이 가장 먼저 떠올랐습니다. 그 이유는 git을 통해 여러 작업을 하나의 파일로 통합을 시켜준다고 생각했기 때문이었습니다. 하지만 이는 잘못된 생각이었고 git는 VCS(Version Control System)으로 버전관리 시스템으로 CI와는 다른 개념의 tool 입니다.

CI Tool에는 여러 종류가 있습니다. Jenkins와 Github Action, TeamCity 등 다양한 CI 툴이 있는데요. 이 중에서 저희 팀은 Github Action으로 CI를 구축했습니다.

Github Action으로 CI를 진행하게 된 이유는 다음과 같습니다.

  • 팀원들 모두가 CI에 대해서 모두 처음 시도하는 것이다.
  • 다른 CI Tool에 비해서 learning curve가 적다.
  • 많이 구현되어 있는 액션을 활용할 수 있다.
  • YAML 형식의 계층 구조로 가독성이 높다
  • github 프로젝트 레포지토리 내에서 쉽게 CI 결과를 확인하고 CI 파일을 관리할 수 있다.

github Actions의 용어 정리

github Actions를 이용하기에 앞서서 용어 정리를 해보고자 합니다.

Event

event는 CI의 작업을 진행시키는 시작점입니다. 쉽게 말하면 등록한 CI의 작업이 어느 상황에 동작하는지를 설정하는 것입니다. event에는 push event, pull request event, issue event 등으로 다양합니다.

ex)

on:
  pull_request:
    branches: [main] # main branch로 pull request될 때 실행됩니다.
    types: [opened, synchronize, reopened]

위의 event 예시는 main 브랜치로 pull request 가 open 될 때 혹은 synchronize 될 때 또는 reopen 될 때 CI 작업이 실행을 하라는 것을 의미합니다.

다양한 event에 대해서 더 알아보려면 다음 링크를 확인해주세요

https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows

workflow

workflow는 말 그대로 “작업 흐름”을 정의하는 곳입니다. 앞선 설명한 event가 발생했을 때 workflow에 정의된 작업이 동작합니다. workflow는 repository 내부 디랙토리인 .github/workflow 에 위치하며 여러개의 workflow가 존재할 수 있습니다. 저희는 이번에 처리하는 작업은 CI이기 때문에 이번 workflow의 내용은 CI에 필요한 작업의 흐름이 정의 될 것입니다.

더 많은 정보를 알아보려면 다음 링크를 확인해주세요

https://docs.github.com/en/actions/using-workflows/about-workflows

job

job은 workflow의 실행 단위로 하나의 workflow 내부에는 하나 혹은 그 이상의 job이 정의 될 수 있습니다. 기본적으로 job은 병렬적으로 동작을 하며 job들 간의 순서가 필요한 경우 needs를 통해 처리하면 순차적으로 처리가 가능합니다.

job을 이용하는데 있어서 필수적으로 정의해야할 것은 runs-on 속성과 steps 입니다. runs-on은 job이 실행되는 환경을 설정하는 것이고 steps은 job 내부에서 순서를 가지고 실행되는 작업입니다. 이 때 step들끼리는 데이터를 주고 받을 수 있습니다.

job의 action을 직접 작성할 수 있지만 github marketplace에서 이미 구성된 action을 이용할 수 있습니다.

S-Hook의 CI

name: Backend CI

on:
  pull_request:
    branches: [main] 
    types: [opened, synchronize, reopened]

defaults:
  run:
    working-directory: backend

jobs:
  build:
    name: CI
    runs-on: ubuntu-latest

    steps:
      - name: Pull Repository
        uses: actions/checkout@v3

      - name: Set up JDK 17
        uses: actions/setup-java@v2 # 자바를 설치하는 명렁어
        with:
          java-version: '17'
          distribution: 'zulu'

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

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

      - name: Comment on test result
        uses: EnricoMi/publish-unit-test-result-action@v1
        if: always()
        with:
          files: '**/build/test-results/test/TEST-*.xml'

      - name: Show comment on fail part
        uses: mikepenz/action-junit-report@v3
        if: always()
        with:
          report_paths: '**/build/test-results/test/TEST-*.xml'
          token: ${{ github.token }}

      - name: Notify slack on CI fail
        uses: 8398a7/action-slack@v3
        with:
          status: ${{ job.status }}
          author_name: 백엔드 빌드 실패 알림
          fields: repo, message, commit, author, action, eventName, ref, workflow, job, took
        env:
          SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
        if: failure()

현재 저희팀의 CI 작업은 다음과 같은 방식으로 동작을 하고 있습니다. 저희 팀의 CI 목표는 개발한 작업이 잘 빌드가 되고 테스트에 통과가 되는지 파악을 하는 것입니다. 이때 테스트를 실패하는 경우에 실패한 테스트에 대해 알려주며 CI의 결과를 Slack으로 전송하여 모든 팀원들이 이를 확인할 수 있게 구성하였습니다.

이의 각 흐름에 대해서 살펴보겠습니다.

on:
  pull_request:
    branches: [main] 
    types: [opened, synchronize, reopened]

작업한 branch에서 main branch로 pull request 요청을 open할 때, synchronize할 때, reopen할 때 동작하도록 event를 설정했습니다.

defaults:
  run:
    working-directory: backend

위와 같이 defaults working-directory를 설정한 이유는 밑의 job은 백엔드 CI를 위한 동작이기 때문에 최상위 디랙토리가 아닌 backend 디릭토리로 설정한 것입니다.

jobs:
  build:
    name: CI
    runs-on: ubuntu-latest

    steps:
      - name: Pull Repository
        uses: actions/checkout@v3

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

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

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

      - name: Comment on test result
        uses: EnricoMi/publish-unit-test-result-action@v1
        if: always()
        with:
          files: '**/build/test-results/test/TEST-*.xml'

      - name: Show comment on fail part
        uses: mikepenz/action-junit-report@v3
        if: always()
        with:
          report_paths: '**/build/test-results/test/TEST-*.xml'
          token: ${{ github.token }}

      - name: Notify slack on CI fail
        uses: 8398a7/action-slack@v3
        with:
          status: ${{ job.status }}
          author_name: 백엔드 빌드 실패 알림
          fields: repo, message, commit, author, action, eventName, ref, workflow, job, took
        env:
          SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
        if: failure()

마지막으로 job의 흐름에 대해서 설명을 하겠습니다.

  1. job이 실행되는 runner container의 환경은 ubunt에서 최신환경으로 설정을 했습니다.(이 부분은 나중에 배포를 하는 환경과 동일하게 설정하면 될 것 같습니다.)
  2. 현재 작업한 branch로 checkout을 한 뒤 pull 받아옵니다.
  3. 현재 프로젝트에서 사용하는 java 17버전을 다운로드를 합니다.
  4. 프로젝트를 빌드를 할 수 있게 gradlew에 실행 권한을 부여합니다.
  5. 빌드를 실행하면서 테스트를 진행합니다.
  6. 테스트의 실행 결과를 나타냅니다.

위의 사진과 같이 CI가 진행이 되면 pull request에 테스트의 결과가 나타납니다. 위의 경우에는 모든 테스트를 통과한 결과이며 실패한 테스트가 있으면 actions 탭에서 ci 정보를 보는 것에서 실패한 테스트에 대해서 자세하게 살펴볼 수 있습니다.

  1. 마지막으로 테스트가 실패를 하는 경우 slack의 webhook을 통해 실패 사실을 알려줍니다.

위와 같이 CI가 실패를 하는 경우 다음과 같이 slack에 알림이 오는 것을 확인할 수 있습니다.

github action을 이용하면서 느낀점

처음 진행해보는 CI 작업이었지만 github 래퍼런스에 사용방법이 상세하게 나타나 있고 많은 action들이 많이 구성되어 있어서 생각보다는 오래걸지리 않고 CI를 완성할 수 있었습니다. CI를 완성하고 이에 실패해보는 경험을 통해서 동작하지 않은 코드가 main brach에 병합되는 것을 막을 수 있어서 보다 코드의 안정성을 높일 수 있어서 의미있는 시간이었습니다.

래퍼런스

https://github.com/marketplace?type=actions
https://docs.github.com/ko/actions
https://www.youtube.com/watch?v=iLqGzEkusIw

0개의 댓글