Docker-compose : npm 설치가 성공한 후 node_modules가 볼륨에 존재하지 않습니다


184

다음 서비스를 갖춘 앱이 있습니다.

  • web/ -포트 5000에서 Python 3 플라스크 웹 서버를 보유하고 실행합니다. sqlite3을 사용합니다.
  • worker/- index.js큐의 작업자 인 파일이 있습니다. 웹 서버는 json API over port를 사용하여이 대기열과 상호 작용합니다 9730. 작업자는 스토리지에 redis를 사용합니다. 작업자는 폴더에 로컬로 데이터를 저장합니다worker/images/

이제이 질문은에만 해당 worker됩니다.

worker/Dockerfile

FROM node:0.12

WORKDIR /worker

COPY package.json /worker/
RUN npm install

COPY . /worker/

docker-compose.yml

redis:
    image: redis
worker:
    build: ./worker
    command: npm start
    ports:
        - "9730:9730"
    volumes:
        - worker/:/worker/
    links:
        - redis

내가 실행 docker-compose build하면 모든 것이 예상대로 작동하고 모든 npm 모듈이 예상대로 설치됩니다 /worker/node_modules.

npm WARN package.json unfold@1.0.0 No README data

> phantomjs@1.9.2-6 install /worker/node_modules/pageres/node_modules/screenshot-stream/node_modules/phantom-bridge/node_modules/phantomjs
> node install.js

<snip>

그러나 내가 할 docker-compose up때이 오류가 나타납니다.

worker_1 | Error: Cannot find module 'async'
worker_1 |     at Function.Module._resolveFilename (module.js:336:15)
worker_1 |     at Function.Module._load (module.js:278:25)
worker_1 |     at Module.require (module.js:365:17)
worker_1 |     at require (module.js:384:17)
worker_1 |     at Object.<anonymous> (/worker/index.js:1:75)
worker_1 |     at Module._compile (module.js:460:26)
worker_1 |     at Object.Module._extensions..js (module.js:478:10)
worker_1 |     at Module.load (module.js:355:32)
worker_1 |     at Function.Module._load (module.js:310:12)
worker_1 |     at Function.Module.runMain (module.js:501:10)

/worker/node_modules호스트 또는 컨테이너에 모듈이없는 것으로 나타났습니다 .

호스트 인 경우 npm install모든 것이 잘 작동합니다. 그러나 나는 그것을하고 싶지 않습니다. 컨테이너가 종속성을 처리하기를 원합니다.

무슨 일이야?

말할 필요도없이, 모든 패키지는 안에 package.json있습니다.


결국 해결책을 찾았습니까?
저스틴 스테이 튼

ONBUILD 명령어를 사용해야한다고 생각합니다 ... github.com/nodejs/docker-node/blob/master/0.12/onbuild/…
Lucas Pottersky

1
IDE가 node_module 의존성을 모르는 경우 어떻게 호스트에서 개발을 하시겠습니까?
André

2
파일 volumes: - worker/:/worker/에서 블록 을 제거 docker-compose.yml하십시오. 이 줄은 COPY 명령으로 작성한 폴더를 덮어 씁니다.
스테판

When I run docker-compose build, everything works as expected and all npm modules are installed in /worker/node_modules as I'd expect.-어떻게 확인 했어?
Vallie

답변:


272

빌드 중에 볼륨이 마운트되지 않았기 때문에 worker디렉토리를에 볼륨으로 추가했기 때문 docker-compose.yml입니다.

docker가 이미지를 빌드하면 node_modules디렉토리가 디렉토리 내에 작성 worker되고 모든 종속성이 설치됩니다. 그런 다음 런타임에 worker외부 도커 의 디렉토리가 도커 인스턴스 (설치되지 않은)에 마운트되어 방금 설치 node_modulesnode_modules것을 숨 깁니다 . 에서 마운트 된 볼륨을 제거하여이를 확인할 수 있습니다 docker-compose.yml.

해결 방법은 데이터 볼륨을 사용하여 모든을 저장하는 것입니다 node_modules. 데이터 볼륨은 worker디렉토리가 마운트 되기 전에 내장 된 docker 이미지의 데이터에 복사되기 때문 입니다. 이것은 다음 docker-compose.yml과 같이 할 수 있습니다 :

