node elastic aws node.js git amazon-web-services npm elastic-beanstalk

node.js - elastic - evite reconstruir node_modules en beanstalk elástico



beanstalk node js (5)

Tenemos una aplicación node.js bastante simple, pero debido al mecanismo de despliegue de AWS Elastic Beanstalk, se tarda unos 5 minutos en implementar una nueva versión (a través de git aws.push ) incluso después de la confirmación de un solo archivo.

Es decir, la confirmación (y la carga) es rápida (solo 1 archivo para enviar), pero luego Elastic Beanstalk recupera el paquete completo de S3, lo descomprime y ejecuta la npm install , lo que hace que node-gyp compile algunos módulos. Al finalizar la instalación / construcción, Elastic Beanstalk limpia /var/app/current y lo reemplaza con la nueva versión de la aplicación.

Huelga decir que la reconstrucción constante de node_modules no es necesaria, y la reconstrucción que lleva 30 segundos en mi Macbook Air anterior, lleva más de 5 minutos en una instancia de ec2.micro, no es divertido.

Veo dos enfoques aquí:

  1. modifica /opt/containerfiles/ebnode.py y juega con la ubicación node_modules para evitar su eliminación y reconstrucción al momento de la implementación.
  2. configure un git repo en la instancia de Elastic Beanstalk EC2 y básicamente vuelva a escribir el procedimiento de implementación nosotros mismos, para que / var / app / current reciba npm install y ejecute npm install solo cuando sea necesario (lo que hace que Elastic Beanstalk se vea como OpsWorks ...)

Ambas opciones carecen de gracia y son propensas a problemas cuando Amazon actualiza sus ganchos y arquitectura Elastic Beanstalk.

Tal vez alguien tenga una mejor idea de cómo evitar la reconstrucción constante de node_modules que ya están presentes en el directorio de la aplicación. Gracias.


25/01/13 NOTA: scripts actualizados para ejecutar la actualización de la versión npm -g (solo una vez, en la instancia inicial desplegada o reconstruida) y para evitar las operaciones de NPM durante el cambio de configuración de EB (cuando el directorio de la aplicación no está presente, para evitar errores y acelerar las actualizaciones de configuración).

De acuerdo, Elastic Beanstalk se comporta de manera dudosa con las compilaciones recientes de node.js (incluida la supuestamente compatible v.0.10.10), así que decidí seguir adelante y modificar EB para que hiciera lo siguiente:

  1. para instalar CUALQUIER versión de node.js según su env.config (incluidas las más recientes que aún no son compatibles con AWS EB)
  2. para evitar la reconstrucción de módulos de nodos existentes, incluido in-app node_modules dir
  3. para instalar node.js globalmente (y cualquier módulo deseado también).

Básicamente, utilizo env.config para reemplazar los enganches deploy y config con los personalizados (ver a continuación). Además, en una configuración de contenedor de EB predeterminada faltan algunas variables env ( $HOME por ejemplo) y node-gyp veces falla durante la reconstrucción debido a esto (me llevó 2 horas de googlear y reinstalar libxmljs para resolver esto).

A continuación se muestran los archivos que se incluirán junto con su compilación. Puede inyectarlos a través de env.config como código en línea o vía source: URL (como en este ejemplo)

env.vars (la versión y el arco del nodo deseado se incluyen aquí y en env.config, ver a continuación)

export HOME=/root export NPM_CONFIG_LOGLEVEL=error export NODE_VER=0.10.24 export ARCH=x86 export PATH="$PATH:/opt/elasticbeanstalk/node-install/node-v$NODE_VER-linux-$ARCH/bin/:/root/.npm"

40install_node.sh (buscar y descomprimir la versión node.js deseada, crear enlaces simbólicos globales, actualizar la versión global de npm)

#!/bin/bash #source env variables including node version . /opt/elasticbeanstalk/env.vars function error_exit { eventHelper.py --msg "$1" --severity ERROR exit $2 } #UNCOMMENT to update npm, otherwise will be updated on instance init or rebuild #rm -f /opt/elasticbeanstalk/node-install/npm_updated #download and extract desired node.js version OUT=$( [ ! -d "/opt/elasticbeanstalk/node-install" ] && mkdir /opt/elasticbeanstalk/node-install ; cd /opt/elasticbeanstalk/node-install/ && wget -nc http://nodejs.org/dist/v$NODE_VER/node-v$NODE_VER-linux-$ARCH.tar.gz && tar --skip-old-files -xzpf node-v$NODE_VER-linux-$ARCH.tar.gz) || error_exit "Failed to UPDATE node version. $OUT" $?. echo $OUT #make sure node binaries can be found globally if [ ! -L /usr/bin/node ]; then ln -s /opt/elasticbeanstalk/node-install/node-v$NODE_VER-linux-$ARCH/bin/node /usr/bin/node fi if [ ! -L /usr/bin/npm ]; then ln -s /opt/elasticbeanstalk/node-install/node-v$NODE_VER-linux-$ARCH/bin/npm /usr/bin/npm fi if [ ! -f "/opt/elasticbeanstalk/node-install/npm_updated" ]; then /opt/elasticbeanstalk/node-install/node-v$NODE_VER-linux-$ARCH/bin/ && /opt/elasticbeanstalk/node-install/node-v$NODE_VER-linux-$ARCH/bin/npm update npm -g touch /opt/elasticbeanstalk/node-install/npm_updated echo "YAY! Updated global NPM version to `npm -v`" else echo "Skipping NPM -g version update. To update, please uncomment 40install_node.sh:12" fi

