Implementación de una aplicación 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 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 interfaz de línea de comandos de Elastic Beanstalk (EB CLI) y, a continuación, se actualiza la aplicación para que utilice el marco Express, Amazon y los 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 para Memcached? en la Guía del usuario ElastiCache de Amazon for 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

  • La interfaz de línea de comando de Elastic Beanstalk (CLI de EB)

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 este tutorial, no es necesario instalar el AWS SDK para Node.js, que también se menciona en el tema al que se hace referencia.

Para obtener detalles sobre la instalación y configuración de la CLI de EB, consulte Instalación de la CLI de EB y Configuració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. Se usará la interfaz de línea de comandos de Elastic Beanstalk (CLI de EB)

Para configurar un repositorio en la CLI de EB para la 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:

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

      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 Apache o nginx como un proxy inverso que se sitúa delante de la aplicación web, reenvía las solicitudes a esta, administra los recursos estáticos y genera registros de acceso y errores.

    • Instance security group (Grupo de seguridad de la instancia): grupo de seguridad de Amazon EC2 configurado para permitir el tráfico entrante en el puerto 80. Este recurso permite que el tráfico HTTP procedente del balanceador de carga llegue a la instancia EC2 en la que se ejecuta la 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: grupo de seguridad de Amazon EC2 configurado para permitir el tráfico entrante en el puerto 80. Este recurso permite que el tráfico HTTP procedente 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 deAWS CloudFormation.

    • Nombre de dominio: nombre de dominio que direcciona el tráfico a la aplicación web con el formato subdominio.región.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 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 comando eb open para abrir la URL del entorno 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 nodejs-example-express-elasticachecódigo fuente final desde .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, ejecute curl http://localhost:3000 en otro terminal o abra un navegador en el equipo local e ingrese el http://localhost:3000 de la dirección URL.

    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é listo, actualice la dirección URL para verificar que ha funcionado. Debería aparecer una página web que diga “Welcome to Express”.

Puede obtener acceso a los logs de las instancias EC2 que ejecutan la aplicación. Para obtener instrucciones acerca del acceso a los logs, consulte Visualización de registros de instancias de Amazon EC2 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 Espacio de nombres de configuración de Node.js. Se crea un usuario de IAM con los permisos necesarios para descubrir los nodos de elasticache y se escribe en un archivo siempre que cambia la caché. También puedes copiar el archivo desde un nodejs-example-express-elasticachearchivo.zip. Para obtener más información sobre las ElastiCache propiedades, consulteEjemplo: ElastiCache.

    nota

    YAML usa la sangría uniforme. 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é.

      nota

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

      Si copias y pegas la URL de tu aplicación 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 registros de instancias de Amazon EC2 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.