Implementación de una aplicación Node.js Express con clústeres en Elastic Beanstalk - AWS Elastic Beanstalk

Las traducciones son generadas a través de traducción automática. En caso de conflicto entre la traducción y la version original de inglés, prevalecerá la version en inglés.

Implementación de una aplicación Node.js Express con clústeres en Elastic Beanstalk

En este tutorial, se explica cómo implementar una aplicación de ejemplo en Elastic Beanstalk mediante la CLI interfaz de línea de comandos (EB) de Elastic Beanstalk y, a continuación, se actualiza la aplicación para que utilice el marco Express, Amazon y la creación de clústeres. ElastiCache La agrupación en clústeres mejora la disponibilidad, el desempeño y la seguridad de su aplicación web. Para obtener más información sobre Amazon ElastiCache, consulta ¿Qué es Amazon ElastiCache (Memcached)? en la Guía del usuario de Amazon ElastiCache (Memcached).

nota

En este ejemplo se crean AWS recursos, por los que es posible que se le cobre. Para obtener más información sobre AWS los precios, consultehttps://aws.amazon.com/pricing/. Algunos servicios forman parte de la capa de uso AWS gratuito. Si es un cliente nuevo, puede probar estos servicios de forma gratuita. Para obtener más información, consulte https://aws.amazon.com/free/.

Requisitos previos

Este tutorial tiene siguientes los requisitos previos:

  • Los tiempos de ejecución de Node.js

  • El software de gestión de paquetes de Node.js predeterminado, npm

  • El generador de línea de comandos Express

  • Interfaz de línea de comandos (EB) de Elastic Beanstalk CLI

Para obtener más detalles acerca de la instalación de los primeros tres componentes y la configuración de su entorno de desarrollo local, consulte Configuración del entorno de desarrollo de Node.js para Elastic Beanstalk. Para este tutorial, no necesita instalar el archivo Node.js, que también se menciona en el AWS SDK tema al que se hace referencia.

Para obtener información detallada sobre la instalación y configuración del EBCLI, consulte Instalación de la interfaz de línea de comandos de Elastic Beanstalk yConfiguración de la CLI de EB.

Cree un entorno de Elastic Beanstalk

Su directorio de aplicaciones

Este tutorial usa un directorio llamado nodejs-example-express-elasticache para el paquete de origen de la aplicación. Cree el directorio nodejs-example-express-elasticache para este tutorial.

~$ mkdir nodejs-example-express-elasticache
nota

Cada tutorial de este capítulo usa su propio directorio para el paquete de origen de la aplicación. El nombre del directorio coincide con el nombre de la aplicación de ejemplo utilizada en el tutorial.

Cambie su directorio de trabajo actual a nodejs-example-express-elasticache.

~$ cd nodejs-example-express-elasticache

Ahora configuremos un entorno de Elastic Beanstalk que ejecute la plataforma Node.js y la aplicación de ejemplo. Usaremos la interfaz de línea de comandos (EB) de Elastic Beanstalk. CLI

