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 unindex.js
archivo que es un trabajador para una cola. el servidor web interactúa con esta cola utilizando una API json a través del puerto9730
. El trabajador usa redis para el almacenamiento. El trabajador también almacena datos localmente en la carpetaworker/images/
Ahora esta pregunta solo concierne a la 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 /worker/node_modules
como esperaba.
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>
Pero cuando lo hago 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, yo 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 incluidos) package.json
.
volumes: - worker/:/worker/
bloque deldocker-compose.yml
archivo. Esta línea sobrescribe la carpeta que crea con el comando COPIAR.When I run docker-compose build, everything works as expected and all npm modules are installed in /worker/node_modules as I'd expect.
- ¿Cómo verificaste esto?Respuestas:
Esto sucede porque ha agregado su
worker
directorio como un volumen a sudocker-compose.yml
, ya que el volumen no se monta durante la compilación.Cuando Docker construye la imagen, el
node_modules
directorio se crea dentro delworker
directorio y todas las dependencias se instalan allí. Luego, en tiempo de ejecución, elworker
directorio desde el acoplador externo se monta en la instancia del acoplador (que no tiene el instaladonode_modules
), ocultando elnode_modules
que acaba de instalar. Puede verificar esto quitando el volumen montado de sudocker-compose.yml
.Una solución alternativa es utilizar un volumen de datos para almacenar todo
node_modules
, ya que los volúmenes de datos copian los datos de la imagenworker
acoplada construida antes de montar el directorio. Esto se puede hacer de ladocker-compose.yml
siguiente manera: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/
EDITAR: desde entonces Docker ha cambiado su sintaxis para requerir un
./
inicio para el montaje en archivos relativos al archivo docker-compose.yml.fuente
/worker/node_modules
mantuvo igual que antes (con dependencias antiguas). ¿Hay algún truco para usar el nuevo volumen al reconstruir la imagen?docker-compose rm
parece solucionar este problema, pero creo que debe haber una solución mejor y más fácil.rebuild --no-cache
cada vez que cambian los departamentos?El
node_modules
volumen sobrescribe la carpeta 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:Dockerfile:
No
node_modules
se puede acceder al directorio desde fuera del contenedor porque está incluido en la imagen.fuente
node_modules
no es accesible desde el exterior del contenedor pero no es realmente un inconveniente;)docker-compose run app npm install
, creará un node_modules en el directorio actual y ya no necesitará reconstruir la imagen.La solución proporcionada por @FrederikNS funciona, pero prefiero nombrar explícitamente mi volumen node_modules.
Mi
project/docker-compose.yml
archivo (docker-compose versión 1.6+):mi estructura de archivos es:
Crea un volumen con nombre
project_node_modules
y lo reutiliza cada vez que subo mi aplicación.Mi
docker volume ls
aspecto es este:fuente
Recientemente tuve un problema similar. Puede instalar en
node_modules
otro lugar y establecer laNODE_PATH
variable de entorno.En el siguiente ejemplo, instalé
node_modules
en/install
trabajador / Dockerfile
docker-compose.yml
fuente
node_modules
función de este artículo . Pero me llevó a experimentar este problema . Esta solución aquí es crear un directorio separado para copiarlopackage.json
, ejecutarlonpm install
allí, luego especificar laNODE_PATH
variable de entornodocker-compose.yml
para que apunte a lanode_modules
carpeta de ese directorio que funciona y se siente bien.npm install
en el host? Parecenode_modules
que aparecerá en el host y se reflejará en el contenedor, teniendo prioridad sobreNODE_PATH
. Por lo tanto, el contenedor usará node_modules del host.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
npm_modules
.Ejemplo:
Dockerfile.dev:
fuente
ACTUALIZACIÓN: utilice la solución 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 la 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
src
carpeta, luego vincularlanode_modules
a esa carpeta, usando este archivo index.js . Entonces, elindex.js
archivo es ahora el punto de partida de mi aplicación.Cuando ejecuto el contenedor, monté la
/app/src
carpeta en mi localsrc
carpeta .Entonces la carpeta del contenedor se ve así:
Es feo , pero funciona.
fuente
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, poner su origen en/worker/src
y supackage.json
en/worker
, por lo que/worker/node_modules
es donde están instalados.fuente
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:
docker-compose.yml:
Dockerfile en la carpeta nodejs:
fuente
NODE_PATH
Fue la clave para mí.CMD npm start
no usa el NODE_PATH especificado.También hay una solución simple sin asignar el
node_module
directorio a otro volumen. Está a punto de mover la instalación de paquetes npm al comando CMD final.trabajador / Dockerfile
docker-compose.yml
fuente
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
(la razón para no hacer
- /worker/node_modules
es porque docker-compose persistirá en ese volumen entre ejecuciones, lo que significa que puede diferir de lo que realmente está en la imagen (lo que anula 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).
fuente
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 formalfuente
node_modules
sea persistente incluso después de retirar el contenedor, también debe saber cuándo o cuándo hacerlonpm install
manualmente. OP sugiere hacerlo en cada compilación de imagen . Puede hacerlo, pero no necesita usar también un volumen para eso. En cada compilación, los módulos estarán actualizados en cualquier momento.Puede probar algo como esto en su Dockerfile:
Entonces deberías usar el Volumen así:
El script de inicio debe ser parte de su repositorio de trabajo y se ve así:
Entonces, los node_modules son parte de su volumen de trabajo y se sincronizan y los scripts npm se ejecutan cuando todo está activo.
fuente
También puede deshacerse de su Dockerfile, debido a su simplicidad, simplemente use una imagen básica y especifique el comando en su archivo de redacción:
Esto es particularmente útil para mí, porque solo necesito el entorno de la imagen, pero operar en mis archivos fuera del contenedor y creo que esto es lo que quieres hacer también.
fuente