로컬 환경에서 개발을 할 때는 외부 패키지를 최초에 딱 한 번만 설치하면 되지만, 항상 새롭게 셋업되는 CI 서버에서는 이 작업을 매번 다시 해야합니다.
깃허브에서 제공하는 캐시(Cache) 액션을 사용하여 CI 서버에서 발생할 수 있는 불필요한 패키지 재설치를 예방하여 워크플로우의 최적화를 해보았습니다.
테스트 환경
- Runner 환경: ubuntu-20.04
- Node.js 버전: 20.15.0 (.nvmrc 파일 기반)
- 패키지 매니저: Yarn
- 캐싱 대상: node_modules
- 의존성 파일: yarn.lock
해당 레포에는 `.github/workflows` 폴더 안에 `deploy-dev/release/production.yml` (환경별로 각각의 3개의 파일이 존재) 이 있는데요.
PR 을 생성하고 merge 를 하면 github action workflow 에 작성된 코드로 CI/CD 자동배포가 진행됩니다.
개발 레포에서 [development 환경 기준] 워크플로 평균 실행시간이 1분 10초 ~ 1분 40초 사이 입니다.
그 중에서 `의존성 설치` 와 `빌드` 쪽에서 시간 소요가 많은 것을 볼 수 있습니다.
이번에는 `의존성 설치` 하는 부분의 속도를 줄여보는 작업을 시작하겠습니다.
[development 환경 기준] .github/workflows` 폴더 안에 `deploy-dev.yml 파일 step 중에
`name: Install dependencies. run: yarn ` 을 실행하는 단계를 보면,
jobs:
deploy_to_production:
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20.15.0
- name: Install dependencies 👈
run: yarn
무려 20초가 걸리는 걸 알 수 있습니다.
매번 `Install dependencies` 를 하는 것 대신, 의존성의 변경이 있을 때만 딱 1번 의존성을 설치하고 해당 의존성을 캐싱해두면 많은 시간 절약을 할 수 있을 것 같은데요.
의존성을 캐싱하기 위해서는 `node_modules` 폴더를 캐싱하면 됩니다.
캐시 적용
step 에 아래와 같은 코드를 추가해줍니다.
👇 add this!
- name: Cache node_modules
uses: actions/cache@v3
id: yarn-cache
with:
# 캐싱할 대상을 정합니다. (대상의 path를 지정)
# 여기서는 npm에서 의존성이 설치되는 디렉터리인 node_modules를 지정
path: |
node_modules
.yarn/cache
# 캐싱의 기준은 key를 기준으로 합니다.
# 의존성이 변경되면, 함께 변경되는 파일인 package-lock.json을 key로 잡아줍니다.
key: ${{ runner.os }}-node-modules-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-node-modules-
# key가 유효하지 않은 경우 runner의 운영체제 값과 node라는 suffix를 key로 복구합니다.
# 결과적으로 package-lock.json이 변경되지 않았다면 캐싱된 node_modules를 사용합니다.
# 만약 복구될 캐시가 없다면 아래에서 사용할 cache-hit는 false가 됩니다.
path 에 명시되어 있는 파일들이 캐싱이 되고, 캐싱된 파일을 재사용할 경우 path 에 명시되어 있는 경로에 다시 옮겨져 실행됩니다.
`cache action` 을 추가하고, 다음 step 에서 `cache hit` 을 기준으로 `Install Dependencies` 를 할지 말지 결정하는 코드도 추가해줍니다.
- name: Install dependencies
if: steps.cache.outputs.cache-hit != 'true' 👈add this!
run: yarn
워크플로우 실행
처음 Actions가 실행될 때 Cache가 존재하지 않기 때문에 Cache Action이 실행될때 로그가 찍힙니다.
- (Run actions/cache@v3)
- Cache not found for input keys: Linux-node-modules-f9a890966f638992bedf436d0fa242f47672707de2481d74488676d053e5988c, Linux-node-modules-
- Cache Key의 형태는 우리가 지정한 ${{ runner.os }}-node-modules-${{ hashFiles('**/yarn.lock') }}
의존성 설치에는 24s 가 소요되었습니다.
Post Cache actions step 은 GitHub Actions의 step이 종료되면 `actions/cache` 패키지가 워크플로우를 종료하면서 추가로 마무리하는 action입니다. 이 step에서 캐시가 저장되었음을 캐시 key와 함께 알려주고 있는데요. 그러면 캐시가 실제로 GitHub에 저장되어 있는지 확인해 봅시다.
GitHub Repository의 Actions -> Caches 탭을 통해 캐시 저장소로 들어가세요.
70 MB의 방금 설치한 의존성 파일이 캐시 된 것을 확인할 수 있습니다. workflow 에서 생성된 cache key 와 동일한 네이밍을 가지고 있는 것을 볼 수 있습니다.
이번에는 저장된 캐시가 잘 동작하는지 보기 위해 `src` 파일 내부의 소스 코드를 하나 수정하고 push 를 해봅니다. (yml 파일은 수정하지 않음)
상단의 Run actions/cache@v3에 따르면 캐시가 정상적으로 복원되었다고 명시되어 있습니다.. 이유는, 첫 번째 GitHub Actions가 동작할 때 만들어 둔 캐시가 있기 때문이고, 그를 복원시켰기 때문인데요.
그리고, 의존성에 변함이 없기 때문에 Install dependencies 는 실행시키지 않아서 0s 소요인 것 을 볼 수 있다.
- name: Install dependencies
if: steps.yarn-cache.outputs.cache-hit != 'true' 👈 해당 조건문으로 실행되기 때문!
run: yarn
결과
기존 dependencies 설치 소요시간 : 20 s
cache 적용 후 dependencies 설치 소요시간 : 0s + 4s (Cache node+module) + 3s (Post Cache node_modules) = 7s
- 의존성 설치 시간: 0초 (캐시에서 복원되었으므로 설치가 불필요)
- 캐시 검색: 4초
- Post Cache 처리: 3초
- 결과적으로, 7초 만에 종속성 준비가 완료되었습니다.
[구분] 캐싱 적용 전 캐싱 적용 후
Dependencies 설치 시간 | 20초 | 7초 |
• Cache hit 여부 | 해당 없음 | Cache hit (100%) |
• 세부 시간 분석 | ||
• 캐시 검색 | N/A | 4초 |
• Post Cache | N/A | 3초 |
캐싱 적용을 통해 의존성 설치에 소요되는 시간을 65% 단축하였습니다.
(20초 → 7초)
version upgrade
actions/cache@v3 → actions/cache@v4로 업그레이드 적용.
https://github.com/actions/cache
버전 v4로 올려야 한다고 합니다. actions/cache@v4 로 코드 변경해주시면 됩니다!
참고
'front-TEST' 카테고리의 다른 글
[vue.js] Storybook + Quasar + Vue3 (스토리북에 Quasar적용) (0) | 2024.05.08 |
---|---|
[vue.js] storybook 도입 (vue3 + vite) (1) | 2024.05.03 |
Mixpanel + vue 연동 (0) | 2024.02.27 |
실무에서 테스트 환경 적용기 [cypress, vue] (1) | 2024.02.01 |
프론트엔드 개발에서 테스트란? (0) | 2023.09.02 |