LabHub
시작하기
배우기 러닝패스 코스

폐쇄망 미러와 사설 CA

레지스트리를 하나 더 세우는 이유

LabHub 에서 이어서 보기

한 줄 요약

npm 의 폐쇄망 대응은 레지스트리를 하나 더 세우는 것이다. 연결된 동안 위(npmjs)를 당겨 채워 두고, 끊은 뒤에는 채워 둔 것만 내준다. 프로젝트는 .npmrcregistry 한 줄로 그 레지스트리를 본다. 잠금 파일에 박힌 주소는 npm 이 알아서 바꿔 주지만, 그 기본값을 모르면 사고가 난다.

왜 이게 필요했나

프런트엔드 저장소 하나의 node_modules 는 패키지 수백 개다. 폐쇄망에서 npm ci 를 치면 첫 패키지에서 멈춘다. 흔한 임시방편은 연결된 PC 에서 node_modules 를 통째로 압축해 들고 들어가는 것인데, 운영체제·node 버전이 다르면 네이티브 모듈이 깨지고, 무엇이 들어갔는지 목록도 남지 않는다. 필요한 것은 패키지 단위로 받아 두고, 잠금 파일대로 다시 설치할 수 있는 저장소다.

어떻게 동작하나

레지스트리를 가리키기. npm 은 설정을 명령줄 → 환경 변수 → npmrc 파일 → 기본값 순으로 따르고, npmrc 는 프로젝트(.npmrc) → 사용자(~/.npmrc) → 전역($PREFIX/etc/npmrc) → 내장 순으로 우선한다. registry 의 기본값은 https://registry.npmjs.org/ 다. 프로젝트 .npmrcregistry= 를 적으면 그 저장소를 여는 누구든 같은 레지스트리를 본다.

verdaccio 의 세 가지 설정. uplinks 는 위 레지스트리 목록이고, packages 는 이름 패턴마다 access·publish·proxy 를 정한다. 문서에 따르면 패턴의 순서가 중요하고 ** 를 마지막 받침으로 둔다. proxy 에 uplink 이름을 적은 패턴은 로컬에 없는 것을 위에서 당겨 storage 에 남기고, proxy 가 없는 패턴은 로컬 저장소에 있는 것만 내준다. 이것이 "끊는다" 의 정체다. 기본 포트는 4873 이다.

Nexus 나 Artifactory 의 용어로 옮기면 이렇다. Nexus 문서는 저장소를 세 종류로 나눈다 — 원격을 캐시하는 proxy, 우리가 올리는 원본인 hosted, 여럿을 한 주소로 묶는 group. verdaccio 의 proxy: npmjs 가 붙은 패턴이 proxy 저장소, 사내 패키지를 publish 하는 패턴이 hosted, 둘을 한 주소로 내주는 것이 group 역할이다. Nexus 3 는 공식 요구 사양이 호스트 메모리 8GB, 기본 힙 2703MB 라 이 실습 파드(2Gi)에는 들어가지 않는다. 원리를 가벼운 것으로 익히고 현장 장비의 메뉴에 대응시키면 된다.

잠금 파일과 주소. package-lock.jsonresolved 에는 tarball 의 전체 주소가 적힌다. 바깥에서 만든 잠금 파일에는 https://registry.npmjs.org/... 가 박혀 있다. npm 의 replace-registry-host 설정이 이 문제를 다룬다. 기본값 npmjs기본 레지스트리를 가리키는 주소만 설정한 레지스트리로 바꿔서 받는다. never 는 적힌 주소 그대로 가고, always 는 어떤 호스트든 바꾼다. 사내 레지스트리 주소가 박힌 잠금 파일을 다른 사내 레지스트리로 옮길 때는 기본값이 도와주지 않는다는 뜻이기도 하다.

설치 명령. npm ci 는 잠금 파일이 반드시 있어야 하고, package.json 과 어긋나면 잠금을 고치는 대신 오류로 멈추며, node_modules 를 지우고 새로 깐다. 반입 재현에는 이쪽이 맞다. --offline 은 네트워크 요청을 아예 하지 않고 캐시만 쓰며, --prefer-offline 은 캐시를 먼저 보되 없으면 받으러 간다. npm 문서는 캐시를 "믿을 만한 영구 저장소로 기대지 말라" 고 적는다 — 캐시를 반입 수단으로 삼기보다 레지스트리를 세우는 이유다.

현장에서 만나는 모습

이 실습 파드에서 재 보았다(npm 10.9.0, verdaccio 6.1.6). registry.npmjs.org 주소가 박힌 잠금 파일로 바깥이 막힌 채 npm ci --registry http://127.0.0.1:4873/ 을 하면 기본값에서는 6개 패키지가 사내 레지스트리에서 설치되고, --replace-registry-host=never 를 주면 프록시 연결 오류로 멈췄다. 같은 잠금 파일, 같은 레지스트리 설정인데 한 줄 기본값이 결과를 가른다. 또 uplink 를 끊은 verdaccio 에 저장소에 없던 패키지를 요청하면 404 가 난다. "레지스트리가 고장 났다" 가 아니라 "반입 목록에 없었다" 는 뜻이니, 404 는 반입 요청서를 다시 쓰라는 신호다.

verdaccio 자체도 npm 패키지라 반입물이다. 이 실습에서 설치하면 의존성이 270여 개 딸려 오고 디스크 59MB 를 차지했다. 버전을 고정해 설치하고 그 잠금 파일도 함께 보관해야 폐쇄망 안에서 같은 verdaccio 를 다시 세울 수 있다.

다음 실습에서 할 것

verdaccio 6.1.6 을 설치해 npmjs 를 위로 둔 레지스트리로 npm.airgap.internal:4873 에 띄우고, 프로젝트 .npmrc 로 가리켜 chalk 4.1.2 를 당겨 채운다. uplink 를 끊고, 바깥이 막힌 채 새 캐시로 npm ci 가 되는지 채점기가 다시 돌려 본다. 마지막에 바깥에서 만든 잠금 파일로 replace-registry-host 의 기본값과 never 를 직접 비교해 기록한다.

참고 문서: npmrc · npm config(registry, replace-registry-host, offline) · npm ci · verdaccio Configuration · verdaccio Packages · Nexus Repository Types · Nexus System Requirements