Para configurar un CLI repositorio de EB para su aplicación y crear un entorno de Elastic Beanstalk que ejecute la plataforma Node.js
  1. Cree un repositorio con el comando eb init.

    ~/nodejs-example-express-elasticache$ eb init --platform node.js --region <region>

    Este comando crea un archivo de configuración en una carpeta llamada .elasticbeanstalk que especifica los ajustes para crear los entornos de la aplicación y crea una aplicación de Elastic Beanstalk con el nombre de la carpeta actual.

  2. Cree un entorno que ejecute una aplicación de ejemplo con el comando eb create.

    ~/nodejs-example-express-elasticache$ eb create --sample nodejs-example-express-elasticache

    Este comando crea un entorno con balanceador de carga utilizando la configuración predeterminada de la plataforma de Node.js y los siguientes recursos:

    • EC2instancia: una máquina virtual de Amazon Elastic Compute Cloud (AmazonEC2) configurada para ejecutar aplicaciones web en la plataforma que elijas.

      Cada plataforma ejecuta un conjunto específico de software, archivos de configuración y scripts compatibles con una determinada versión de lenguaje, marco de trabajo y contenedor web (o una combinación de estos). La mayoría de las plataformas utilizan NGINX Apache o un proxy inverso que se coloca delante de la aplicación web, le reenvía las solicitudes, proporciona activos estáticos y genera registros de acceso y errores.

    • Grupo de seguridad de instancias: un grupo EC2 de seguridad de Amazon configurado para permitir el tráfico entrante en el puerto 80. Este recurso permite que el HTTP tráfico del balanceador de cargas llegue a la EC2 instancia que ejecuta tu aplicación web. De forma predeterminada, el tráfico no está permitido en otros puertos.

    • Balanceador de carga: balanceador de carga de Elastic Load Balancing configurado para distribuir solicitudes a las instancias que se ejecutan en la aplicación. Los balanceadores de carga también permiten que las instancias no estén expuestas directamente a Internet.

    • Grupo de seguridad del balanceador de carga: un grupo EC2 de seguridad de Amazon configurado para permitir el tráfico entrante en el puerto 80. Este recurso permite que HTTP el tráfico de Internet llegue al balanceador de carga. De forma predeterminada, el tráfico no está permitido en otros puertos.

    • Grupo de Auto Scaling: grupo de Auto Scaling configurado para reemplazar una instancia si termina o deja de estar disponible.

    • Bucket de Amazon S3: ubicación de almacenamiento para el código fuente, los registros y otros artefactos que se crean al utilizar Elastic Beanstalk.

    • CloudWatch Alarmas de Amazon: dos CloudWatch alarmas que monitorean la carga de las instancias de su entorno y que se activan si la carga es demasiado alta o demasiado baja. Cuando se activa una alarma, en respuesta, el grupo de Auto Scaling aumenta o reduce los recursos.

    • AWS CloudFormation pila: Elastic AWS CloudFormation Beanstalk se utiliza para lanzar los recursos de su entorno y propagar los cambios de configuración. Los recursos se definen en una plantilla que puede verse en la consola de AWS CloudFormation.

    • Nombre de dominio: un nombre de dominio que se dirige a su aplicación web en el formulario subdomain.region.elasticbeanstalk.com.

      nota

      Para aumentar la seguridad de las aplicaciones de Elastic Beanstalk, el dominio elasticbeanstalk.com está registrado en la lista de sufijos públicos (). PSL Para mayor seguridad, se recomienda que utilice cookies con un prefijo __Host- en caso de que necesite configurar cookies confidenciales en el nombre de dominio predeterminado de sus aplicaciones de Elastic Beanstalk. Esta práctica le ayudará a defender su dominio contra los intentos de falsificación de solicitudes entre sitios (). CSRF Para obtener más información, consulte la página de configuración de cookies en la red de desarrolladores de Mozilla.

  3. Cuando se complete la creación del entorno, utilice el eb opencomando para abrir el entorno URL en el navegador predeterminado.

    ~/nodejs-example-express-elasticache$ eb open

Ahora ha creado un entorno de Elastic Beanstalk para Node.js con una aplicación de ejemplo. Puede actualizarlo con su propia aplicación. Luego, actualizamos la aplicación de ejemplo para que use el marco de Express.

Actualizar la aplicación para que use Express

Actualice la aplicación de ejemplo en el entorno de Elastic Beanstalk para que utilice el marco de Express.

Puede descargar el código fuente final desde nodejs-example-express-elasticache.zip.

Si desea actualizar la aplicación para que use Express

