본문 바로가기

개발 이야기/실무 Recipe

github action cache 하기 | 매번 build 하신다고요?

이번 포스팅은 쇼핑몰 컨셉이다. 빰빠빠. 빰빠빰. 빠라 빠라바라 빠밤밤.

 

 

이런!

github action이 한 두개가 아니라고요? action을 돌릴 때마다 너무 느려 답답하다고요? 그런 당신을 위해 준비했습니다!

 

 

브금

 


 

dependency, build caching하는 방법, 절찬리 공개 중!

 

source: 유준호 유튜브 채널 crank chop

 

자, 지금부터 제가 소개할것은 그리 대단한것은 아니지만 엄청난 걸 소개해드리려고 합니다!

actions/cache 액션을 사용해서 캐싱하는 방법입니다. 자, 아래의 코드를 보시죠!

 

name: Caching with npm

on: push

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v2

    - name: Cache node modules
      uses: actions/cache@v2
      env:
        cache-name: cache-node-modules
      with:
        # npm cache files are stored in `~/.npm` on Linux/macOS
        path: ~/.npm
        key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
        restore-keys: |
          ${{ runner.os }}-build-${{ env.cache-name }}-
          ${{ runner.os }}-build-
          ${{ runner.os }}-

    - name: Install Dependencies
      run: npm install

    - name: Build
      run: npm build

    - name: Test
      run: npm test

 

key

갑작스러운 코드에 놀라지마시고 key에 주목해주세요! 캐시를 저장할 때 생성되는 키입니다. 캐싱된 데이터를 찾을 때 이 key를 사용합니다. 실행 context에서 가져온 package-lock.json 파일을 해싱해서 키로 저장합니다. 만약 key가 그대로면 캐싱된 파일을 찾아서 사용하고, key가 바뀌었다면 변경사항이 있다고 판단해 다시 install 합니다. 👍

 

runner.os

runner.os에는 운영체제가 들어갑니다. ubuntu를 쓰고 있으니 Linux가 들어가겠군요.

 

restore key

만약 key로 못찾았다면 restore key에 매치되는 또 다른 키를 찾아 사용합니다. 사용되는 순서는 위에서 아래부터입니다.

 

 


 

인생은 실전!

이제 캐싱한 dependency를 다른 job에서 사용해보겠습니다. main 브랜치에 Pull Request를 날릴 때마다 실행되는 workflow.yml 파일입니다.

 

source: 유준호 유튜브 채널 사무라이 칼

 

자 하나하나 파헤쳐 볼까요?

 

name: Pull Request CI

on:
  pull_request:
    branches:
      - main

env:
  CACHED_DEPENDENCY_PATHS: ${{ github.workspace }}/node_modules
  CACHED_BUILD_PATHS: ${{ github.workspace }}/.next
  BUILD_CACHE_KEY: ${{ github.sha }}

