nodejs compose node.js docker ubuntu-14.04 docker-compose

node.js - docker compose nodejs



Docker-compose: node_modules no está presente en un volumen después de que la instalación de npm se realice correctamente (12)

Tengo una aplicación con los siguientes servicios:

  • web/ - mantiene y ejecuta un servidor web de matraz python 3 en el puerto 5000. Utiliza sqlite3.
  • worker/ - tiene un archivo index.js que es un trabajador para una cola. el servidor web interactúa con esta cola utilizando una API json a través del puerto 9730 . El trabajador usa redis para el almacenamiento. El trabajador también almacena datos localmente en la carpeta worker/images/

Ahora esta pregunta solo concierne al 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

Cuando ejecuto docker-compose build , todo funciona como se esperaba y todos los módulos npm se instalan en /worker/node_modules como esperaba.

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>

Pero cuando docker-compose up , veo este error:

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)

Resulta que ninguno de los módulos está presente en /worker/node_modules (en el host o en el contenedor).

Si en el host, npm install , entonces todo funciona bien. Pero no quiero hacer eso. Quiero que el contenedor maneje las dependencias.

¿Qué está pasando mal aquí?

(No hace falta decir que todos los paquetes están en package.json ).


ACTUALIZACIÓN: utilice la solution proporcionada por @FrederikNS.

Encontré el mismo problema. Cuando la carpeta /worker se monta en el contenedor, todo su contenido se sincronizará (por lo que la carpeta node_modules desaparecerá si no lo tiene localmente).

Debido a los paquetes npm incompatibles basados ​​en el sistema operativo, no pude simplemente instalar los módulos localmente, luego iniciar el contenedor, así que ...

Mi solución a esto fue envolver la fuente en una carpeta src , luego vincular node_modules a esa carpeta, usando este archivo index.js . Entonces, el archivo index.js es ahora el punto de partida de mi aplicación.

Cuando ejecuto el contenedor, monté la carpeta /app/src en mi carpeta src local.

Entonces la carpeta del contenedor se ve así:

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

Es feo , pero funciona.


Debido a la forma en que Node.js carga los módulos , node_modules puede estar en cualquier parte de la ruta a su código fuente. Por ejemplo, coloque su fuente en /worker/src y su package.json en /worker , entonces /worker/node_modules es donde están instalados.


El volumen sobrescribe la carpeta node_modules y ya no se puede acceder a ella en el contenedor. Estoy usando la estrategia de carga del módulo nativo para extraer la carpeta del volumen:

/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 se puede acceder a node_modules desde fuera del contenedor porque está incluido en la imagen.


En mi opinión, no deberíamos RUN npm install en el Dockerfile. En cambio, podemos iniciar un contenedor usando bash para instalar las dependencias antes de ejecutar el servicio de nodo formal

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


Esto sucede porque ha agregado su directorio de worker como un volumen a su docker-compose.yml , ya que el volumen no se monta durante la compilación.

Cuando Docker construye la imagen, el directorio node_modules se crea dentro del directorio de worker y todas las dependencias se instalan allí. Luego, en tiempo de ejecución, el directorio de worker desde la ventana acoplable externa se monta en la instancia de la ventana acoplable (que no tiene los node_modules instalados), ocultando los node_modules que acaba de instalar. Puede verificar esto eliminando el volumen montado de su docker-compose.yml .

Una solución alternativa es usar un volumen de datos para almacenar todos los node_modules , ya que los volúmenes de datos copian los datos de la imagen acoplada construida antes de montar el directorio de worker . Esto se puede hacer en el docker-compose.yml esta manera:

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

No estoy completamente seguro de si esto impone algún problema para la portabilidad de la imagen, pero como parece que está utilizando principalmente Docker para proporcionar un entorno de tiempo de ejecución, esto no debería ser un problema.

Si desea leer más sobre los volúmenes, hay una buena guía de usuario disponible aquí: https://docs.docker.com/userguide/dockervolumes/


Hay dos requisitos separados que veo para los entornos de desarrollo de nodos ... monte su código fuente EN el contenedor y monte los node_modules DESDE el contenedor (para su IDE). Para lograr lo primero, haces el montaje habitual, pero no todo ... solo las cosas que necesitas

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

(la razón para no hacerlo - /worker/node_modules es porque docker-compose persistirá ese volumen entre ejecuciones, lo que significa que puede divergir de lo que realmente está en la imagen (lo que frustra el propósito de no solo vincular el montaje desde su host)).

El segundo es realmente más difícil. Mi solución es un poco hack, pero funciona. Tengo un script para instalar la carpeta node_modules en mi máquina host, y solo tengo que recordar llamarlo cada vez que actualizo package.json (o lo agrego al destino make que ejecuta la compilación docker-compose localmente).

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


Hay una solución elegante:

Simplemente monte no todo el directorio, sino solo el directorio de la aplicación. De esta manera no tendrás problemas con npm_modules .

Ejemplo:

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


Instalar node_modules en el contenedor para que sea diferente de la carpeta del proyecto, y configurar NODE_PATH en su carpeta node_modules me ayuda (necesita reconstruir el contenedor).

Estoy usando docker-compose. Estructura del archivo de mi proyecto:

-/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 en la carpeta nodejs:

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


La solución proporcionada por @FrederikNS funciona, pero prefiero nombrar explícitamente mi volumen node_modules.

Mi project/docker-compose.yml (docker-compose versión 1.6+):

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

mi estructura de archivos es:

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

Crea un volumen llamado project_node_modules y lo reutiliza cada vez que project_node_modules mi aplicación.

Mi docker volume ls ve así:

DRIVER VOLUME NAME local project1_mysql local project1_node_modules local project2_postgresql local project2_node_modules


Puedes probar algo como esto en tu Dockerfile:

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

Entonces deberías usar el Volumen así:

volumes: - worker/:/worker:rw

El script de inicio debe ser parte de su repositorio de trabajo y se ve así:

#!/bin/sh npm install npm start

Entonces, los node_modules son parte de su volumen de trabajo y se sincronizan y los scripts npm se ejecutan cuando todo está activo.


Recientemente tuve un problema similar. Puede instalar node_modules otro lugar y establecer la variable de entorno NODE_PATH .

En el ejemplo a continuación, instalé node_modules en /install

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


También hay una solución simple sin asignar el directorio node_module a otro volumen. Está a punto de mover la instalación de paquetes npm al comando CMD final.

Desventaja de este enfoque:

  • ejecute npm install cada vez que ejecute el contenedor (cambiar de npm a yarn también podría acelerar un poco este proceso).

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