Una vez que haya creado el entorno con una aplicación de ejemplo, puede actualizarlo con su propia aplicación. En este procedimiento, ejecutamos primero los comandos express y npm install para configurar el marco de Express en el directorio de la aplicación.

  1. Ejecute el comando express. Esto genera package.json, app.js y unos directorios.

    ~/nodejs-example-express-elasticache$ express

    Cuando se le pregunte, escriba y si desea continuar.

    nota

    Si el comando express no funciona, es posible que no haya instalado el generador de línea de comandos Express tal y como se describe en la sección Requisitos previos anterior. O bien, puede que sea necesario configurar la ruta del directorio de su máquina local para ejecutar el comando express. Consulte la sección Requisitos previos para conocer los pasos detallados sobre la configuración del entorno de desarrollo, de modo que pueda continuar con este tutorial.

  2. Configure las dependencias locales.

    ~/nodejs-example-express-elasticache$ npm install
  3. (Opcional) Compruebe que el servidor de aplicaciones web se inicie.

    ~/nodejs-example-express-elasticache$ npm start

    Debería ver una salida similar a esta:

    > nodejs@0.0.0 start /home/local/user/node-express > node ./bin/www

    El servidor se ejecuta en el puerto 3000 de forma predeterminada. Para probarlo, ejecútelo curl http://localhost:3000 en otro terminal o abra un navegador en el equipo local e introduzca la URL dirección. http://localhost:3000

    Presione Ctrl+C para detener el servidor.

  4. Cambie el nombre de nodejs-example-express-elasticache/app.js a nodejs-example-express-elasticache/express-app.js.

    ~/nodejs-example-express-elasticache$ mv app.js express-app.js
  5. Actualice la línea var app = express(); en nodejs-example-express-elasticache/express-app.js a la siguiente:

    var app = module.exports = express();
  6. En el equipo local, cree un archivo llamado nodejs-example-express-elasticache/app.js con el siguiente código.

    /** * Module dependencies. */ const express = require('express'), session = require('express-session'), bodyParser = require('body-parser'), methodOverride = require('method-override'), cookieParser = require('cookie-parser'), fs = require('fs'), filename = '/var/nodelist', app = express(); let MemcachedStore = require('connect-memcached')(session); function setup(cacheNodes) { app.use(bodyParser.raw()); app.use(methodOverride()); if (cacheNodes.length > 0) { app.use(cookieParser()); console.log('Using memcached store nodes:'); console.log(cacheNodes); app.use(session({ secret: 'your secret here', resave: false, saveUninitialized: false, store: new MemcachedStore({ 'hosts': cacheNodes }) })); } else { console.log('Not using memcached store.'); app.use(session({ resave: false, saveUninitialized: false, secret: 'your secret here' })); } app.get('/', function (req, resp) { if (req.session.views) { req.session.views++ resp.setHeader('Content-Type', 'text/html') resp.send(`You are session: ${req.session.id}. Views: ${req.session.views}`) } else { req.session.views = 1 resp.send(`You are session: ${req.session.id}. No views yet, refresh the page!`) } }); if (!module.parent) { console.log('Running express without cluster. Listening on port %d', process.env.PORT || 5000) app.listen(process.env.PORT || 5000) } } console.log("Reading elastic cache configuration") // Load elasticache configuration. fs.readFile(filename, 'UTF8', function (err, data) { if (err) throw err; let cacheNodes = [] if (data) { let lines = data.split('\n'); for (let i = 0; i < lines.length; i++) { if (lines[i].length > 0) { cacheNodes.push(lines[i]) } } } setup(cacheNodes) }); module.exports = app;
  7. Reemplace el contenido del archivo nodejs-example-express-elasticache/bin/www por lo siguiente:

    #!/usr/bin/env node /** * Module dependencies. */ const app = require('../app'); const cluster = require('cluster'); const debug = require('debug')('nodejs-example-express-elasticache:server'); const http = require('http'); const workers = {}, count = require('os').cpus().length; function spawn() { const worker = cluster.fork(); workers[worker.pid] = worker; return worker; } /** * Get port from environment and store in Express. */ const port = normalizePort(process.env.PORT || '3000'); app.set('port', port); if (cluster.isMaster) { for (let i = 0; i < count; i++) { spawn(); } // If a worker dies, log it to the console and start another worker. cluster.on('exit', function (worker, code, signal) { console.log('Worker ' + worker.process.pid + ' died.'); cluster.fork(); }); // Log when a worker starts listening cluster.on('listening', function (worker, address) { console.log('Worker started with PID ' + worker.process.pid + '.'); }); } else { /** * Create HTTP server. */ let server = http.createServer(app); /** * Event listener for HTTP server "error" event. */ function onError(error) { if (error.syscall !== 'listen') { throw error; } const bind = typeof port === 'string' ? 'Pipe ' + port : 'Port ' + port; // handle specific listen errors with friendly messages switch (error.code) { case 'EACCES': console.error(bind + ' requires elevated privileges'); process.exit(1); break; case 'EADDRINUSE': console.error(bind + ' is already in use'); process.exit(1); break; default: throw error; } } /** * Event listener for HTTP server "listening" event. */ function onListening() { const addr = server.address(); const bind = typeof addr === 'string' ? 'pipe ' + addr : 'port ' + addr.port; debug('Listening on ' + bind); } /** * Listen on provided port, on all network interfaces. */ server.listen(port); server.on('error', onError); server.on('listening', onListening); } /** * Normalize a port into a number, string, or false. */ function normalizePort(val) { const port = parseInt(val, 10); if (isNaN(port)) { // named pipe return val; } if (port >= 0) { // port number return port; } return false; }
  8. Implemente los cambios en su entorno Elastic Beanstalk con el comando eb deploy.

    ~/nodejs-example-express-elasticache$ eb deploy
  9. Su entorno se actualizará al cabo de unos minutos. Una vez que el entorno esté verde y listo, actualícelo URL para comprobar que ha funcionado. Debería aparecer una página web que diga “Welcome to Express”.

