본문으로 건너뛰기
개발 머꼬
개발 노트Docker
hohyeon.dev25

소스를 마운트했더니 컨테이너 안 node_modules가 사라진 이유

  • #Common Pitfall
  • #Docker
  • #Engineering Note

문제 발생

개발용으로 소스를 바인드 마운트했더니 컨테이너가 뜨자마자 죽었습니다.

services:
  app:
    volumes:
      - .:/app          # 호스트 소스를 컨테이너로
Error: Cannot find module 'express'

이미지 빌드 때 분명히 pnpm install을 했는데 /app/node_modules가 비어 있었습니다.

원인 분석

마운트는 덮어쓰는 게 아니라 가립니다. Docker 문서가 동작을 정확히 적습니다 — 비어 있지 않은 볼륨을 파일이 있는 컨테이너 디렉터리에 마운트하면 기존 파일들은 마운트에 의해 가려집니다(obscured).

호스트의 프로젝트 디렉터리에는 node_modules가 없거나(있어도 OS·아키텍처가 다를 수 있습니다) 다른 내용입니다. 그것이 /app을 통째로 덮으면서, 이미지 안에 설치해둔 node_modules가 보이지 않게 된 것입니다.

반대 방향의 동작도 문서에 있습니다 — 비어 있는 볼륨을 내용이 있는 디렉터리에 마운트하면 그 파일·디렉터리가 기본적으로 볼륨으로 전파(복사)됩니다. 이름 있는 볼륨을 쓰면 첫 실행 때 이미지의 내용으로 채워진다는 뜻이고, 이번 문제의 해법이 여기서 나옵니다.

두 방식의 성격 차이도 정리돼 있습니다 — 볼륨은 Docker가 관리하며 호스트 머신의 핵심 기능과 격리되고 /var/lib/docker/volumes/ 아래에 저장되는 반면, 바인드 마운트는 호스트의 디렉터리 구조와 OS에 의존합니다.

해결 방안

  1. node_modules만 이름 있는 볼륨으로 덮습니다. 소스는 바인드 마운트로 즉시 반영하고, 의존성은 컨테이너 것을 씁니다.
services:
  app:
    volumes:
      - .:/app
      - app_node_modules:/app/node_modules
volumes:
  app_node_modules:
  1. 의존성이 바뀌면 그 볼륨을 지웁니다. 첫 생성 때 채워진 내용이 계속 남으므로, package.json이 바뀌면 docker compose down -v나 해당 볼륨 삭제가 필요합니다 — 이걸 모르면 "설치했는데 반영이 안 된다"로 이어집니다.

  2. 용도로 둘을 나눠 씁니다. 문서 권고대로 컨테이너와 호스트 양쪽에서 파일에 접근해야 하면 바인드 마운트(개발 중 소스), 그 밖에는 볼륨(DB 데이터, 업로드 파일)이 기본입니다.

  3. 데이터 볼륨은 백업 경로를 정합니다. 문서가 볼륨의 장점으로 드는 것이 백업·이관의 용이함인데, 실제로 백업 절차를 만들어두지 않으면 이점이 아닙니다.

  4. 권한을 함께 봅니다. 비root로 실행하는 컨테이너가 마운트된 디렉터리에 쓰려면 UID/GID가 맞아야 합니다.

  5. 운영 이미지에는 소스를 마운트하지 않습니다. 이 구성은 개발 편의를 위한 것이고, 운영에서는 이미지 안의 내용이 곧 배포 산출물이어야 합니다.

공식 문서

마지막 수정

좋아요북마크

댓글0

아직 댓글이 없어요. 첫 의견을 편하게 남겨 보세요.