Implantação de um aplicativo Node.js Express com clustering no Elastic Beanstalk - AWS Elastic Beanstalk

As traduções são geradas por tradução automática. Em caso de conflito entre o conteúdo da tradução e da versão original em inglês, a versão em inglês prevalecerá.

Implantação de um aplicativo Node.js Express com clustering no Elastic Beanstalk

Este tutorial mostra como implantar um aplicativo de amostra no Elastic Beanstalk usando a interface de CLI linha de comando (EB) do Elastic Beanstalk e, em seguida, atualizando o aplicativo para usar a estrutura Express, a Amazon e o clustering. ElastiCache O clustering aprimora a alta disponibilidade, a performance e a segurança do seu aplicativo web. Para saber mais sobre a Amazon ElastiCache, acesse O que é a Amazon ElastiCache (Memcached)? no Guia do usuário da Amazon ElastiCache (Memcached).

nota

Este exemplo cria AWS recursos, pelos quais você pode ser cobrado. Para obter mais informações sobre AWS preços, consultehttps://aws.amazon.com/pricing/. Alguns serviços fazem parte do nível de uso AWS gratuito. Se for um cliente novo, você pode testar esses serviços gratuitamente. Consulte https://aws.amazon.com/free/ Para mais informações.

Pré-requisitos

Este tutorial requer os seguintes pré-requisitos:

  • Os tempos de execução do Node.js

  • O software gerenciador de pacotes Node.js padrão, npm

  • O gerador de linha de comando Express

  • A interface de linha de comando (EB) do Elastic Beanstalk CLI

Para obter detalhes sobre como instalar os três primeiros componentes listados e configurar seu ambiente de desenvolvimento local, consulte Configurando seu ambiente de desenvolvimento Node.js para o Elastic Beanstalk. Para este tutorial, você não precisa instalar o AWS SDK for Node.js, que também é mencionado no tópico referenciado.

Para obter detalhes sobre a instalação e configuração do EBCLI, consulte Instale a interface de linha de comando do Elastic Beanstalk e. Configurar a EB CLI

Criar um ambiente do Elastic Beanstalk

Seu diretório de aplicativos

Este tutorial usa um diretório chamado nodejs-example-express-elasticache para o pacote de origem do aplicativo. Crie o diretório nodejs-example-express-elasticache para este tutorial.

~$ mkdir nodejs-example-express-elasticache
nota

Cada tutorial neste capítulo usa seu próprio diretório para o pacote de origem do aplicativo. O nome do diretório corresponde ao nome do aplicativo de amostra usado pelo tutorial.

Altere seu diretório de trabalho atual para nodejs-example-express-elasticache.

~$ cd nodejs-example-express-elasticache

Agora, vamos configurar um ambiente do Elastic Beanstalk executando a plataforma Node.js e o aplicativo de amostra. Usaremos a interface de linha de comando (EB) do Elastic Beanstalk. CLI

