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_modules한 node_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(에서 스위칭 당신이 용기를 실행할 때마다 npm에 yarn이 과정을 조금 속도를 힘을).

작업자 / 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.