node.js - node - Ejecutar Grunt/Gulp dentro de contenedor Docker o fuera?
nodejs inspect (3)
Estoy tratando de identificar una buena práctica para el proceso de compilación de una aplicación nodejs usando grunt / gulp para ser implementada dentro de un contenedor docker.
Estoy muy contento con la siguiente secuencia:
- construir usando un gruñido (o trago) fuera del recipiente
- agregar la carpeta ./dist al contenedor
- ejecutar npm install (con - marca de producción) dentro del contenedor
Pero en cada ejemplo que encuentro, veo un enfoque diferente:
- agregar la carpeta ./src al contenedor
- ejecutar npm install (con dependencias de desarrollo) dentro del contenedor
- ejecutar la instalación de la planta (si es necesario) dentro del contenedor
- ejecutar gruñido (o trago) dentro del contenedor
En mi opinión, el primer enfoque genera un contenedor más liviano y eficiente, pero todos los ejemplos que hay por ahí utilizan el segundo enfoque. ¿Me estoy perdiendo de algo?
La única diferencia que veo es que puede reproducir una instalación de gruñido completo en el segundo enfoque.
Con la primera, usted depende de una acción local que podría realizarse de manera diferente, en diferentes entornos.
Un contenedor debe basarse en una imagen que pueda reproducirse fácilmente en lugar de depender de una carpeta de host que contenga "lo que se necesita" (sin saber cómo se ha hecho esa parte)
Si la sobrecarga del entorno de compilación que viene con la instalación es demasiado para una imagen ronca, puede:
- cree una imagen "
app.tar
" dedicada a la instalación ( lo hice para Apache, que tuve que volver a compilar , creando un paquete deb en un volumen compartido ).
En su caso, puede crear un archivo (''tar'') de la aplicación instalada. creando un contenedor desde una imagen base, usando el volumen de ese primer contenedor
docker run --it --name=app.inst --volumes-from=app.tar ubuntu untar /shared/path/app.tar docker commit app.inst app
Luego, el resultado final es una imagen con la aplicación presente en su sistema de archivos.
Esta es una mezcla entre su enfoque 1 y 2.
Me gustaría sugerir un tercer enfoque que he hecho para un sitio generado estático, la imagen de compilación separada.
En este enfoque, su Dockerfile
principal (el que está en la raíz del proyecto) se convierte en una imagen de compilación y desarrollo, básicamente haciendo todo en el segundo enfoque. Sin embargo, reemplaza el CMD
en tiempo de ejecución, que consiste en dist.tar
carpeta dist
construida en un dist.tar
o similar.
Luego, tienes otra carpeta (algo así como image
) que tiene un Dockerfile
. El rol de esta imagen es solo servir los contenidos dist.tar
. Entonces hacemos una docker cp <container_id_from_tar_run> /dist
. Luego, Dockerfile
solo instala nuestro servidor web y tiene un ADD dist.tar /var/www
.
El resumen es algo como:
- Cree la imagen de Docker del
builder
(que le proporciona un entorno de trabajo sin servidor web). En este punto, la aplicación está construida. Podríamos ejecutar el contenedor en desarrollo congrunt serve
o cualquiera que sea el comando para iniciar nuestro servidor de desarrollo integrado. - En lugar de ejecutar el servidor, anulamos el comando predeterminado para cargar nuestra carpeta dist. Algo como
tar -cf /dist.tar /myapp/dist
. - Ahora tenemos un contenedor temporal con un artefacto
/dist.tar
. Cópielo a su carpeta de Docker de implementación real a la que llamamosimage
usandodocker cp <container_id_from_tar_run> /dist.tar ./image/
. - Ahora, podemos construir la pequeña imagen de Docker sin todas nuestras dependencias de desarrollo con la
docker build ./image
.
Me gusta este enfoque porque todavía es todo Docker. Todos los comandos en este enfoque son comandos de Docker y realmente puede reducir la imagen real que termina desplegando.
Si desea ver una imagen con este enfoque en acción, visite https://github.com/gliderlabs/docker-alpine que usa una imagen de constructor (en la carpeta del constructor) para crear archivos tar.gz que luego se copien a su respectiva carpeta Dockerfile
.
Una variación de la solución 1 es tener un "padre -> hijo" que hace que la construcción del proyecto sea realmente rápida. Tendría archivo docker como:
FROM node
RUN mkdir app
COPY dist/package.json app/package.json
WORKDIR app
RUN npm install
Esto manejará la instalación de las dependencias de los nodos y tendrá otro archivo docker que manejará la "instalación" de la aplicación como:
FROM image-with-dependencies:v1
ENV NODE_ENV=prod
EXPOSE 9001
COPY dist .
ENTRYPOINT ["npm", "start"]
con esto, puede continuar su desarrollo y la "construcción" de la imagen de la ventana acoplable será más rápida de lo que sería si tuviera que "reinstalar" las dependencias del nodo. Si instala nuevas dependencias en el nodo, simplemente vuelva a compilar la imagen de dependencias.
Espero que esto ayude a alguien.
Saludos