Puede acceder a los registros de EC2 las instancias que ejecutan la aplicación. Para obtener instrucciones acerca del acceso a los logs, consulte Visualización de los registros de EC2 las instancias de Amazon en su entorno de Elastic Beanstalk.

A continuación, vamos a actualizar la aplicación Express para usar Amazon ElastiCache.

Para actualizar tu aplicación Express para usar Amazon ElastiCache
  1. En su equipo local, cree un directorio .ebextensions en el directorio de nivel superior del paquete de código fuente. En este ejemplo, usaremos nodejs-example-express-elasticache/.ebextensions.

  2. Cree un archivo de configuración nodejs-example-express-elasticache/.ebextensions/elasticache-iam-with-script.config con el siguiente fragmento. Para obtener más información sobre el archivo de configuración, consulte Node.js espacio de nombres de configuración. Esto crea un IAM usuario con los permisos necesarios para descubrir los nodos de elasticache y escribe en un archivo cada vez que cambia la caché. También puede copiar el archivo desde nodejs-example-express-elasticache un archivo.zip. Para obtener más información sobre las ElastiCache propiedades, consulteEjemplo: ElastiCache.

    nota

    YAMLse basa en una hendidura coherente. Utilice el mismo nivel de sangría cuando sustituya el contenido en el archivo de configuración de ejemplo y asegúrese de que el editor de texto utiliza espacios para la sangría, no tabuladores.

    Resources: MyCacheSecurityGroup: Type: 'AWS::EC2::SecurityGroup' Properties: GroupDescription: "Lock cache down to webserver access only" SecurityGroupIngress: - IpProtocol: tcp FromPort: Fn::GetOptionSetting: OptionName: CachePort DefaultValue: 11211 ToPort: Fn::GetOptionSetting: OptionName: CachePort DefaultValue: 11211 SourceSecurityGroupName: Ref: AWSEBSecurityGroup MyElastiCache: Type: 'AWS::ElastiCache::CacheCluster' Properties: CacheNodeType: Fn::GetOptionSetting: OptionName: CacheNodeType DefaultValue: cache.t2.micro NumCacheNodes: Fn::GetOptionSetting: OptionName: NumCacheNodes DefaultValue: 1 Engine: Fn::GetOptionSetting: OptionName: Engine DefaultValue: redis VpcSecurityGroupIds: - Fn::GetAtt: - MyCacheSecurityGroup - GroupId AWSEBAutoScalingGroup : Metadata : ElastiCacheConfig : CacheName : Ref : MyElastiCache CacheSize : Fn::GetOptionSetting: OptionName : NumCacheNodes DefaultValue: 1 WebServerUser : Type : AWS::IAM::User Properties : Path : "/" Policies: - PolicyName: root PolicyDocument : Statement : - Effect : Allow Action : - cloudformation:DescribeStackResource - cloudformation:ListStackResources - elasticache:DescribeCacheClusters Resource : "*" WebServerKeys : Type : AWS::IAM::AccessKey Properties : UserName : Ref: WebServerUser Outputs: WebsiteURL: Description: sample output only here to show inline string function parsing Value: | http://`{ "Fn::GetAtt" : [ "AWSEBLoadBalancer", "DNSName" ] }` MyElastiCacheName: Description: Name of the elasticache Value: Ref : MyElastiCache NumCacheNodes: Description: Number of cache nodes in MyElastiCache Value: Fn::GetOptionSetting: OptionName : NumCacheNodes DefaultValue: 1 files: "/etc/cfn/cfn-credentials" : content : | AWSAccessKeyId=`{ "Ref" : "WebServerKeys" }` AWSSecretKey=`{ "Fn::GetAtt" : ["WebServerKeys", "SecretAccessKey"] }` mode : "000400" owner : root group : root "/etc/cfn/get-cache-nodes" : content : | # Define environment variables for command line tools export AWS_ELASTICACHE_HOME="/home/ec2-user/elasticache/$(ls /home/ec2-user/elasticache/)" export AWS_CLOUDFORMATION_HOME=/opt/aws/apitools/cfn export PATH=$AWS_CLOUDFORMATION_HOME/bin:$AWS_ELASTICACHE_HOME/bin:$PATH export AWS_CREDENTIAL_FILE=/etc/cfn/cfn-credentials export JAVA_HOME=/usr/lib/jvm/jre # Grab the Cache node names and configure the PHP page aws cloudformation list-stack-resources --stack `{ "Ref" : "AWS::StackName" }` --region `{ "Ref" : "AWS::Region" }` --output text | grep MyElastiCache | awk '{print $4}' | xargs -I {} aws elasticache describe-cache-clusters --cache-cluster-id {} --region `{ "Ref" : "AWS::Region" }` --show-cache-node-info --output text | grep '^ENDPOINT' | awk '{print $2 ":" $3}' > `{ "Fn::GetOptionSetting" : { "OptionName" : "NodeListPath", "DefaultValue" : "/var/www/html/nodelist" } }` mode : "000500" owner : root group : root "/etc/cfn/hooks.d/cfn-cache-change.conf" : "content": | [cfn-cache-size-change] triggers=post.update path=Resources.AWSEBAutoScalingGroup.Metadata.ElastiCacheConfig action=/etc/cfn/get-cache-nodes runas=root sources : "/home/ec2-user/elasticache" : "https://elasticache-downloads.s3.amazonaws.com/AmazonElastiCacheCli-latest.zip" commands: make-elasticache-executable: command: chmod -R ugo+x /home/ec2-user/elasticache/*/bin/* packages : "yum" : "aws-apitools-cfn" : [] container_commands: initial_cache_nodes: command: /etc/cfn/get-cache-nodes
  3. En su equipo local, cree un archivo de configuración nodejs-example-express-elasticache/.ebextensions/elasticache_settings.config con el siguiente fragmento de código para configurarlo. ElastiCache

    option_settings: "aws:elasticbeanstalk:customoption": CacheNodeType: cache.t2.micro NumCacheNodes: 1 Engine: memcached NodeListPath: /var/nodelist
  4. En el equipo local,sustituya nodejs-example-express-elasticache/express-app.js con el siguiente fragmento. Este archivo lee la lista de nodos del disco (/var/nodelist) y configura Express para que utilice memcached como un almacén de sesiones si los nodos están presentes. Su archivo debería tener el siguiente aspecto.

    /** * Module dependencies. */ var express = require('express'), session = require('express-session'), bodyParser = require('body-parser'), methodOverride = require('method-override'), cookieParser = require('cookie-parser'), fs = require('fs'), filename = '/var/nodelist', app = module.exports = express(); var MemcachedStore = require('connect-memcached')(session); function setup(cacheNodes) { app.use(bodyParser.raw()); app.use(methodOverride()); if (cacheNodes) { app.use(cookieParser()); console.log('Using memcached store nodes:'); console.log(cacheNodes); app.use(session({ secret: 'your secret here', resave: false, saveUninitialized: false, store: new MemcachedStore({'hosts': cacheNodes}) })); } else { console.log('Not using memcached store.'); app.use(cookieParser('your secret here')); app.use(session()); } app.get('/', function(req, resp){ if (req.session.views) { req.session.views++ resp.setHeader('Content-Type', 'text/html') resp.write('Views: ' + req.session.views) resp.end() } else { req.session.views = 1 resp.end('Refresh the page!') } }); if (!module.parent) { console.log('Running express without cluster.'); app.listen(process.env.PORT || 5000); } } // Load elasticache configuration. fs.readFile(filename, 'UTF8', function(err, data) { if (err) throw err; var cacheNodes = []; if (data) { var lines = data.split('\n'); for (var i = 0 ; i < lines.length ; i++) { if (lines[i].length > 0) { cacheNodes.push(lines[i]); } } } setup(cacheNodes); });
  5. En el equipo local, actualice package.json con el siguiente contenido:

    "dependencies": { "cookie-parser": "~1.4.4", "debug": "~2.6.9", "express": "~4.16.1", "http-errors": "~1.6.3", "jade": "~1.11.0", "morgan": "~1.9.1", "connect-memcached": "*", "express-session": "*", "body-parser": "*", "method-override": "*" }
  6. Ejecute npm install.

    ~/nodejs-example-express-elasticache$ npm install
  7. Implemente la aplicación actualizada.

    ~/nodejs-example-express-elasticache$ eb deploy
  8. Su entorno se actualizará al cabo de unos minutos. Una vez que su entorno esté listo, verifique que el código ha funcionado.

    1. Consulta la CloudWatch consola de Amazon para ver tus ElastiCache estadísticas. Para ver tus ElastiCache métricas, selecciona Métricas en el panel izquierdo y, a continuación, busca CurrItems. Seleccione ElastiCache > Métricas del nodo de caché y, a continuación, seleccione su nodo de caché para ver el número de elementos de la caché.

      CloudWatch dashboard showing CurrItems metric for an ElastiCache node over time.
      nota

      Asegúrese de buscar en la misma región en la que ha implementado su aplicación.

      Si copias y pegas la aplicación URL en otro navegador web y actualizas la página, el CurrItem recuento debería aumentar al cabo de 5 minutos.

    2. Tome una instantánea de los registros.. Para obtener más información acerca de la recuperación de registros, consulte Visualización de los registros de EC2 las instancias de Amazon en su entorno de Elastic Beanstalk.

    3. Compruebe el archivo /var/log/nodejs/nodejs.log en el paquete del registro. Debería ver algo similar a lo siguiente:

      Using memcached store nodes: [ 'aws-my-1oys9co8zt1uo.1iwtrn.0001.use1.cache.amazonaws.com:11211' ]

Limpieza

Si ya no desea ejecutar la aplicación, puede limpiar los recursos terminando el entorno y eliminando la aplicación.

Utilice el comando eb terminate para finalizar el entorno y el comando eb delete para eliminar la aplicación.

Para terminar su entorno

En el directorio en el que creó el repositorio local, ejecute eb terminate.

$ eb terminate

Este proceso puede tardar unos minutos. Elastic Beanstalk muestra un mensaje cuando el entorno termina correctamente.