Ich habe eine App mit folgenden Diensten:
web/
- hält einen Python 3-Flask-Webserver auf Port 5000 und führt ihn aus. Verwendet sqlite3.worker/
- hat eineindex.js
Datei, die ein Arbeiter für eine Warteschlange ist. Der Webserver interagiert mit dieser Warteschlange über eine JSON-API über Port9730
. Der Worker verwendet Redis zur Speicherung. Der Worker speichert Daten auch lokal im Ordnerworker/images/
Jetzt betrifft diese Frage nur die 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 laufe docker-compose build
, funktioniert alles wie erwartet und alle npm-Module werden wie erwartet installiert /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>
Aber wenn ich das tue docker-compose up
, 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 vorhanden ist /worker/node_modules
(auf dem Host oder im Container).
Wenn auf dem Host, ich npm install
, dann funktioniert alles gut. Aber das will ich nicht. Ich möchte, dass der Container Abhängigkeiten behandelt.
Was läuft hier falsch?
(Unnötig zu erwähnen, dass alle Pakete enthalten sind package.json
.)
volumes: - worker/:/worker/
Block aus derdocker-compose.yml
Datei zu entfernen . Diese Zeile überschreibt den Ordner, den Sie mit dem Befehl COPY erstellen.When I run docker-compose build, everything works as expected and all npm modules are installed in /worker/node_modules as I'd expect.
- Wie hast du das überprüft?Antworten:
Dies liegt daran, dass Sie Ihr
worker
Verzeichnis als Volume zu Ihrem hinzugefügt habendocker-compose.yml
, da das Volume während des Builds nicht bereitgestellt wird.Wenn Docker das Image erstellt, wird das
node_modules
Verzeichnis innerhalb desworker
Verzeichnisses erstellt und alle Abhängigkeiten werden dort installiert. Zur Laufzeit wird dasworker
Verzeichnis von außerhalb des Dockers in die Docker-Instanz eingebunden (auf der das Docker nicht installiert istnode_modules
), wodurch dasnode_modules
gerade installierte Verzeichnis ausgeblendet wird . Sie können dies überprüfen, indem Sie das bereitgestellte Volume von Ihrem entfernendocker-compose.yml
.Eine Problemumgehung besteht darin, ein Datenvolume zum Speichern aller Daten zu verwenden
node_modules
, da Datenvolumes die Daten aus dem erstellten Docker-Image kopieren, bevor dasworker
Verzeichnis bereitgestellt wird. Dies kann folgendermaßen geschehendocker-compose.yml
: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 Volumes erfahren möchten, finden Sie hier eine nette Bedienungsanleitung: https://docs.docker.com/userguide/dockervolumes/
BEARBEITEN: Docker hat seitdem seine Syntax dahingehend geändert, dass ein Leading
./
für das Mounten in Dateien relativ zur Datei docker-compose.yml erforderlich ist.quelle
/worker/node_modules
unverändert geblieben (mit alten Abhängigkeiten). Gibt es einen Trick, wie man beim Wiederherstellen des Images ein neues Volume verwendet?docker-compose rm
scheint die Verwendung dieses Problems zu beheben, aber ich glaube, es muss eine bessere und einfachere Lösung geben.rebuild --no-cache
Deps jedes Mal ändern müssen?Der
node_modules
Ordner wird vom Volume überschrieben und ist im Container nicht mehr zugänglich. Ich verwende die native Modul-Ladestrategie , um den Ordner aus dem Volume zu entfernen:Dockerfile:
Auf das
node_modules
Verzeichnis kann von außerhalb des Containers nicht zugegriffen werden, da es im Bild enthalten ist.quelle
node_modules
ist nicht von außerhalb des Containers zugänglich, aber nicht wirklich ein Nachteil;)docker-compose run app npm install
, erstellen Sie ein Knotenmodul im aktuellen Verzeichnis und müssen das Image nicht mehr neu erstellen.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+):Meine Dateistruktur ist:
Es erstellt ein Volume mit dem Namen
project_node_modules
und verwendet es jedes Mal wieder, wenn ich meine Anwendung starte.Mein
docker volume ls
sieht so aus:quelle
Ich hatte kürzlich ein ähnliches Problem. Sie können an einer
node_modules
anderen Stelle installieren und dieNODE_PATH
Umgebungsvariable festlegen .Im Beispiel unten habe ich installiert
node_modules
in/install
Arbeiter / Dockerfile
docker-compose.yml
quelle
node_modules
basierend auf diesem Artikel überschrieb . Aber es hat mich dazu gebracht, dieses Problem zu erleben . Diese Lösung besteht darin, ein separates Verzeichnis zu erstellenpackage.json
, in das Sienpm install
es kopieren , dort ausführen und dann dieNODE_PATH
Umgebungsvariable angeben könnendocker-compose.yml
, um auf dennode_modules
Ordner dieses Verzeichnisses zu verweisen .npm install
auf dem Host laufen ? Es scheintnode_modules
auf dem Host zu erscheinen und wird im Container wiedergegeben, wobei Vorrang vor dem Container bestehtNODE_PATH
. Der Container verwendet also node_modules vom Host.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
npm_modules
.Beispiel:
Dockerfile.dev:
quelle
UPDATE: Verwenden Sie die Lösung von @FrederikNS zur Verfügung gestellt.
Ich bin auf das gleiche Problem gestoßen. Wenn der Ordner
/worker
in den Container eingebunden wird, wird der gesamte Inhalt synchronisiert (sodass der Ordner node_modules verschwindet, wenn Sie ihn nicht lokal haben.)Aufgrund inkompatibler npm-Pakete, die auf dem Betriebssystem basieren, konnte ich die Module nicht nur lokal installieren, sondern auch den Container starten.
Meine Lösung bestand darin, die Quelle in einen
src
Ordner zu packen und dannnode_modules
mit dieser Datei index.js in diesen Ordner zu verlinken . Dieindex.js
Datei ist nun der Ausgangspunkt meiner Anwendung.Wenn ich den Container ausführe, habe ich den
/app/src
Ordner in meinen lokalensrc
Ordner eingebunden.Der Containerordner sieht also ungefähr so aus:
Es ist hässlich , aber es funktioniert ..
quelle
Aufgrund der Art und Weise, wie Node.js Module lädt ,
node_modules
kann es sich an einer beliebigen Stelle im Pfad zu Ihrem Quellcode befinden. Legen Sie beispielsweise Ihre Quelle an/worker/src
und Ihrepackage.json
in/worker
, also/worker/node_modules
dort, wo sie installiert sind.quelle
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:
docker-compose.yml:
Docker-Datei im Ordner nodejs:
quelle
NODE_PATH
war der Schlüssel für mich.CMD npm start
nicht das angegebene NODE_PATH verwendet.Es gibt auch eine einfache Lösung, ohne das
node_module
Verzeichnis einem anderen Volume zuzuordnen. Es geht darum, die Installation von npm-Paketen in den endgültigen CMD-Befehl zu verschieben.Arbeiter / Dockerfile
docker-compose.yml
quelle
Es gibt zwei separate Anforderungen, die ich für Knotenentwicklungsumgebungen sehe ... Mounten Sie Ihren Quellcode in den Container und mounten Sie die Node_Module aus dem Container (für Ihre IDE). Um das erste zu erreichen, machst du das übliche Reittier, aber nicht alles ... nur die Dinge, die du brauchst
(Der Grund dafür
- /worker/node_modules
ist, dass Docker-Compose dieses Volume zwischen den Läufen beibehält, was bedeutet, dass Sie von dem, was tatsächlich im Image enthalten ist, abweichen können (was den Zweck zunichte macht, nicht nur das Mounten von Ihrem Host zu binden)).Der zweite ist eigentlich schwieriger. Meine Lösung ist ein bisschen hackisch, aber es funktioniert. Ich habe ein Skript zum Installieren des Ordners node_modules auf meinem Hostcomputer, und ich muss nur daran denken, es aufzurufen, wenn ich package.json aktualisiere (oder es dem make-Ziel hinzufüge, auf dem Docker-Compose Build lokal ausgeführt wird).
quelle
Meiner Meinung nach sollten wir nicht
RUN npm install
in die Dockerfile. Stattdessen können wir einen Container mit bash starten, um die Abhängigkeiten zu installieren, bevor der formale Knotendienst ausgeführt wirdquelle
node_modules
auch nach dem Entfernen des Containers dauerhaft bleiben, sollten Sie auch wissen, wann oder wann Sie dies nichtnpm install
manuell tun müssen. OP schlägt vor, dies bei jedem Image-Build zu tun . Sie können das tun, aber Sie müssen dafür nicht auch ein Volume verwenden. Bei jedem Build sind die Module auf jeden Fall auf dem neuesten Stand.Sie können so etwas in Ihrer Docker-Datei ausprobieren:
Dann sollten Sie das Volume wie folgt verwenden:
Das Startskript sollte Teil Ihres Worker-Repositorys sein und sieht folgendermaßen aus:
Die node_modules sind also Teil Ihres Worker-Volumes und werden synchronisiert und die npm-Skripte werden ausgeführt, wenn alles in Betrieb ist.
quelle
Sie können Ihre Docker-Datei aufgrund ihrer Einfachheit auch über Bord werfen. Verwenden Sie einfach ein Basisbild und geben Sie den Befehl in Ihrer Erstellungsdatei an:
Dies ist besonders nützlich für mich, da ich nur die Umgebung des Bildes benötige, aber meine Dateien außerhalb des Containers bearbeite und ich denke, dass Sie dies auch tun möchten.
quelle