CI 빌드 시간 400% 개선하기 (feat: Github Action)

covy·2024년 3월 3일
post-thumbnail

현재 우리 프로젝트에서 CI는 15~19분이 걸린다. (시작한지 2주 됐다)
추후 CD를 추가하기 전에 이 말도 안되는 시간을 줄여보고자 한다.

먼저 오래걸리는 명령어를 보자

  • build with Gradle (캐시 사용)
  • Post Cache Gradle packages
  • Post set up JDK 17

3개 명령어 중 build with Gradle만 우리가 선언한 것이고 나머지 명령어는 자동으로 실행된 것이라 빌드 시간을 줄이는 것의 필요성을 느꼈다.

원인을 분석했는데, 2가지 원인을 찾을 수 있었다.

  • 캐시 파일을 못찾고 있다.
  • 현재 private repository라 성능이 느리다.

캐시 파일을 못찾고 있다

빌드의 속도에서는 빌드 파일이 캐싱되어 있는가가 많은 영향을 끼친다. 그래서 이전에 gradle 캐시를 하는 코드를 추가했었는데, 확인해보니 아래 오류 메세지가 뜨고 있었다.

Cache not found for input keys

input keys를 통한 캐시된 파일을 못찾고 있다는 오류였다. 왜 이런 문제가 나타날까?

Cache’s are scoped to a key and a branch, so a cache created on branch-A won’t be accessible by branch-B unless branch-A is the default branch.

정리하자면 default branch가 아닌 브랜치에서 캐시를 끌어다 쓸 수 없다고 한다.
보통 PR시에 workflow를 실행하는데, 내 경우에 default에서 파생된 브랜치에서 캐시 생성을 하고있기 때문에 접근이 불가능한 것이다.

해결방법은 없나?

Main Branch에서 캐싱을 해라고 공식적으로 이야기한다. 다만 워크플로에 적합하지 않는 해결방법이라 말이 많다. 하지만 현재 이것밖에 방법이 없다.

결론: 캐싱을 위한 워크플로를 만들자

default branch에 푸쉬가 될 때마다 캐싱을한다.
default branch에서 파생되는 branch는 캐싱된 데이터로 사용할 수 있다.

name: Android CI

on:
  push:
    branches: ["develop"]

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v3

      # Gradle 캐싱: 빌드 시간과 네트워크 통신을 줄이기 위해 의존성 패키지들을 캐싱하여 재사용
      - name: Cache Gradle packages
        uses: actions/cache@v3
        with:
          path: |
            ~/.gradle/caches
            ~/.gradle/wrapper
          key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties', '**/buildSrc/**/*.kt') }}
          restore-keys: |
              ${{ runner.os }}-gradle-

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

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

      - name: Access Google Client Id
        env:
          GOOGLE_CLIENT_ID: ${{ secrets.GOOGLE_CLIENT_ID }}
        run: |
          echo "GOOGLE_CLIENT_ID=\"$GOOGLE_CLIENT_ID\"" >> local.properties

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

Github 성능 정책

Private Repository Public Repository Action Runner 성능차이가 있다.
성능은 아래 이미지와 같다

Public Repository

Private Repository

우리는 Private Repository로 운영하고 있어, 느린 점도 있다.

빌드 대신 Test만 실행 그리고 병렬적으로

선택적으로 build 대신 test만 돌려서 빌드시간을 아낄 수 있다(캐시를 안했을 기준 꽤나 많은 시간이 차이가 난다.)
또한 --parallel(병렬 실행)을 하여 속도를 당길 수 있을 것이다.

./gradlew build --parallel
./gradlew test --parallel

우리가 앞당긴 시간 (Private Repo 기준)

Before

After

After - Public Repo로 돌렸을 때

비용 절감 수치

PR 빌드시간이 대략? 4배정도 빨라졌다.

절대적으로는 Push시에도 5분정도 빌드를 하기 때문에 사실상 30%~50% 정도로 비용이 절감이 되었다고 볼 수 있다. Push시 빌드는 앱 CD 절차에 활용할 수 있을 것 같으므로 긍정적인 개선으로 본다.

reference

0개의 댓글