jobs:
  job_install_dependencies:
    name: Install Dependencies
    runs-on: ubuntu-latest
    timeout-minutes: 15
    steps:
      - name: Check out current commit (${{ github.sha }})
        uses: actions/checkout@v2
      - name: Set up Node
        uses: actions/setup-node@v1
      - name: Compute dependency cache key
        id: compute_lockfile_hash
        run: echo "::set-output name=hash::${{ hashFiles('package-lock.json') }}"
      - name: Check dependency cache
        uses: actions/cache@v2
        id: cache_dependencies
        with:
          path: ${{ env.CACHED_DEPENDENCY_PATHS }}
          key: ${{ steps.compute_lockfile_hash.outputs.hash }}
      - name: Install dependencies
        # use '.', not '[]' with hyphenated variables
        # https://github.com/nektos/act/issues/104#issuecomment-592892249
        if: steps.cache_dependencies.outputs.cache-hit == ''
        run: npm install
    outputs:
      dependency_cache_key: ${{ steps.compute_lockfile_hash.outputs.hash }}

  job_build:
    name: Build
    needs: job_install_dependencies
    runs-on: ubuntu-latest
    timeout-minutes: 15
    steps:
      - name: Check out current commit (${{ github.sha }})
        uses: actions/checkout@v2
      - name: Set up Node
        uses: actions/setup-node@v1
      - name: Check dependency cache
        uses: actions/cache@v2
        with:
          path: ${{ env.CACHED_DEPENDENCY_PATHS }}
          key: ${{ needs.job_install_dependencies.outputs.dependency_cache_key }}
      - name: Check build cache
        uses: actions/cache@v2
        id: cache_built_packages
        with:
          path: ${{ env.CACHED_BUILD_PATHS }}
          key: ${{ env.BUILD_CACHE_KEY }}
      - name: Build packages
        if: steps.cache_built_packages.outputs.cache-hit == ''
        run: npm run build
    outputs:
      dependency_cache_key: ${{ needs.job_install_dependencies.outputs.dependency_cache_key }}

  job_audit:
    name: Audit
    needs: job_build
    # ... 생략

  job_size_check:
    name: Size Check
    needs: job_build
    timeout-minutes: 15
    runs-on: ubuntu-latest
    if: ${{ github.head_ref }}
    steps:
      - name: Check out current commit (${{ github.sha }})
        uses: actions/checkout@v2
      - name: Set up Node
        uses: actions/setup-node@v1
      - name: Check dependency cache
        uses: actions/cache@v2
        with:
          path: ${{ env.CACHED_DEPENDENCY_PATHS }}
          key: ${{ needs.job_build.outputs.dependency_cache_key }}
      - name: Check build cache
        uses: actions/cache@v2
        with:
          path: ${{ env.CACHED_BUILD_PATHS }}
          key: ${{ env.BUILD_CACHE_KEY }}
      - name: Check bundle sizes
        uses: andresz1/size-limit-action@v1.4.0
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}
          skip_step: build

 

 

env path

  • CACHED_DEPENDENCY_PATHS: install dependency가 위치한 경로입니다.
  • CACHED_BUILD_PATHS: build 폴더가 위치한 경로입니다.
  • BUILD_CACHE_KEY: github commit hash code 입니다.

 

env:
  CACHED_DEPENDENCY_PATHS: ${{ github.workspace }}/node_modules
  CACHED_BUILD_PATHS: ${{ github.workspace }}/.next
  BUILD_CACHE_KEY: ${{ github.sha }}

 

 

install dependency

 

install job을 추가해줍니다. job_install_dependencies는 다른 job에서도 쓰일 이름이니 최대한 직관적으로 적어주세요.

 

Compute dependency cache key 스텝에서는 위에서 말한 대로 package-lock.json 파일을 해시하여 hash라는 이름으로 output을 저장합니다.

 

Check dependency cache 스텝에서는 actions/cache를 사용해 캐시된 dependency가 있는지 체크합니다. key: ${{ steps.compute_lockfile_hash.outputs.hash }}를 보니 step id인 compute_lockfile_hash의 outputs.hash 키로 확인하고 있군요.

 

그 다음 cache-hit가 false라면 npm install을 합니다. 만약 cache-hit가 true라면 install 하지 않겠지요?

 

jobs:
  job_install_dependencies:
    name: Install Dependencies
    runs-on: ubuntu-latest
    timeout-minutes: 15
    steps:
      - name: Check out current commit (${{ github.sha }})
        uses: actions/checkout@v2

      - name: Set up Node
        uses: actions/setup-node@v1

      - name: Compute dependency cache key
        id: compute_lockfile_hash
        run: echo "::set-output name=hash::${{ hashFiles('package-lock.json') }}"

      - name: Check dependency cache
        uses: actions/cache@v2
        id: cache_dependencies
        with:
          path: ${{ env.CACHED_DEPENDENCY_PATHS }}
          key: ${{ steps.compute_lockfile_hash.outputs.hash }}

      - name: Install dependencies
        # 하이픈 변수에는 '[]'가 아니라 '.'을 사용하세요
        # https://github.com/nektos/act/issues/104#issuecomment-592892249
        if: steps.cache_dependencies.outputs.cache-hit == ''
        run: npm install
    outputs:
      dependency_cache_key: ${{ steps.compute_lockfile_hash.outputs.hash }}

 

