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í:
- 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. - 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 ejecutenpm 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:
- 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)
- para evitar la reconstrucción de módulos de nodos existentes, incluido in-app node_modules dir
- 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.
Tenía más de 10 minutos de compilación cuando iba a implementar. La solución fue mucho más simple que la que se les ocurrió a otros ... ¡Simplemente comprueba node_modules en git! Ver http://www.futurealoof.com/posts/nodemodules-in-git.html para el razonamiento