node.js - node - elastic beanstalk package json




evite reconstruir node_modules en beanstalk elástico (4)

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 :)

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.


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

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.