turbo prune는 도커하고 친해지고 싶어

서론

turbo prune이 다시 돌아왔습니다! 저번에는 이 명령어가 터보레포의 특정 워크스페이스를 도커 이미지로 빌드할 때 왜 필요한지, 또한 기본적으로 어떻게 동작하는지 확인했습니다. 거기에 더해 하나를 더 알아볼 겁니다. 기존의 방법으로도 도커 이미지를 빌드하기에는 충분하지만 완벽하지는 않습니다. 해결하지 못한 작은 문제가 하나 있거든요.

문제점

질문입니다! 만약, 도커 이미지의 빌드에 사용될 파일들 중에 디펜던시와 관련이 없는 것이 변경된다면 어떻게 될까요? 이런 상황에서 도커는 기존의 캐시를 활용하지 않습니다! 디펜던시가 변하지 않았어도 계속 새로 설치가 된다는 괴담을 맞이하게 되는 겁니다. 정말 무서운 일입니다.

이 질문은 turbo prune으로 생성된 가지치기된 모노레포를 그대로 가져와 빌드할 때 생기는 문제와도 이어져 있습니다. 사실 그 상황이 그대로 발생합니다! 해당 모노레포에 해당하는 워크스페이스의 파일이 하나라도 추가 혹은 변경된다면 디펜던시는 언제나 다시 처음부터 설치됩니다... 으아악!!

해결방법?

모든 문제는 디펜던시와 관련 없는 파일이 수정될 때 도커가 이를 감지하고 캐시를 깨트리면서 생겼습니다. 그렇다면 도커가 캐시를 깨트리지 않게 만들면 되겠군요! 아예 디펜던시와 관련있는 파일만 모아 설치를 진행하면 모든 문제가 해결될 것만 같습니다.

도커에서 이런 일을 더욱 쉽게 만들어주는 기능이 무엇일까요? 바로 스테이지입니다! 각각의 스테이지는 독립된 캐시를 가지고, 파일을 입맛에 맞게 골라 사용할 수 있으니까요.

그렇다면 우리는 디펜던시를 설치하는 스테이지와 빌드하는 스테이지를 나누고 설치 스테이지에 디펜던시와 관련있는 파일만 포함시켜야 합니다. 즉, 모노레포에서 락파일과 package.json만 쏙 빼서 설치 스테이지에 넣어주는 과정을 거쳐야 하죠. 이제 해결 방법에 좀 더 가까워진 느낌이 듭니다! 하지만 머릿 속 한켠에 "완전 귀찮아!" 같은 생각이 무럭무럭 피어오르지는 않나요..? 경험담입니다.

괜찮습니다. 여러분들은 터보레포를 사용하고 있으니까요!

--docker

역시나! 터보레포는 이 문제도 이미 해결할 수단을 마련해 놓았습니다. --docker 옵션이 바로 그 것입니다.

turbo prune --scope="a-workspace"

이전에 우리는 다음과 같은 명령어로 가지치기된 모노레포를 만들었습니다. 그 모노레포의 구조는 다음과 같습니다:

.
├── apps/
│   └── a-workspaces/   // example-package-1만 사용
│       ├── package.json
│       └── src/
├── packages/
│   └── example-package-1/
│       ├── index.ts
│       └── package.json
└── pnpm-lock.yaml

언제나 보던 익숙한 구조입니다. 그렇다면 이번에는 --docker 옵션을 사용해 봅시다.

turbo prune --scope="a-workspace" --docker

기존의 명령어의 뒤에 --docker를 적어주면 됩니다. 이 것을 통해 만들어진 모노레포의 구조는 다음과 같습니다:

.
├── full
│   ├── apps/
│   │   └── a-workspaces/   // example-package-1만 사용
│   │       ├── package.json
│   │       └── src/
│   └── packages/
│       └── example-package-1/
│           ├── index.ts
│           └── package.json
├── json
│   ├── apps/
│   │   └── a-workspaces/
│   │       └── package.json
│   └── packages/
│       └── example-package-1/
│           └── package.json
└── pnpm-lock.yaml

전의 구조와 무언가 달라보입니다. 우리가 살펴봐야 할 부분은 나눠져 있는 full, json 디렉토리의 용도입니다.

json 디렉토리는 이 옵션의 핵심입니다. full 디렉토리와 비교해 보세요. 무언가 빠진 부분이 있지 않나요? json 디렉토리는 바로 full 디렉토리에서 오직 package.json만을 가져와 만들어졌습니다. 그렇습니다, 바로 이겁니다! 우리가 원하던 거에요!

image--docker로 분리된 디렉토리 덕분에 설치, 빌드 스테이지를 분리해 줄 수 있습니다. 설치 스테이지에서는 락파일과 json 디렉토리를 가져와 오직 디펜던시의 설치만, 빌드 스테이지에서는 설치 스테이지에서 설치된 디펜던시들과 full 디렉토리에서 가져온 소스 파일들을 가져와 빌드만 하게 만드는 것이죠.

이제 설치 스테이지는 디펜던시 설치에 반드시 필요한 락파일과 package.json만을 가질 수 있게 되었습니다. 더 이상 설치 스테이지에서 디펜던시와 관련되지 않은 다른 파일의 변경으로 캐시가 깨지는 일은 생기지 않습니다. 문제 해결입니다!

TMI

도움이 됐나요?

다행입니다! 해피 해킹!

References

댓글을 작성해보세요.