web-dev-qa-db-ger.com

Docker-compose: Knotenmodule, die nach der erfolgreichen Installation von npm nicht auf einem Volume vorhanden sind

Ich habe eine App mit folgenden Diensten:

  • web/ - hält einen python 3 flask Web-Server auf Port 5000. Verwendet sqlite3.
  • worker/ - hat eine index.js - Datei, die ein Arbeiter für eine Warteschlange ist. Der Webserver interagiert mit dieser Warteschlange unter Verwendung einer JSON-API über Port 9730. Der Arbeiter verwendet redis zur Speicherung. Der Worker speichert die Daten auch lokal im Ordner worker/images/

Diese Frage betrifft jetzt nur den 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

Wenn ich docker-compose build Ausführe, funktioniert alles wie erwartet und alle npm-Module werden wie erwartet in /worker/node_modules Installiert.

npm WARN package.json [email protected] No README data

> [email protected] install /worker/node_modules/pageres/node_modules/screenshot-stream/node_modules/phantom-bridge/node_modules/phantomjs
> node install.js

<snip>

Aber wenn ich docker-compose up Mache, sehe ich diesen Fehler:

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)

Es stellt sich heraus, dass keines der Module in /worker/node_modules Vorhanden ist (auf dem Host oder im Container).

Wenn ich auf dem Host npm install Bin, funktioniert alles einwandfrei. Das will ich aber nicht. Ich möchte, dass der Container Abhängigkeiten verarbeitet.

Was läuft hier falsch?

(Selbstverständlich sind alle Pakete in package.json.)

144
Karan Goel

Dies geschieht, weil Sie Ihr worker -Verzeichnis als Volume zu Ihrem docker-compose.yml Hinzugefügt haben, da das Volume während des Builds nicht bereitgestellt wird.

Wenn Docker das Image erstellt, wird das Verzeichnis node_modules Im Verzeichnis worker erstellt, und alle Abhängigkeiten werden dort installiert. Dann wird zur Laufzeit das Verzeichnis worker von außerhalb des Dockers in die Docker-Instanz eingebunden (auf der node_modules Nicht installiert ist), wobei das gerade installierte node_modules Ausgeblendet wird. Sie können dies überprüfen, indem Sie das gemountete Volume aus Ihrem docker-compose.yml Entfernen.

Eine Problemumgehung besteht darin, ein Daten-Volume zum Speichern des gesamten node_modules Zu verwenden, während Daten-Volumes in die Daten aus dem erstellten Docker-Image kopiert werden, bevor das Verzeichnis worker bereitgestellt wird. Dies kann in docker-compose.yml Folgendermaßen erfolgen:

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

Ich bin nicht ganz sicher, ob dies Probleme für die Portabilität des Images mit sich bringt, aber da Sie anscheinend hauptsächlich Docker verwenden, um eine Laufzeitumgebung bereitzustellen, sollte dies kein Problem sein.

Wenn Sie mehr über Bände lesen möchten, finden Sie hier ein Nizza-Benutzerhandbuch: https://docs.docker.com/userguide/dockervolumes/

217
FrederikNS

Das node_modules Ordner wird vom Volume überschrieben und ist im Container nicht mehr verfügbar. Ich benutze die native Modul-Ladestrategie , um den Ordner vom Volume zu entfernen:

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

Dockerfile:

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

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

node_modules ist von außerhalb des Containers nicht zugänglich, da es im Bild enthalten ist.

28
jsan

Die von @FrederikNS bereitgestellte Lösung funktioniert, aber ich bevorzuge es, mein node_modules-Volume explizit zu benennen.

Meine project/docker-compose.yml Datei (Docker-Compose Version 1.6+):

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

meine dateistruktur ist:

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

Es erstellt ein Volume mit dem Namen project_node_modules Und verwendet es jedes Mal, wenn ich meine Anwendung öffne.

Mein docker volume ls Sieht so aus:

DRIVER              VOLUME NAME
local               project1_mysql
local               project1_node_modules
local               project2_postgresql
local               project2_node_modules
26

Ich hatte kürzlich ein ähnliches Problem. Sie können node_modules An anderer Stelle installieren und die Umgebungsvariable NODE_PATH Festlegen.

Im folgenden Beispiel habe ich node_modules In /install Installiert.

arbeiter/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
18
ericstolten

