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.jsarchivo 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_modulescomo 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.ymlarchivo. 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
workerdirectorio 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_modulesdirectorio se crea dentro delworkerdirectorio y todas las dependencias se instalan allí. Luego, en tiempo de ejecución, elworkerdirectorio desde el acoplador externo se monta en la instancia del acoplador (que no tiene el instaladonode_modules), ocultando elnode_modulesque 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 imagenworkeracoplada construida antes de montar el directorio. Esto se puede hacer de ladocker-compose.ymlsiguiente 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_modulesmantuvo igual que antes (con dependencias antiguas). ¿Hay algún truco para usar el nuevo volumen al reconstruir la imagen?docker-compose rmparece solucionar este problema, pero creo que debe haber una solución mejor y más fácil.rebuild --no-cachecada vez que cambian los departamentos?El
node_modulesvolumen 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_modulesse puede acceder al directorio desde fuera del contenedor porque está incluido en la imagen.fuente
node_modulesno 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.ymlarchivo (docker-compose versión 1.6+):mi estructura de archivos es:
Crea un volumen con nombre
project_node_modulesy lo reutiliza cada vez que subo mi aplicación.Mi
docker volume lsaspecto es este:fuente
Recientemente tuve un problema similar. Puede instalar en
node_modulesotro lugar y establecer laNODE_PATHvariable de entorno.En el siguiente ejemplo, instalé
node_modulesen/installtrabajador / Dockerfile
docker-compose.yml
fuente
node_modulesfunció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 installallí, luego especificar laNODE_PATHvariable de entornodocker-compose.ymlpara que apunte a lanode_modulescarpeta de ese directorio que funciona y se siente bien.npm installen el host? Parecenode_modulesque 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
/workerse 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
srccarpeta, luego vincularlanode_modulesa esa carpeta, usando este archivo index.js . Entonces, elindex.jsarchivo es ahora el punto de partida de mi aplicación.Cuando ejecuto el contenedor, monté la
/app/srccarpeta en mi localsrccarpeta .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_modulespuede estar en cualquier parte de la ruta a su código fuente. Por ejemplo, poner su origen en/worker/srcy supackage.jsonen/worker, por lo que/worker/node_moduleses 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_PATHFue la clave para mí.CMD npm startno usa el NODE_PATH especificado.También hay una solución simple sin asignar el
node_moduledirectorio 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_moduleses 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 installen el Dockerfile. En cambio, podemos iniciar un contenedor usando bash para instalar las dependencias antes de ejecutar el servicio de nodo formalfuente
node_modulessea persistente incluso después de retirar el contenedor, también debe saber cuándo o cuándo hacerlonpm installmanualmente. 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