며칠 전에는 Front
쪽 Build
CI의 속도를 개선해봤습니다.
해당 글을 참조 해주시면 됩니다.
오늘은 CD쪽의 속도를 개선해보겠습니다.
npm
의 node_modules
캐싱하기workflow
의 로그를 살펴보니, 며칠전에 개선한 npm
의 의존성 캐싱
이 적용이 되어있지 않았습니다.
그래서 제일 먼저, npm
의 node_modules
에 캐싱을 적용 해주겠습니다.
jobs:
build:
name: Build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
... 생략 # Set up JDK 17, # Grant execute permission for gradlew
- name: Setup Gradle
uses: gradle/actions/setup-gradle@ec92e829475ac0c2315ea8f9eced72db85bb337a # v3.0.0
- name: Build with Gradle Wrapper
run: ./gradlew build
working-directory: ./my-garden-be
jobs:
build:
name: Build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
... 생략 # Set up JDK 17, # Grant execute permission for gradlew
- name: Setup Gradle
uses: gradle/actions/setup-gradle@ec92e829475ac0c2315ea8f9eced72db85bb337a # v3.0.0
# 캐시 추가
- name: Check node modules cache
id: cache
uses: actions/cache@v4
with:
path: '**/node_modules'
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
# 캐시가 존재하므로, npmInstall 과정을 생략
- name: Build with Gradle Wrapper (skip npm install)
if: steps.cache.outputs.cache-hit == 'true'
run: ./gradlew build -x npmInstall
working-directory: ./my-garden-be
# 캐시가 존재하지않으므로, npmInstall 진행
- name: Build with Gradle Wrapper (npm install)
if: steps.cache.outputs.cache-hit != 'true'
run: ./gradlew build
working-directory: ./my-garden-be
이전 글에서 설명드렸던 내용과 거의 비슷합니다.
node_modules
를 찾아서 캐싱을 합니다. (캐시 키는 package-lock.json
)node_modules
를 load
하고 cache-hit
을 true
로 설정 // 키가 없으면, cache-hit
을 false
로 설정cache-hit
에 따라서 npmInstall
을 생략하거나 포함해서 gradle build
가 진행됩니다.캐싱하기 전에는 보시는 것처럼 vite Build
전에, 무조건 npmInstall
이 진행이 되었고 약 10초
정도의 시간이 소모됐습니다.
저장된 캐시가 없다면 캐시를 저장하는 과정에서 시간이 약 6초
정도 더 걸리긴 하지만,
한번 캐싱이 되면 보시는 것처럼 약 10초
정도 되던 npmInstall
과정이 생략됩니다.
캐시가 없을 때, 새로
save
하는step
(약 6초
소요)
캐시가 존재할 때,
load
하는step
(약 2초
소요)
캐시 load시에 약 2초
정도 걸리긴 하지만,
npmInstall
을 skip
함으로써 약 10초
의 시간을 아꼈기 때문에 대략 약 7초 ~ 8초
의 시간을 절약할 수 있었습니다.
Docker
캐시 삭제하기CD workflow
에서 docker image
를 빌드하는 순서는 먼저 docker buildx
를 설치하고, 해당 buildx
를 이용하여 docker image
를 build
합니다.
여기서 Build and push
를 살펴보면, 조금 특이한 점이 있습니다.
로그를 살펴보면서 설명을 드리겠습니다.
아래의 이미지는 Build and push
의 로그입니다.
1번
내용이 docker image
를 build
하는 부분이고,
2번
은 해당 image
를 캐싱하기 위해 준비하고 추출하는 과정입니다.
image
를 build
하는 시간 (3.3 + 1.0 = 4.3s
) 보다, 캐싱을 하는 시간 (5.2s
)이 더 긴 것을 보실 수 있습니다.
제 프로젝트에서는 완성된 이미지를 캐싱해도, 다시 재사용할 일이 없기 때문에 캐싱을 사용하지 않는 것이 시간 절약에 더 좋다는 판단을 내렸습니다.
그래서 해당 캐싱을 제거하여 시간을 조금이라도 단축시켜보겠습니다.
완성된 이미지를 재사용 하지 않는 이유에 대해서도 설명을 드리겠습니다.
현재 제 프로젝트는
docker image
를 사용하여CD
를 진행하고 있으며, 해당docker image
는jdk17-alpine
위에jar
파일을 복사하여 실행시키는 구조입니다.
(※jar
파일은GitHub Action Runner Instance
가docker image
를 만들기 전step
에서gradle
로build
를 합니다.)매번
CD
를 진행할 때마다 새로jar
를build
를 해서 배포하기 때문에, 캐싱된 데이터가 재사용 되지 않습니다.
# docker buildx 설치
- name: Set up docker buildx
uses: docker/setup-buildx-action@v3
... 생략 # GitHub Container Registry에 로그인
# Docker 빌드 & GitHub Container Registry에 푸시
- name: Build and push
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: ${{ env.DOCKER_IMAGE }}:latest
cache-from: type=gha
cache-to: type=gha, mode=min
# docker buildx 설치
- name: Set up docker buildx
uses: docker/setup-buildx-action@v3
... 생략 # GitHub Container Registry에 로그인
# Docker 빌드 & GitHub Container Registry에 푸시
- name: Build and push
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: ${{ env.DOCKER_IMAGE }}:latest
build-push-action
액션의 옵션인 cache-from
와 cache-to
를 제거하여, 캐시를 사용하지 않도록 했습니다.
캐시를 추출하던 과정이 사라진 것을 보실 수 있습니다.
캐시를 제거함으로써 캐시를 추출하던 시간을 아꼈기 때문에 대략 약 5초
의 시간을 절약할 수 있었습니다.
속도를 개선하기 전과 개선을 완료한 후를 비교하면, 1분 40초
→ 1분 25초
(약 15%
의 성능 향상)
docker image
를 build
하는 job
기준 (deploy
하는 시간은 고정적이므로 제외)
상황 | npm 의존성 캐싱 X | npm 의존성 캐싱 O |
---|---|---|
도커 캐싱 O | 1분 40초 | 1분 31초 |
도커 캐싱 X | 측정 안함 | 1분 25초 |