redis:
    image: redis
worker:
    build: ./worker
    command: npm start
    ports:
        - "9730:9730"
    volumes:
        - ./worker/:/worker/
        - /worker/node_modules
    links:
        - redis

이미지의 이식성에 문제가 있는지 여부는 확실하지 않지만 런타임 환경을 제공하기 위해 주로 도커를 사용하는 것처럼 보이므로 문제가되지 않습니다.

볼륨에 대한 자세한 내용을 보려면 https://docs.docker.com/userguide/dockervolumes/ 에서 유용한 사용자 안내서를 참조 하십시오.

편집 : Docker는 ./docker-compose.yml 파일과 관련하여 파일을 마운트 하기 위해 선행을 요구하도록 구문을 변경했습니다 .


7
좋은 답변, 최소한의 방해 및 훌륭한 설명!
kkemple 님이

41
이 방법을 시도하고 종속성이 변경되면 벽을 쳤습니다. 이미지를 재구성하고 새 컨테이너를 시작했으며 볼륨 /worker/node_modules이 이전과 동일하게 유지되었습니다 (오래된 종속성 사용). 이미지를 다시 만들 때 새로운 볼륨을 사용하는 방법이 있습니까?
Ondrej Slinták

11
docker compose는 다른 컨테이너가 사용하더라도 볼륨이 제거되지 않은 경우에도 볼륨을 제거하지 않는 것 같습니다. 따라서 어떤 이유로 든 동일한 유형의 사용되지 않는 컨테이너가있는 경우 이전 설명에서 설명한 시나리오가 이어집니다. 내가 시도한 것에서을 사용 docker-compose rm하여이 문제를 해결 하는 것처럼 보이지만 더 좋고 쉬운 해결책이 있어야한다고 생각합니다.
Ondrej Slinták 2016 년

15
2018 년 rebuild --no-cache에는 뎁이 바뀔 때마다 해결책이 없습니까?
Eelke

7
`--renew-anon-volumes` 를 사용하면 이전 컨테이너의 데이터 대신 익명 볼륨을 다시 생성 할 수 있습니다 .
Mohammed Essehemy

37

node_modules볼륨 이 폴더를 덮어 쓰고 컨테이너에서 더 이상 액세스 할 수 없습니다. 내가 사용하고 네이티브 모듈 로딩 전략을 볼륨에서 폴더를 꺼내 :

/data/node_modules/ # dependencies installed here
/data/app/ # code base

도커 파일 :

COPY package.json /data/
WORKDIR /data/
RUN npm install
ENV PATH /data/node_modules/.bin:$PATH

COPY . /data/app/
WORKDIR /data/app/

node_modules가 이미지에 포함되어 있기 때문에 디렉토리는 컨테이너 외부에서 액세스 할 수 없습니다.


1
이 접근법에 단점이 있습니까? 나를 위해 잘 작동하는 것 같습니다.
Bret Fisher

1
node_modules정말 단점은 컨테이너 외부에서 액세스 할 수 없습니다하지만)
jsan

package.json을 변경할 때마다 --no-cache로 전체 컨테이너를 다시 빌드해야합니까?
Luke

package.json을 변경할 때 이미지를 다시 작성해야하지만 --no-cache는 필요하지 않습니다. 실행 docker-compose run app npm install하면 현재 디렉토리에 node_modules가 만들어지고 더 이상 이미지를 다시 만들 필요가 없습니다.
jsan

9
단점은 더 이상 IDE 자동 완성, 도움, 좋은 ​​개발 경험이 없다는 것입니다. 이제 모든 것도 호스트에 설치해야하지만 여기에서 도커를 사용하는 이유는 개발자 호스트가 프로젝트로 작업 할 필요가 없다는 것입니까?
Michael B.

31

@FrederikNS가 제공하는 솔루션은 작동하지만 node_modules 볼륨의 이름을 명시 적으로 지정하는 것을 선호합니다.

project/docker-compose.yml파일 (docker-compose 버전 1.6 이상) :

