CI\CD/GitHub Actions

[GitHub Actions] cache Action 사용해 반복되는 작업 캐싱하기

반복되는 작업 캐싱이 필요한 이유

CI/CD 작업을 하면 계속해서 반복되는 작업들이 있다. 만약 이런 작업들이 반복된다면 리소스가 낭비되며, 요금 청구가 늘어날 수 있다. 특히 GitHub Action의 경우 무료 사용자에게는 2000분의 시간만을 무료로 제공해주고 Pro 사용자에게는 3000분만을 무료로 제공해주기 때문에 리소스 사용을 아껴야 할 필요가 있다.

 

이러한 반복되는 작업들은 GitHub Actions에서 제공해주는 cache Action을 통해 해결이 가능하다. cache Action은 GitHub에서 공식적으로 지원하는 캐싱 방식이다.

 

참고 : https://github.com/actions/cache

 

GitHub - actions/cache: Cache dependencies and build outputs in GitHub Actions

Cache dependencies and build outputs in GitHub Actions - GitHub - actions/cache: Cache dependencies and build outputs in GitHub Actions

github.com

 

 

cache Action이란?

cache Action은 특정한 path의 작업물들을 특정한 key 값을 통해 캐싱 해놓고 만약 같은 key가 사용된다면 캐싱된 파일을 꺼내와 사용할 수 있도록 만들어 놓은 Action이다. 따라서 cache Action의 대표적인 파라미터는 key와 path 두가지이다.

 

  • key: 캐싱된 파일을 구분하는 Key
  • path: 어떤 경로의 파일들이 모두 저장되고 복구될 것인지를 지정

 

Step은 다음과 같이 만든다.

- name: Cache Action
  uses: actions/cache@v3
  with:
    path: [path]
    key: [key]

 

Gradle 파일 캐싱하기

보통 안드로이드나 스프링에서는에서는 빌드에 gradle 파일을 사용하기 때문에 gradle을 캐싱한다. 경로는 ~/.gradle/caches 와 ~/.gradle/wrapper 로 잡으면 된다.

 

해당 경로의 파일들은 실행 os가 변경되었을 때 다시 설정되어야 하므로 runner.os 를 key에 추가한다. 또한 .gradle 파일 혹은 gradle-wrapper.properties 파일이 변경되었을 때도 ~/.gradle/caches 와 ~/.gradle/wrapper 경로의 파일들이 다시 설정되어야 하기 때문에 hashFiles 메서드들 통해 해당 파일들(.gradle, gradle-wrapper.properties)로 해시값을 생성해 key로 만든다.

- uses: actions/cache@v3
  with:
    path: |
      ~/.gradle/caches
      ~/.gradle/wrapper
    key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
    restore-keys: |
      ${{ runner.os }}-gradle-

 

그러면 .gradle 파일이 추가, 삭제, 변경되거나  gradle-wrapper.properties 파일이 추가, 삭제, 변경되거나 가상 머신의 os 가 변경되었을 때 gradle sync를 다시 하게 된다.

 

 

cache Action 사용해 성능 비교해보기

자 이제 cache를 사용할 때와 하지 않을 때 빌드 속도 차이를 비교해보자.

 

아래는 이전 글에서 사용했던 안드로이드 테스트 후 빌드해 Job Artifact를 만드는 Workflow 파일이다.

name: Job Artifacts - Make Android APK

on:
  workflow_dispatch:

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - name: Check out Repository
        uses: actions/checkout@v3

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

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

      - name: Test with Gradle
        run: ./gradlew test

  build:
    needs: test
    runs-on: ubuntu-latest
    steps:
      - name: Check out Repository
        uses: actions/checkout@v3

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

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

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

      - name: Upload Apk
        uses: actions/upload-artifact@v3
        with:
          name: android-artifact
          path: app/build/outputs/apk/release

 

 

우리는 여기에 캐싱을 하는 Action을 중간에 추가할 것이다.

name: Job Artifacts - Make Android APK - Cached

on:
  workflow_dispatch:

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - name: Check out Repository
        uses: actions/checkout@v3

      # 캐싱 추가
      - name: Cache Gradle
        uses: actions/cache@v3
        with:
          path: |
            ~/.gradle/caches
            ~/.gradle/wrapper
          key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
          restore-keys: |
            ${{ runner.os }}-gradle-

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

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

      - name: Test with Gradle
        run: ./gradlew test

  build:
    needs: test
    runs-on: ubuntu-latest
    steps:
      - name: Check out Repository
        uses: actions/checkout@v3

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

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

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

      - name: Upload Apk
        uses: actions/upload-artifact@v3
        with:
          name: android-artifact
          path: app/build/outputs/apk/release

 

이를 실행해보면 Action에 Gradle 이 성공적으로 캐싱 되었다는게 나온다.

 

성능 비교해보기

이전에 캐싱을 하지 않았을 때 build 단계에서 Build With Gradle Step이 걸린 시간은 1분 18초였다.

 

 

Gradle을 캐싱 하면 그 시간이 47초로 줄어든 것을 확인할 수 있다.

 

 

 30초 정도가 줄어들었다. 여기서는 간단한 Gradle을 사용해서 성능 차이가 엄청나지는 않고, Gradle을 사용하는 Job이 두개 뿐이라서 많은 효과는 못본다. 하지만 만약 Gradle 이 복잡해져서 빌드에 시간이 15분씩 걸린다면? Job이 3개, 4개가 된다면 효과는 엄청나다.  만약 위 작업으로 1번 실행할 때마다 10분을 줄일 수 있고, 만약 하루 평균 100번씩 돌아간다고 하면 리눅스 서버 기준 하루에 8~256달러 정도의 비용을 아낄 수 있다.

 

 

다른 cache Action 스크립트 확인해보기

다른 언어와 시스템에 대한 스크립트들도 아래에서 확인할 수 있다. 한국에서 자주 사용되는 방식 위주로 종류를 선정했다. 만약 다른 언어와 빌드 시스템에 대한 캐싱이 필요하다면 문서를 확인해보도록 하자.  

 

자 이제 GitHub Action에 cache를 도입해 최적화를 해보도록 하자.

반응형

 

이 글의 저작권은 Dev World 에 있습니다. 글, 이미지 무단 재배포 및 변경을 금지합니다.

 

 

Kotlin, Android, Spring 사용자 오픈 카톡

오셔서 궁금한 점을 질문해보세요!
비밀번호 : kotlin22

open.kakao.com