yarn 에서 pnpm 으로, 그리고 CodeBuild 캐시

CodeBuild 에 S3캐시 + pnpm 묻히기

개요

현재 회사에서는 Next.js 프로젝트에 CodePipeline, CodeBuild 를 활용한 CI/CD 가 구축되어 있다.

CodeBuild 와 yarn classic 을 활용해 배포를 진행하게 되면 빌드 + 배포 시간이 평균 9분이 넘어간다.
예전에 Vercel 에서 빌드 + 배포를 진행했을 때 3분대가 나왔던 거랑 비교하면 9분이라는 굉장히 큰 시간을 빌드 + 배포에 쓰고 있다.

이를 줄여보고자 CodeBuild 의 S3 캐시와 yarn classic 을 pnpm 로 마이그레이션 하는 등 시도를 해봤다.

결론부터 말하자면 pnpm + S3 캐시를 도입 후 빌드+배포 시간이 평균 554초에서 평균 392초대로 25%가 감소했다.

yarn 에서 pnpm 으로

  1. pnpm 설치

    우선 pnpm 을 설치해야 한다. 공식문서에 여러 방법이 설명되어있지만 이 글에서는 corepack 을 활용한다.

    corepack 을 사용하기 위해서는 node 16.13 버전 이상이 필요하다.

     $ corepack enable
     $ pnpm -v
    
  2. node_modules 삭제

    npkill 을 활용하여 프로젝트의 모든 node_modules 를 삭제한다.

     $ npx npkill
    
  3. pnpm import

    pnpm import 를 활용해 기존 lockfile 로 부터 pnpm-lock.yaml 을 생성한다.

     $ pnpm import
    

    pnpm import 후 기존 lockfile

    만약 모노레포를 사용중이라면 pnpm-workspace.yaml 을 미리 생성해야 한다.

     # pnpm-workspace.yaml
     packages:
       # all packages in direct subdirs of packages/
       - 'apps/*'
       # all packages in subdirs of components/
       - 'components/**'
       # exclude packages that are inside test directories
       - '!**/test/**'
    

    참고: https://pnpm.io/cli/import

  4. 의존성 설치

     $ pnpm install
    

    추가로 package.jsonpackageManager 필드를 추가 하면 다른 환경에서 같은 pnpm 버전을 사용할 수 있다.

     // package.json
     {
       "packageManager": "pnpm@<version>"
     }
    

    자세한 내용은 node 공식문서에서 확인 할 수 있다.

이를 buildspec.yaml 에 적용하면 아래와 같은 코드가 된다.

# buildspec.yaml
version: 0.2

phases:
  install:
    runtime-versions:
      nodejs: 18
    commands:
      # pnpm 사용
      - corepack enable
      - pnpm -v
      - pnpm install --frozen-lockfile
  build:
    commands:
      # 혹은 모노레포를 사용중이라면 `pnpm -F <package-name> run build`
      - pnpm run build

CodeBuild 에 S3 캐시 적용하기

우선 S3 캐시를 적용할 CodeBuild 프로젝트 상세 페이지에 접속한다.
상세 콘솔에서 Edit > Artifacts 메뉴에 들어간다.

하단의 Additional configuration 을 확장해 보면 Cache TypeNo Cache 로 설정되어 있는 걸 확인 할 수 있다.

위 이미지와 같이 Cache TypeAmazon S3 로 변경한 뒤 Cache bucketCache path prefix 를 설정한다.

CodeBuild, pnpm 캐시 트러블 슈팅

트러블 슈팅으로 고생했는데, cache paths 에 node_modules 를 입력하면 S3 캐시 업로드가 진행이 되지 않는 이슈가 있었다. 이는 pnpm 이 기본적으로 의존성을 심볼릭 링크 방식을 사용함에 있어서 생기는 이슈였고, S3 는 심볼릭 링크 업로드를 지원하지 않는다.

해결 방법은 pnpm 의 공식 문서를 보다 찾게 되었다.

공통으로 pnpm config set store-dir <path> 부분이 자주 보이는데, 이를 buildspec.yaml 에 적용해 보니 S3 캐시 업로드가 정상적으로 진행이 되었다.

pnpm store 와 캐시를 추가하면 아래와 같은 코드가 된다.

# buildspec.yaml
version: 0.2

phases:
  install:
    runtime-versions:
      nodejs: 18
    commands:
      - corepack enable
      - pnpm -v
      # pnpm store 위치 설정
      - pnpm config set store-dir .pnpm-store
      - pnpm install --frozen-lockfile
  build:
    commands:
      - pnpm run build

# Cache 추가
cache:
  paths:
    - '.pnpm-store/**/*'
    - '.next/cache/**/*'

결론

-평균 초빌드 + 배포 횟수
yarn + No Cache55457
yarn + No Cache (최근 10회)49010
pnpm + No Cache4283
pnpm + Cache(pnpm)4083
pnpm + Cache(pnpm, Next.js)3922

아직 테스트 수가 적어서 더 지켜봐야 정확한 판단 가능하겠지만 당장 결과를 본다면,
yarn → pnpm 으로 변경한 것만으로 Install 시간이 전체 평균 25%(162초), 최근 평균 12%(98초) 정도 감소했고, S3 캐시를 도입했을 때 평균 9%(30초) 정도 줄어들었다.

충분히 pnpm + S3 캐시를 도입할 가치는 있어 보인다.