version: '2'
services:
  frontend:
    ....
    build: ./worker
    volumes:
      - ./worker:/worker
      - node_modules:/worker/node_modules
    ....
volumes:
  node_modules:

내 파일 구조는 다음과 같습니다

project/
   │── worker/
        └─ Dockerfile
   └── docker-compose.yml

project_node_modules응용 프로그램을 시작할 때마다 이름이 지정된 볼륨을 생성 하고 재사용합니다.

docker volume ls모습은 다음과 같습니다.

DRIVER              VOLUME NAME
local               project1_mysql
local               project1_node_modules
local               project2_postgresql
local               project2_node_modules

3
이 "작동"하는 동안 도커의 실제 개념을 우회합니다. 최대의 이식성을 위해 모든 종속성을 구워야합니다. 당신은 좀 불면있는 다른 명령을 실행하지 않고 이미지를 이동할 수 없습니다
하비에르 Buzzi을

4
몇 시간 동안 같은 문제를 해결하려고 노력하고 내 자신과 동일한 솔루션을 생각해 냈습니다. 귀하의 답변은 가장 높은 등급이어야하지만, 귀하의 볼륨 이름을 "node_modules"로 지정하고 모든 독자에게 이것이 새로운 볼륨을 생성한다는 사실이 없기 때문에 ppl은 귀하의 답변을 얻지 못합니다. 코드를 읽을 때 로케일 node_modules 폴더를 "다시 마운트"하고 해당 아이디어를 버렸다고 생각했습니다. 어쩌면 볼륨 이름을 "container_node_modules"와 같은 형식으로 편집해야합니다. :)
Fabian

1
나는이 쉽게 여러 빌드 stages.The 큰 문서에서 노드 모듈에 대한 동일한 볼륨을 참조 수있는 가장 우아한 해결책이 될 것으로 도커에서 건물 노드 앱의 교훈 도 같은 방법을 사용합니다.
kf06925

1
@ kf06925 당신이 정말로 저를 구했습니다.이 문제를 해결하기 위해 몇 시간을 보냈습니다. 정말 감사 할 수 있다면 맥주를 사 겠어요
Helado

21

나는 최근에 비슷한 문제가 있었다. node_modules다른 곳에 설치 하고 NODE_PATH환경 변수를 설정할 수 있습니다 .

예에서 I가 설치 아래 node_modules/install

작업자 / Dockerfile

FROM node:0.12

RUN ["mkdir", "/install"]

ADD ["./package.json", "/install"]
WORKDIR /install
RUN npm install --verbose
ENV NODE_PATH=/install/node_modules

WORKDIR /worker

COPY . /worker/

docker-compose.yml

redis:
    image: redis
worker:
    build: ./worker
    command: npm start
    ports:
        - "9730:9730"
    volumes:
        - worker/:/worker/
    links:
        - redis

6
@FrederikNS가 투표 한 최고의 솔루션은 유용합니다 . 이 기사를node_modules 기반으로 컨테이너의 볼륨을 덮어 쓰는 로컬 볼륨의 다른 문제를 해결하는 방법이었습니다 . 그러나이 문제 를 경험하게 되었습니다 . 이 솔루션은 여기에 별도의 디렉토리를 작성하여 복사하여 실행 한 다음 환경 변수 를 지정하여 해당 디렉토리 의 폴더가 작동하고 올바르게 느낍니다. package.jsonnpm installNODE_PATHdocker-compose.ymlnode_modules
cwnewhouse

Dockerfile에 ENV NODE_PATH = / install / node_modules를 포함시키는 것은 몇 시간 동안 다른 접근법을 시도한 후에 마침내 해결책이었습니다. 감사합니다.
베니 미드

npm install호스트에서 실행하면 어떻게 되나요? node_modules호스트에 표시되는 것 보다 우선하여 컨테이너에 반영됩니다 NODE_PATH. 따라서 컨테이너는 호스트의 node_modules를 사용합니다.
vitalets

19

우아한 해결책이 있습니다.

전체 디렉토리가 아니라 앱 디렉토리 만 마운트하십시오. 이렇게하면에 문제가 발생하지 않습니다 npm_modules.