Para configurar um CLI repositório EB para seu aplicativo e criar um ambiente do Elastic Beanstalk executando a plataforma Node.js
  1. Crie um repositório com o comando eb init.

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

    Esse comando cria um arquivo de configuração em uma pasta chamada .elasticbeanstalk que especifica as configurações para a criação de ambientes para a aplicação e cria uma aplicação do Elastic Beanstalk com nome baseado na pasta atual.

  2. Crie um ambiente executando um aplicativo de exemplo com o comando eb create.

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

    Esse comando cria um ambiente com balanceamento de carga com as configurações padrão da plataforma do Node.js e os seguintes recursos:

    • EC2instância — Uma máquina virtual Amazon Elastic Compute Cloud (AmazonEC2) configurada para executar aplicativos web na plataforma que você escolher.

      Cada plataforma executa um conjunto específico de software, arquivos de configuração e scripts para oferecer suporte a uma versão de linguagem, framework, contêiner da web específicos ou a uma combinação deles. A maioria das plataformas usa o Apache ou NGINX como um proxy reverso que fica na frente do seu aplicativo web, encaminha solicitações para ele, fornece ativos estáticos e gera registros de acesso e erro.

    • Grupo de segurança da instância — Um grupo EC2 de segurança da Amazon configurado para permitir tráfego de entrada na porta 80. Esse recurso permite que o HTTP tráfego do balanceador de carga chegue à EC2 instância que executa seu aplicativo web. Por padrão, o tráfego não é permitido em outras portas.

    • Balanceador de carga: um balanceador de carga do Elastic Load Balancing configurado para distribuir solicitações para as instâncias que executam a aplicação. Um load balancer também elimina a necessidade de expor suas instâncias diretamente à Internet.

    • Grupo de segurança do balanceador de carga — Um grupo EC2 de segurança da Amazon configurado para permitir tráfego de entrada na porta 80. Esse recurso permite que o HTTP tráfego da Internet chegue ao balanceador de carga. Por padrão, o tráfego não é permitido em outras portas.

    • Grupo de Auto Scaling: grupo de Auto Scaling configurado para substituir uma instância se ela for encerrada ou ficar indisponível.

    • Bucket do Amazon S3: um local de armazenamento do seu código-fonte, logs e outros artefatos criados quando o Elastic Beanstalk é utilizado.

    • CloudWatch Alarmes da Amazon — Dois CloudWatch alarmes que monitoram a carga nas instâncias em seu ambiente e que são acionados se a carga for muito alta ou muito baixa. Quando um alarme é acionado, o seu grupo de Auto Scaling pode aumentar ou diminuir.

    • AWS CloudFormation stack — O Elastic AWS CloudFormation Beanstalk usa para lançar os recursos em seu ambiente e propagar as alterações de configuração. Os recursos são definidos em um modelo que você pode visualizar no console do AWS CloudFormation.

    • Nome de domínio — Um nome de domínio que direciona para seu aplicativo da web no formulário subdomain.region.elasticbeanstalk.com.

      nota

      Para aumentar a segurança de seus aplicativos do Elastic Beanstalk, o domínio elasticbeanstalk.com é registrado na Lista pública de sufixos (). PSL Para maior segurança, recomendamos que você use cookies com um prefixo __Host- se precisar definir cookies confidenciais no nome de domínio padrão para suas aplicações do Elastic Beanstalk. Essa prática ajudará a defender seu domínio contra tentativas de falsificação de solicitações entre sites ()CSRF. Para obter mais informações, consulte a página Set-Cookie na Mozilla Developer Network.

  3. Quando a criação do ambiente for concluída, use o eb opencomando para abrir o ambiente URL no navegador padrão.

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

Agora você criou um ambiente Node.js Elastic Beanstalk com um aplicativo de amostra. Você pode atualizá-lo com seu próprio aplicativo. Em seguida, atualizamos o aplicativo de exemplo para usar a framework do Express.

Atualize o aplicativo para usar o Express

Atualize a aplicação demonstrativa no ambiente do Elastic Beanstalk para usar a framework do Express.

Você pode baixar o código-fonte final em nodejs-example-express-elasticache.zip.

Para atualizar seu aplicativo para usar o Express

Depois de criar um ambiente com um aplicativo de amostra, você pode atualizá-lo com seu próprio aplicativo. Neste procedimento, primeiro executamos os comandos npm install eexpress para configurar a estrutura Express no diretório do seu aplicativo.

  1. Execute o comando express. Isso gera package.json, app.js e alguns diretórios.

    ~/nodejs-example-express-elasticache$ express

    Quando solicitado, digite y se você deseja continuar.

    nota

    Se o comando express não funcionar, talvez você não tenha instalado o gerador de linha de comando Express conforme descrito na seção Pré-requisitos anterior. Ou talvez seja necessário configurar a configuração do caminho do diretório para sua máquina local para executar o comando express. Consulte a seção Pré-requisitos para obter etapas detalhadas sobre como configurar seu ambiente de desenvolvimento, para que você possa continuar com este tutorial.

  2. Configure as dependências locais.

    ~/nodejs-example-express-elasticache$ npm install
  3. (Opcional) Verifique a inicialização do servidor do aplicativo da web.

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

    Você deve ver saída semelhante a:

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

    Por padrão, o servidor é executado na porta 3000. Para testá-lo, execute curl http://localhost:3000 em outro terminal ou abra um navegador no computador local e digite o URL endereçohttp://localhost:3000.

    Pressione Ctrl+C para interromper o servidor.

  4. Renomeie nodejs-example-express-elasticache/app.js para nodejs-example-express-elasticache/express-app.js.

    ~/nodejs-example-express-elasticache$ mv app.js express-app.js
  5. Atualize a linha var app = express(); no nodejs-example-express-elasticache/express-app.js da seguinte forma:

    var app = module.exports = express();
  6. No seu computador local, crie um arquivo chamado nodejs-example-express-elasticache/app.js com o seguinte 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. Substitua o conteúdo do arquivo nodejs-example-express-elasticache/bin/www com o seguinte:

    #!/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. Implante as alterações em seu ambiente Elastic Beanstalk com o comando eb deploy.

    ~/nodejs-example-express-elasticache$ eb deploy
  9. O ambiente será atualizado após alguns minutos. Quando o ambiente estiver verde e pronto, atualize o URL para verificar se funcionou. Você deverá ver uma página da web dizendo: "Welcome to Express".