Es gibt eine elegante Lösung:

Mounten Sie einfach nicht das gesamte Verzeichnis, sondern nur das App-Verzeichnis. Auf diese Weise haben Sie keine Probleme mit npm_modules.

Beispiel:

  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
16
holms

UPDATE: Verwenden Sie die Lösung von @FrederikNS.

Ich bin auf dasselbe Problem gestoßen. Wenn der Ordner /worker In den Container eingebunden wird, wird der gesamte Inhalt synchronisiert (der Ordner node_modules wird also ausgeblendet, wenn Sie ihn nicht lokal haben).

Aufgrund inkompatibler npm-Pakete, die auf dem Betriebssystem basieren, konnte ich die Module nicht einfach lokal installieren - und dann den Container starten.

Meine Lösung für dieses Problem bestand darin, die Quelle in einen src -Ordner zu packen und dann node_modules Mit diese index.js-Datei in diesen Ordner zu verlinken. Die Datei index.js Ist nun der Ausgangspunkt meiner Anwendung.

Beim Ausführen des Containers habe ich den Ordner /app/src In meinen lokalen Ordner src geladen.

Der Containerordner sieht also ungefähr so ​​aus:

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

Es ist hässlich , aber es funktioniert ..

12
JAM

Aufgrund von wie Node.js Module lädt , node_modules kann sich an einer beliebigen Stelle im Pfad zu Ihrem Quellcode befinden. Setzen Sie Ihre Quelle zum Beispiel auf /worker/src und dein package.json im /worker, damit /worker/node_modules ist, wo sie installiert sind.

9
Justin Stayton

Das Installieren von node_modules im Container in einem anderen als dem Projektordner und das Festlegen von NODE_PATH in Ihrem node_modules-Ordner hilft mir (Sie müssen den Container neu erstellen).

Ich benutze Docker-Compose. Meine Projektdateistruktur:

-/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

Dockerfile im nodejs Ordner:

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
6
sergeysynergy

Es gibt auch eine einfache Lösung ohne Zuordnung node_module Verzeichnis in ein anderes Volume. Es geht darum, die Installation von npm-Paketen in den endgültigen CMD-Befehl zu verschieben.

Nachteil dieses Ansatzes:

  • lauf npm install jedes Mal, wenn Sie Container ausführen (das Umschalten von npm auf yarn kann diesen Vorgang auch etwas beschleunigen).

arbeiter/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
5
Egel

Es gibt zwei unterschiedliche Anforderungen für Node-Dev-Umgebungen: Mounten Sie Ihren Quellcode in den Container und mounten Sie die node_modules aus dem Container (für Ihre IDE). Um das erste zu erreichen, machst du das übliche Mount, aber nicht alles ... nur die Dinge, die du brauchst

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

(der Grund, nicht zu tun - /worker/node_modules liegt daran, dass docker-compose dieses Volume zwischen den Durchläufen beibehält, was bedeutet, dass Sie von dem abweichen können, was sich tatsächlich im Image befindet (um nicht nur die Bereitstellung von Ihrem Host zu binden).

Der zweite ist tatsächlich schwieriger. Meine Lösung ist ein bisschen hackisch, aber es funktioniert. Ich habe ein Skript, um den Ordner node_modules auf meinem Host-Computer zu installieren, und ich muss nur daran denken, es aufzurufen, wenn ich package.json aktualisiere (oder es dem make-Ziel hinzufüge, das docker-compose build lokal ausführt).

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

Meiner Meinung nach sollten wir nicht RUN npm install in der Dockerfile. Stattdessen können wir einen Container mit bash starten, um die Abhängigkeiten zu installieren, bevor wir den formalen Knotendienst ausführen

docker run -it -v ./app:/usr/src/app  your_node_image_name  /bin/bash
[email protected]:/usr/src/app# npm install
2
salamander

Sie können so etwas in Ihrem Dockerfile ausprobieren:

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

Dann solltest du das Volume so benutzen:

volumes:
  - worker/:/worker:rw

Das Startscript sollte Teil Ihres Worker-Repositorys sein und wie folgt aussehen:

#!/bin/sh
npm install
npm start

Die node_modules sind also Teil Ihres Worker-Volumes und werden synchronisiert und die npm-Skripte werden ausgeführt, wenn alles läuft.

1
Parav01d