아니 이럴수가! 정말 실행되지 않았군요. 놀랍게도 install이 23초 밖에 안걸렸습니다!

 

 

build

job_build:
    name: Build
    needs: job_install_dependencies
    runs-on: ubuntu-latest
    timeout-minutes: 15
    steps:
      - name: Check out current commit (${{ github.sha }})
        uses: actions/checkout@v2

      - name: Set up Node
        uses: actions/setup-node@v1

      - name: Check dependency cache
        uses: actions/cache@v2
        with:
          path: ${{ env.CACHED_DEPENDENCY_PATHS }}
          key: ${{ needs.job_install_dependencies.outputs.dependency_cache_key }}

      - name: Check build cache
        uses: actions/cache@v2
        id: cache_built_packages
        with:
          path: ${{ env.CACHED_BUILD_PATHS }}
          key: ${{ env.BUILD_CACHE_KEY }}

      - name: Build packages
        if: steps.cache_built_packages.outputs.cache-hit == ''
        run: npm run build
    outputs:
      dependency_cache_key: ${{ needs.job_install_dependencies.outputs.dependency_cache_key }}

 

needs: job_install_dependencies : 위의 job name이 기억나시나요? 앞의 job이 선행되어야 한다는 걸 뜻합니다! 아래처럼 직렬로 실행될지 병렬로 실행될 지 알 수 있습니다.

- Check dependency cache: install job의 output인 dependency key로 캐싱된 파일을 찾습니다.

- Check build cache: env 에서 정한 build cache key를 사용해 cache된 파일을 찾습니다.

- cache-hit가 true면 캐싱 파일을 사용하고 false면 build 합니다.

- outputs: 다음 job에서는 install의 output을 모르기 때문에 build job에서 한 번 더 dependency_cache_key를 output으로 저장합니다.

 

 

 

do something

이제는 캐시된 dependency와 build 파일을 갖다쓰기만 하면 됩니다. needs로 job_build 가 선행되어야 함을 알려줍시다. 그리고 dependency key와 build key로 캐시 파일을 체크하고 그 다음 원하는 액션을 실행시켜주시면 됩니다!

 

  job_size_check:
    name: Size Check
    needs: job_build
    timeout-minutes: 15
    runs-on: ubuntu-latest
    steps:
      - name: Check out current commit (${{ github.sha }})
        uses: actions/checkout@v2

      - name: Set up Node
        uses: actions/setup-node@v1

      - name: Check dependency cache
        uses: actions/cache@v2
        with:
          path: ${{ env.CACHED_DEPENDENCY_PATHS }}
          key: ${{ needs.job_build.outputs.dependency_cache_key }}

      - name: Check build cache
        uses: actions/cache@v2
        with:
          path: ${{ env.CACHED_BUILD_PATHS }}
          key: ${{ env.BUILD_CACHE_KEY }}

      - name: Check bundle sizes
        uses: andresz1/size-limit-action@v1.4.0
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}
          skip_step: build

 

 

자, 잘 붙었습니다! 당신도 이제 팀에서 멋진 CI 꾼이 될 수 있습니다!

 

 

 

 

source: 유준호 유튜브 채널 - 사무라이 칼

 

"이 포스팅을 통해 action을 손쉽고 빠르게 사용할 수 있게 되었어요!"

 

 


 

지금 당장 github action cache를 사용해보세요!

사용을 원하시는 분들은 아래 링크를 참고해주세요.

source: cj 홈쇼핑

 

캄사합니다! 😉