Você pode acessar os registros das EC2 instâncias que executam seu aplicativo. Para obter instruções sobre como acessar os logs, consulte Visualização de registros de EC2 instâncias da Amazon em seu ambiente do Elastic Beanstalk.

Em seguida, vamos atualizar o aplicativo Express para usar a Amazon ElastiCache.

Para atualizar seu aplicativo Express para usar a Amazon ElastiCache
  1. No computador local, crie um diretório .ebextensions no diretório de nível superior do seu pacote de origem. Neste exemplo, usamos nodejs-example-express-elasticache/.ebextensions.

  2. Crie um arquivo de configuração nodejs-example-express-elasticache/.ebextensions/elasticache-iam-with-script.config com o seguinte snippet. Para obter mais informações sobre o arquivo de configuração, consulte Node.js namespace de configuração. Isso cria um IAM usuário com as permissões necessárias para descobrir os nós do elasticache e grava em um arquivo sempre que o cache é alterado. Você também pode copiar o arquivo do nodejs-example-express-elasticachearquivo.zip. Para obter mais informações sobre as ElastiCache propriedades, consulteExemplo: ElastiCache.

    nota

    YAMLdepende de uma indentação consistente. Compare o nível de recuo ao substituir o conteúdo em um arquivo de configuração de exemplo e se confira se o editor de texto usa espaços, e não caracteres de tabulação, como recuo.

    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. No seu computador local, crie um arquivo de configuração nodejs-example-express-elasticache/.ebextensions/elasticache_settings.config com o seguinte trecho para configurar. ElastiCache

    option_settings: "aws:elasticbeanstalk:customoption": CacheNodeType: cache.t2.micro NumCacheNodes: 1 Engine: memcached NodeListPath: /var/nodelist
  4. No seu computador local, substitua nodejs-example-express-elasticache/express-app.js pelo seguinte snippet. Esse arquivo lê a lista de nós do disco (/var/nodelist) e configura o Express para usar memcached como armazenamento de sessão se os nós estiverem presentes. Seu arquivo deve ter uma aparência semelhante à seguinte:

    /** * 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. No computador local, atualize package.json com o seguinte conteúdo:

    "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. Executar npm install.

    ~/nodejs-example-express-elasticache$ npm install
  7. Implante o aplicativo atualizado.

    ~/nodejs-example-express-elasticache$ eb deploy
  8. O ambiente será atualizado após alguns minutos. Depois que seu ambiente estiver verde e pronto, verifique se o código funcionou.

    1. Verifique o CloudWatch console da Amazon para ver suas ElastiCache métricas. Para visualizar suas ElastiCache métricas, selecione Métricas no painel esquerdo e, em seguida, pesquise por CurrItems. Selecione ElastiCache > Métricas do nó de cache e, em seguida, selecione seu nó de cache para visualizar o número de itens no cache.

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

      Verifique se você está visualizando a mesma região na qual implantou seu aplicativo.

      Se você copiar e colar seu aplicativo URL em outro navegador da Web e atualizar a página, verá sua CurrItem contagem aumentar após 5 minutos.

    2. Faça um snapshot dos logs. Para obter mais informações sobre recuperação de logs, consulte Visualização de registros de EC2 instâncias da Amazon em seu ambiente do Elastic Beanstalk.

    3. Verifique o arquivo /var/log/nodejs/nodejs.log no pacote de logs. Você deverá ver algo semelhante a:

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

Limpeza

Se não quiser mais executar seu aplicativo, você pode limpar encerrando seu ambiente e excluindo o aplicativo.

Use o comando eb terminate para encerrar o seu ambiente e o comando eb delete para excluir o seu aplicativo.

Para encerrar seu ambiente

No diretório onde você criou o repositório local, execute eb terminate.

$ eb terminate

Esse processo pode levar alguns minutos. O Elastic Beanstalk exibirá uma mensagem quando o ambiente foi encerrado com êxito.