CI/CD
pnpm lockfile 때문에 CI 빌드만 실패했을 때 확인한 순서
로컬 설치는 되는데 CI에서 frozen lockfile로 멈춘 상황을 package.json, lockfile, Node 버전 순서로 좁힌 기록이다.
증상: 로컬은 통과, CI만 실패
작업하던 저장소에서 pnpm install은 로컬에서 문제없이 끝났는데, 배포 파이프라인에서는 의존성 설치 단계에서 바로 멈췄다. 처음에는 캐시가 꼬인 줄 알고 CI 캐시를 지웠지만 결과가 같았다. 로그를 다시 보니 핵심은 네트워크가 아니라 lockfile이었다.
ERR_PNPM_OUTDATED_LOCKFILE Cannot install with "frozen-lockfile" because pnpm-lock.yaml is not up to date with package.json
헷갈렸던 지점은 로컬에서 새 패키지를 설치한 뒤 package.json만 커밋하고 pnpm-lock.yaml을 빠뜨렸다는 점이다. npm을 오래 쓰다 보면 lockfile 변경을 덜 중요하게 보기도 하는데, CI에서는 보통 재현 가능한 설치를 위해 lockfile 불일치를 실패로 처리한다.
먼저 비교한 파일
바로 패키지를 다시 설치하기 전에, 어떤 파일이 달라졌는지부터 확인했다.
git diff -- package.json pnpm-lock.yaml
pnpm install --frozen-lockfile
로컬에서도 --frozen-lockfile을 붙이니 같은 에러가 재현됐다. 이 단계에서 CI 문제가 아니라 저장소 상태 문제라고 판단했다.
내가 정한 수정 기준
단순히 pnpm install을 다시 실행하면 lockfile은 갱신된다. 다만 무작정 커밋하지 않고 세 가지를 봤다.
package.json에 의도하지 않은 버전 범위 변경이 있는지pnpm-lock.yaml에서 너무 많은 패키지가 바뀌지 않았는지- CI의 Node, pnpm 버전이 로컬과 크게 다르지 않은지
버전 차이는 다음처럼 확인했다.
node -v
pnpm -v
한 번은 로컬 pnpm이 더 최신이라 lockfile 형식이 바뀐 적이 있었다. 그 뒤로는 packageManager 필드를 명시해 두는 편이다.
{
"packageManager": "[email protected]"
}
다시 실패하지 않게 만든 작은 습관
수정 후에는 로컬에서 CI와 비슷한 명령을 한 번 돌렸다.
rm -rf node_modules
pnpm install --frozen-lockfile
pnpm build
시간은 조금 더 걸리지만, 배포 버튼을 누른 뒤에야 lockfile 누락을 발견하는 것보다 훨씬 낫다. 이번 일 이후로 의존성을 건드린 커밋에서는 package.json과 lockfile을 같이 보는 체크를 습관처럼 하고 있다.
마무리 메모
CI 설치 실패는 종종 캐시나 네트워크처럼 보이지만, lockfile 오류는 메시지가 꽤 정확하다. 로그의 첫 줄만 보지 말고 frozen-lockfile, packageManager, pnpm 버전 세 가지를 같이 보면 원인을 빨리 좁힐 수 있었다.