예:

  frontend:
    build:
      context: ./ui_frontend
      dockerfile: Dockerfile.dev
    ports:
    - 3000:3000
    volumes:
    - ./ui_frontend/src:/frontend/src

Dockerfile.dev :

FROM node:7.2.0

#Show colors in docker terminal
ENV COMPOSE_HTTP_TIMEOUT=50000
ENV TERM="xterm-256color"

COPY . /frontend
WORKDIR /frontend
RUN npm install update
RUN npm install --global typescript
RUN npm install --global webpack
RUN npm install --global webpack-dev-server
RUN npm install --global karma protractor
RUN npm install
CMD npm run server:dev

훌륭한. 왜 받아 들여지지 않는지 이해할 수 없습니다.
Jivan

2
이것은 빠르고 빠른 솔루션이지만 새 종속성 설치 후 재 구축 및 정리가 필요합니다.
Kunok

나는 다르게 다르게 지금 node_modules를위한 볼륨과 호스트에서 마운트하는 볼륨이 있어야합니다. 그렇다면 전혀 문제가 없습니다
holms

14

업데이트 : @FrederikNS에서 제공 하는 솔루션을 사용하십시오 .

같은 문제가 발생했습니다. 폴더 /worker가 컨테이너에 마운트 되면 모든 내용이 동기화됩니다 (따라서 로컬로 가지고 있지 않으면 node_modules 폴더가 사라집니다).

OS 기반의 npm 패키지가 호환되지 않기 때문에 모듈을 로컬로 설치할 수 없었으며 컨테이너를 시작했습니다.

이것에 대한 나의 해결책은 소스를 src폴더 node_modules감싸고이 index.js 파일을 사용하여 해당 폴더에 링크 하는 것입니다 . 따라서 index.js파일은 이제 내 응용 프로그램의 시작점입니다.

컨테이너를 실행할 때 /app/src폴더를 로컬 src폴더에 마운트했습니다 .

따라서 컨테이너 폴더는 다음과 같습니다.

/app
  /node_modules
  /src
    /node_modules -> ../node_modules
    /app.js
  /index.js

그것은이다 추한 ,하지만 작동합니다 ..


3
오, 친애하는 주님.
Lucas Pottersky


7

컨테이너에 node_modules를 프로젝트 폴더와 다른 컨테이너에 설치하고 NODE_PATH를 node_modules 폴더로 설정하면 컨테이너를 다시 빌드해야합니다.

docker-compose를 사용하고 있습니다. 내 프로젝트 파일 구조 :

-/myproject
--docker-compose.yml
--nodejs/
----Dockerfile

docker-compose.yml :

version: '2'
services:
  nodejs:
    image: myproject/nodejs
    build: ./nodejs/.
    volumes:
      - ./nodejs:/workdir
    ports:
      - "23005:3000"
    command: npm run server

nodejs 폴더의 Dockerfile :

FROM node:argon
RUN mkdir /workdir
COPY ./package.json /workdir/.
RUN mkdir /data
RUN ln -s /workdir/package.json /data/.
WORKDIR /data
RUN npm install
ENV NODE_PATH /data/node_modules/
WORKDIR /workdir

1
이것이 내가 찾은 최고의 솔루션입니다. NODE_PATH나를위한 열쇠였습니다.
cdignam

나는 이것이 의미가 있다고 생각하지만 이미지를 실행할 때 NODE_PATH를 설정하면 CMD npm start 지정된 NODE_PATH를 사용하지 않습니다.
Acton

6

node_module디렉토리를 다른 볼륨에 매핑하지 않는 간단한 솔루션도 있습니다 . npm 패키지 설치를 최종 CMD 명령으로 옮길 예정입니다.

이 접근법의 단점 :

  • 실행 npm install(에서 스위칭 당신이 용기를 실행할 때마다 npmyarn이 과정을 조금 속도를 힘을).

작업자 / Dockerfile

FROM node:0.12
WORKDIR /worker
COPY package.json /worker/
COPY . /worker/
CMD /bin/bash -c 'npm install; npm start'

docker-compose.yml

redis:
    image: redis
