Docker COPY와 빌드 컨텍스트 — 디렉토리 중첩
Dockerfile 을 애플리케이션 저장소가 아니라 별도 저장소에 두고, CI 에서 둘을
각각 clone 해서 이미지를 빌드하는 구조였습니다. 그 CI 에서 npm install 이
실패했습니다.
ENOENT: no such file or directory, open '/service/app-v2/package.json'
WORKDIR /service/app-v2 에 package.json 이 없다는 겁니다. 그런데 소스에는
분명히 있었습니다.
빌드 컨텍스트 루트에 통째로 든 소스 디렉토리
CI workspace 는 저장소 두 개를 각각 clone 해서 루트에 나란히 두는 구조였습니다.
<빌드 컨텍스트 루트>/
├── app-v2/ ← 소스 저장소 (여기 package.json 있음)
│ ├── package.json
│ └── src/
├── dockerfile-repo/ ← Dockerfile 저장소
└── Dockerfile
빌드 컨텍스트가 이 루트고, Dockerfile 에는 이렇게 적혀 있었습니다.
COPY . /service/app-v2
COPY . 는 빌드 컨텍스트 전체를 복사합니다. 디렉토리 구조를 그대로 유지한
채로 복사합니다. 그래서 결과가 이렇게 됩니다.
/service/app-v2/
├── app-v2/ ← 소스 디렉토리가 한 겹 더 생김
│ ├── package.json
│ └── src/
├── dockerfile-repo/ ← 불필요한 것까지 복사
└── Dockerfile
package.json 이 /service/app-v2/app-v2/ 안에 있습니다. WORKDIR 은
/service/app-v2 라서 거기서 npm install 을 돌리면 한 겹 아래에 있는
package.json 을 못 찾습니다.
해결 — COPY 대상 명시로 중첩 제거
. 대신 복사할 디렉토리를 지정했습니다.
COPY app-v2 /service/app-v2
COPY app-v2 /service/app-v2 는 빌드 컨텍스트의 app-v2/ 안의 내용을
목적지에 넣습니다. 디렉토리 자체가 아니라 그 안쪽이 들어갑니다.
/service/app-v2/
├── package.json ← 원하는 위치
└── src/
이제 WORKDIR 에서 package.json 이 보입니다. dockerfile-repo 같은
불필요한 것도 안 따라옵니다.
COPY의 두 형태
같은 목적지라도 소스를 어떻게 쓰냐에 따라 결과가 다릅니다.
COPY app-v2 /service/app-v2
# app-v2/ 안의 파일들이 /service/app-v2/ 로
# → /service/app-v2/package.json
COPY . /service/app-v2
# 컨텍스트 전체가 구조 유지한 채로
# → /service/app-v2/app-v2/package.json (한 겹 더)
COPY . 는 빌드 컨텍스트 루트에 복사하려는 것만 딱 있을 때 맞습니다. 루트에
다른 디렉토리가 섞여 있으면 그것까지 다 들어가고, 소스가 한 겹 중첩됩니다.
빌드 컨텍스트가 저장소 하나의 루트면 COPY . 로 충분합니다. 여러 저장소를
한 workspace 에 clone 해서 쓰는 CI 구조라면, 무엇을 복사할지 명시하는 게
안전합니다.
댓글 0