50npm.sh (crea / var / node_modules, lo enlaza al directorio de la aplicación y ejecuta la instalación de npm. Puede instalar cualquier módulo de forma global desde aquí, irán a /root/.npm)

#!/bin/bash . /opt/elasticbeanstalk/env.vars function error_exit { eventHelper.py --msg "$1" --severity ERROR exit $2 } #install not-installed yet app node_modules if [ ! -d "/var/node_modules" ]; then mkdir /var/node_modules ; fi if [ -d /tmp/deployment/application ]; then ln -s /var/node_modules /tmp/deployment/application/ fi OUT=$([ -d "/tmp/deployment/application" ] && cd /tmp/deployment/application && /opt/elasticbeanstalk/node-install/node-v$NODE_VER-linux-$ARCH/bin/npm install 2>&1) || error_exit "Failed to run npm install. $OUT" $? echo $OUT

env.config (observe la versión del nodo aquí también, y para estar seguro, coloque también la versión de nodo deseada en la configuración de env en la consola de AWS. No estoy seguro de cuál de estas configuraciones tendrá prioridad).

packages: yum: git: [] gcc: [] make: [] openssl-devel: [] option_settings: - option_name: NODE_ENV value: production - option_name: RDS_HOSTNAME value: fill_me_in - option_name: RDS_PASSWORD value: fill_me_in - option_name: RDS_USERNAME value: fill_me_in - namespace: aws:elasticbeanstalk:container:nodejs option_name: NodeVersion value: 0.10.24 files: "/opt/elasticbeanstalk/env.vars" : mode: "000775" owner: root group: users source: https://dl.dropbox.com/.... "/opt/elasticbeanstalk/hooks/configdeploy/pre/40install_node.sh" : mode: "000775" owner: root group: users source: https://raw.github.com/.... "/opt/elasticbeanstalk/hooks/appdeploy/pre/50npm.sh" : mode: "000775" owner: root group: users source: https://raw.github.com/.... "/opt/elasticbeanstalk/hooks/configdeploy/pre/50npm.sh" : mode: "000666" owner: root group: users content: | #no need to run npm install during configdeploy "/opt/elasticbeanstalk/hooks/appdeploy/pre/40install_node.sh" : mode: "000775" owner: root group: users source: https://raw.github.com/....

Ahí lo tienes: ¡en el despliegue de instancias t1.micro ahora toma 20-30 segundos en vez de 10-15 minutos! Si despliega 10 veces al día, este ajuste le ahorrará 3 (tres) semanas en un año. Espero que ayude y un agradecimiento especial al personal de AWS EB por mi fin de semana perdido :)


Gracias Kirill, ¡fue realmente útil!

Solo estoy compartiendo mi archivo de configuración para las personas que solo buscan la solución simple para la npm install . Este archivo debe colocarse en la carpeta .ebextensions del proyecto, es más ligero ya que no incluye la última versión de la instalación del nodo y está listo para usar.

También comprueba dinámicamente la versión del nodo instalada, por lo que no es necesario que se incluya en el archivo env.vars.

.ebextensions/00_deploy_npm.config

files: "/opt/elasticbeanstalk/env.vars" : mode: "000775" owner: root group: users content: | export NPM_CONFIG_LOGLEVEL=error export NODE_PATH=`ls -td /opt/elasticbeanstalk/node-install/node-* | head -1`/bin "/opt/elasticbeanstalk/hooks/appdeploy/pre/50npm.sh" : mode: "000775" owner: root group: users content: | #!/bin/bash . /opt/elasticbeanstalk/env.vars function error_exit { eventHelper.py --msg "$1" --severity ERROR exit $2 } #install not-installed yet app node_modules if [ ! -d "/var/node_modules" ]; then mkdir /var/node_modules ; fi if [ -d /tmp/deployment/application ]; then ln -s /var/node_modules /tmp/deployment/application/ fi OUT=$([ -d "/tmp/deployment/application" ] && cd /tmp/deployment/application && $NODE_PATH/npm install 2>&1) || error_exit "Failed to run npm install. $OUT" $? echo $OUT "/opt/elasticbeanstalk/hooks/configdeploy/pre/50npm.sh" : mode: "000666" owner: root group: users content: | #no need to run npm install during configdeploy


Hay un paquete npm que sobrescribe el comportamiento EB predeterminado para el npm install al truncar los siguientes archivos:

  • /opt/elasticbeanstalk/hooks/appdeploy/pre/50npm.sh
  • /opt/elasticbeanstalk/hooks/configdeploy/pre/50npm.sh

https://www.npmjs.com/package/eb-disable-npm

Sería mejor que copiar el script de SO, ya que este paquete se mantiene y probablemente se actualizará cuando cambie el comportamiento de EB.


He encontrado una solución rápida para esto. Miré a través de los scripts de compilación que Amazon está utilizando y solo ejecutan npm install si está presente el paquete.json. Entonces, después de su implementación inicial, puede cambiarlo a _package.json y npm install ya no se ejecutará! No es la mejor solución pero es una solución rápida si la necesitas.