worker:
    build: ./worker
    ports:
        - "9730:9730"
    volumes:
        - worker/:/worker/
    links:
        - redis

3

노드 개발 환경에 대해 두 가지 별도의 요구 사항이 있습니다 ... 소스 코드를 컨테이너에 마운트하고 컨테이너 (IDE의 경우)에서 node_modules를 마운트하십시오. 첫 번째를 달성하기 위해서는 일반적인 마운트를 수행하지만 모든 것이 아니라 필요한 것만 수행하십시오.

volumes:
    - worker/src:/worker/src
    - worker/package.json:/worker/package.json
    - etc...

(하지 말아야 할 이유 - /worker/node_modules는 docker-compose가 실행 사이에 해당 볼륨을 유지하기 때문에 실제로 이미지에있는 것과 다를 수 있습니다 (호스트에서 마운트를 바인딩하는 것이 아니라 목적을 무시 함).

두 번째는 실제로 더 어렵다. 내 솔루션은 약간 해킹이지만 작동합니다. 호스트 컴퓨터에 node_modules 폴더를 설치하는 스크립트가 있으며 package.json을 업데이트 할 때마다 호출해야합니다 (또는 docker-compose build를 로컬로 실행하는 make 대상에 추가).

install_node_modules:
    docker build -t building .
    docker run -v `pwd`/node_modules:/app/node_modules building npm install

2

제 생각 RUN npm install에는 Dockerfile에 있으면 안됩니다. 대신 공식 노드 서비스를 실행하기 전에 bash를 사용하여 컨테이너를 시작하여 종속성을 설치할 수 있습니다

docker run -it -v ./app:/usr/src/app  your_node_image_name  /bin/bash
root@247543a930d6:/usr/src/app# npm install

나는 실제로 이것에 당신에 동의합니다. 볼륨은 컨테이너와 호스트간에 데이터를 공유하려고 할 때 사용됩니다. node_modules컨테이너를 제거한 후에도 지속성을 유지 하기로 결정한 경우 npm install수동으로 수행 할시기와 시기를 알아야 합니다. OP는 모든 이미지 빌드에서 이를 수행 할 것을 제안합니다 . 그렇게 할 수 있지만 볼륨을 사용할 필요는 없습니다. 모든 빌드에서 모듈은 최신 상태입니다.
phil294

@Blauhirn gulp watch (또는 유사한 명령)를 수행 할 때 로컬 호스트 볼륨을 컨테이너에 마운트하는 것이 도움이됩니다. 다른 소스 (js, css 등)를 계속 변경하면서 node_modules를 유지하고 싶습니다. npm은 로컬 펄프를 사용해야하므로 지속해야합니다 (또는 시작시 다른 방법으로 설치해야 함)
tbm

2

Dockerfile에서 다음과 같은 것을 시도 할 수 있습니다.

FROM node:0.12
WORKDIR /worker
CMD bash ./start.sh

그런 다음 볼륨을 다음과 같이 사용해야합니다.

volumes:
  - worker/:/worker:rw

시작 스크립트는 작업자 저장소의 일부 여야하며 다음과 같습니다.

#!/bin/sh
npm install
npm start

따라서 node_modules는 작업자 볼륨의 일부이며 동기화되며 npm 스크립트는 모든 것이 작동하면 실행됩니다.


컨테이너를 시작하는 데 큰 오버 헤드가 발생합니다.
tbm

2
그러나 node_modules가 로컬 시스템에 유지되기 때문에 처음입니다.
Parav01d

또는 이미지가 다시 작성되거나 볼륨이 제거 될 때까지 :). 즉, 더 나은 해결책을 찾지 못했습니다.
tbm

0

Dockerfile은 단순하기 때문에 기본 이미지를 사용하고 작성 파일에 명령을 지정하면됩니다.

version: '3.2'

services:
  frontend:
    image: node:12-alpine
    volumes:
      - ./frontend/:/app/
    command: sh -c "cd /app/ && yarn && yarn run start"
    expose: [8080]
    ports:
      - 8080:4200

이미지의 환경이 필요하지만 컨테이너 외부의 파일에서 작업하기 때문에 이것이 나에게 특히 유용합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.