ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Yarn berry] Yarn Berry Install 과정 파헤쳐보기
    개발 블로깅/기타 개념 2023. 1. 23. 21:47

     

    CI 환경에서 Yarn Berry Install 시간을 줄이기 위해 이것저것 실험을 해보다 보니, install 시에 진행되는 과정에 대해 깊게 알아볼 수 있게 되었다.

    사실 pnp를 이용해버리면 install 과정 자체를 줄일 수 있을 것이란 희망이 컸었으나, 실질적으로 우리 모노레포 환경과, 특히나 Cypress와 같이 현 로컬 환경의 바이너리 정보들이 필요로 한 환경에서는 pnp가 큰 의미가 없다는 것을 알게 되면서... 좌절..(관련 링크)

    그럼에도 불구하고, 우리 환경에서 pnp가 아니더라도 CI 시간을 단축시키기 위한 여러 가지 테스트를 해보는 중이다.

    CI 단에서 돌아가는 큰 스텝은 아래와 같다.

    • - yarn install
    • - yarn build
    • - run Test Code

     

    그 중, 우선은 yarn install에 대한 시간을 단축시키기 위한 테스트를 진행해 보았다.

     

    Yarn install 기본적인 동작 방식

    모두들 알다시피 Yarn install의 과정은 아래와 같이 동작한다.

    • 현재 Docker 컨테이너 환경에서 node_modules가 없으면, package.json과 lock 파일을 보고 디펜던시들을 설치한다.
    • 이미 기존에 디펜던시들이 모두 설치가 되어 있으면 별도의 install 과정을 수행하지 않는다.
    • package.json의 일부 디펜던시만 추가, 변경 및 삭제가 있을 경우, 해당하는 디펜던시 처리만 수행하고 install 과정을 끝낸다.

     

    기존에는 CI단에서  항상 새로운 스테이지가 돌 때마다 새롭게 install 과정을 수행하면서 많은 시간을 소비했는데,
    이전에 돌던 CI 단의 디펜던시와 큰 변화가 없어 이전 디펜던시를 유지할 수 있다면 install 시간을 크게 단축시킬 수 있다.

    그러면 어떻게 하면 이전 디펜던시를 유지하고 새로운 CI 환경에서 기존 디펜던시 상태를 유지시킬 수 있을까?

    단순히 node_modules만 유지하면 될까?

    아니다. 단순히 node_modules만 유지한다면, 새로운 CI 환경에서는 현재 install 상태에 대한 정보를 알고 있지 않아 이미 디펜던시가 설치되어 있음에도 다시 한번 새롭게 설치 과정을 진행한다.

    그러면 제대로 해당 환경에 디펜던시 정보를 유지하기 위해서는 어떻게 할 수 있을까?

    이를 위해서는 Yarn install 과정이 어떻게 돌아가는지 알 필요가 있다. 

     

    Yarn Install 과정 파헤쳐보기


    Yarn install은 크게 Resolution, Fetch, Link 3단계로 이루어져 있다.

     

    Resolution Step

    Resolution 단계는 현재 프로젝트 내에 있는 lock 파일과 package.json 파일을 읽고, 현재 환경에 설치되어야 할 디펜던시 트리를 생성한다. 현재 파일들의 정보를 가지고 알고리즘을 돌려 트리 정보만 생성하기 때문에, 뒤의 두 Step 중에 가장 빠르게 수행이 된다.

    (트리에는 이미 설치된 디펜던시와 새롭게 설치해야 할 디펜던시 모두를 포함한 전체 트리를 말한다.)

     

    Fetch Step

    Resolve Step에서 생성된 디펜던시 트리를 가지고 각 디펜던시를 요청해서 설치할 수 있는 곳을 fetch로 요청해서 찾아, 각 디펜던시 별 설치 요청을 할 수 있는 fetch 정보 트리를 생성하는 단계이다.

    .yarn/cache 내부에 이미 설치된 디펜던시는 해당 디렉토리에 zip 파일로 가지고 있는데, fetch Step에서는 여기 디렉토리를 가장 처음으로 리서치를 해서 찾는다.

    여기에 없으면 npm서버로 fetch 요청을 보내 디펜던시 정보에 대한 설치 가능한 버전이 있는지 확인하게 된다.

    위 로그와 같이, install 중에 몇 개의 디펜던시가 .yarn/cache에서 찾았는지 혹은 새롭게 fetch해서 찾았는지 알 수 있다.

    npm서버에서 설치 버전의 응답을 받으면, .yarn/cache 파일에 zip으로 다운로드를 하고, 향후 Link Step에서 .yarn/cache를 참조하여 설치할 수 있도록 한다. 만약 npm 서버까지 해당하는 설치 버전에 대한 응답을 받지 못하면 fetch step 실패로 install fail이 발생하게 된다.

    설치할 디펜던시가 Cache로 가지고 있지 않아 새로 fetch 요청을 하게 되면, 요청한 디펜던시를 Cache로 새롭게 다운로드하는 시간과 네트워크 요청 시간에 소모가 발생하게 된다.

    (이때 Cache를 거치지 않고 바로 node_modules로만 사용할 수 있지 않을까 해서 방법을 찾아보았으나, 별도로 yarn cache disable 할 수 있는 방법은 없는 것 같다.)

     

    Offline Cache

    An overview of Yarn's offline cache, a feature that allows Yarn to work just fine even should the network go down for any reason.

    yarnpkg.com

     

    모든 디펜던시가 fetch로부터 설치 가능한 정보를 확인 후 트리를 생성하게 되면 Link Step으로 넘어간다.

     

    Link Step

    Fetch Step에서 생성한 정보 트리를 가지고 실제로 해당 환경에 디펜던시를 하나씩 설치하는 과정을 진행한다.

    .yarn/cache의 파일들을 이용하여 프로젝트에서 직접 사용할 수 있도록 node_modules에 디펜던시 코드를 풀어버린다.

    만약 설치할 디펜던시가 node_modules에 존재한다면 해당 디펜던시는 별도의 Link Step을 처리하지 않는다.

    여기서 주의할 점은, 대부분 디펜던시는 node_modules에만 설치 후 끝나지만, Cypress, SWC와 같이 현재 로컬 환경의 바이너리 정보가 필요한 디펜던시들은 내 로컬 글로벌 Library 경로에 해당 바이너리 파일도 함께 설치를 수행한다. 

    바이너리 파일이 설치되는 경로는 아래와 같다.

    • MacOS: ~/Library/Caches/Cypress
    • Linux: ~/.cache/Cypress
    • Windows: /AppData/Local/Cypress/Cache

     

    바이너리 파일이 설치되면서 .yarn경로에 install-state.gz라는 파일도 함께 생성하는데, 이 파일은 현재 환경에서 install 최적화된 정보를 가지고 있는 파일이라고만 Doc에 설명이 되어있기만 한데, 현재 로컬 환경의 바이너리 파일 설치가 필요로 한 정보들을 담은 파일로 추측된다.

    node_modules가 있다 해도 install-state.gz 파일이 없으면, 현 로컬 환경에 바이너리 파일이 설치되어있지 않다고 판단하고 바이너리 파일 설치를 수행한다.

    만약 새로운 CI 단에서 이전 CI 단의 node_modules와 install-state.gz만 유지를 해버리면, yarn은 해당 환경에 디펜던시와 바이너리 설치가 되어있다고 판단하고 install을 수행하지 않고 무사히 끝나겠지만, 실제로 바이너리 파일은 설치가 되어있지 않은 상태가 돼서 run 할 때 에러가 발생하게 된다.

     

    위 내용들을 다시 정리하면 아래와 같다.

     

    Resolution Step

    - 전체적인 디펜던시 정보 트리만 생성하는 단계.

     

    Fetch Step

    - 각 디펜던시가 cache와 npm 서버 중 어디를 통해 설치할 수 있는지 확인.
    - npm 서버로 파악되면 cache로 zip을 내려받음.

     

    Link Step

    - cache에서 node_modules로 코드를 풀어버리는 단계.
    - 바이너리 파일이 필요한 디펜던시는 내 로컬 환경에 해당 디펜던시의 바이너리 파일을 함께 설치.

    반응형

    댓글

Designed by Tistory.