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á.
Implantar uma aplicação Node.js Express com clustering no Elastic Beanstalk
Este tutorial apresenta a implantação de uma aplicação demonstrativa no Elastic Beanstalk usando a Interface de Linhas de Comando do Elastic Beanstalk (CLI do EB) e, depois, atualizando a aplicação para usar a framework Express
nota
Este exemplo cria recursos da AWS, pelos quais você poderia ser cobrado. Para obter mais informações sobre os preços da AWS, consulte https://aws.amazon.com/pricing/
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 Elastic Beanstalk Command Line Interface (EB CLI)
Para obter detalhes sobre como instalar os três primeiros componentes listados e configurar seu ambiente de desenvolvimento local, consulte Configurar seu ambiente de desenvolvimento Node.js para o Elastic Beanstalk. Para este tutorial, você não precisa instalar o AWS SDK para Node.js, que também é mencionado no tópico referenciado.
Para obter detalhes sobre como instalar e configurar a EB CLI, consulte Instalar 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 do Elastic Beanstalk (EB CLI).
Para configurar um repositório EB CLI para seu aplicativo e criar um ambiente Elastic Beanstalk executando a plataforma Node.js
-
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. -
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:
-
Instância do EC2: uma máquina virtual do Amazon Elastic Compute Cloud (Amazon EC2) configurada para executar aplicações Web na plataforma escolhida.
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 o NGINX como um proxy reverso que fica na frente da aplicação Web, encaminha solicitações para ela, atende ativos estáticos e gera logs de acesso e de erro.
-
Grupo de segurança de instância: um grupo de segurança do Amazon EC2 configurado para permitir tráfego de entrada na porta 80. Esse recurso permite que o tráfego HTTP do load balancer chegue à instância do EC2 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 de segurança do Amazon EC2 configurado para permitir tráfego de entrada na porta 80. Esse recurso permite que o tráfego HTTP da Internet acesse o load balancer. 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.
-
Alarmes do Amazon CloudWatch: dois alarmes do CloudWatch que monitoram a carga nas instâncias do ambiente e são acionados quando ela está muito alta ou muito baixa. Quando um alarme é acionado, o seu grupo de Auto Scaling pode aumentar ou diminuir.
-
Pilha do AWS CloudFormation: o Elastic Beanstalk usa o AWS CloudFormation para iniciar os recursos em seu ambiente e propagar 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 encaminha para a aplicação Web no formato
subdomínio
.região
.elasticbeanstalk.com.Segurança de domínios
Para aumentar a segurança de suas aplicações do Elastic Beanstalk, o domínio elasticbeanstalk.com é registrado na Lista Pública de Sufixos (PSL)
. Se precisar definir cookies confidenciais no nome de domínio padrão para suas aplicações Elastic Beanstalk, recomendamos usar cookies com um prefixo
__Host-
para maior segurança. Essa prática defende seu domínio contra tentativas de falsificação de solicitação entre sites (CSRF). Para obter mais informações, consulte a página Set-Cookiena Mozilla Developer Network.
-
-
Quando a criação do ambiente for concluída, use o comando eb open para abrir o URL do ambiente 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 fazer download do código-fonte final de 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.
-
Execute o comando
express
. Isso gerapackage.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.
-
Configure as dependências locais.
~/nodejs-example-express-elasticache$
npm install
-
(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 insira o endereço URLhttp://localhost:3000
.Pressione Ctrl+C para interromper o servidor.
-
Renomeie
nodejs-example-express-elasticache/app.js
paranodejs-example-express-elasticache/express-app.js
.~/nodejs-example-express-elasticache$
mv
app.js express-app.js
-
Atualize a linha
var app = express();
nonodejs-example-express-elasticache/express-app.js
da seguinte forma:var app = module.exports = express();
-
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;
-
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; }
-
Implante as alterações em seu ambiente Elastic Beanstalk com o comando eb deploy.
~/nodejs-example-express-elasticache$
eb deploy
-
O ambiente será atualizado após alguns minutos. Assim que 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 logs das instâncias EC2 que executam a aplicação. 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.
Depois, atualizaremos o aplicativo Express para usar o Amazon ElastiCache.
Para atualizar seu aplicativo Express para usar o Amazon ElastiCache
-
No computador local, crie um diretório
.ebextensions
no diretório de nível superior do seu pacote de origem. Neste exemplo, usamosnodejs-example-express-elasticache/.ebextensions
. -
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 Namespace de configuração do Node.js. Isso cria um usuário do IAM com as permissões necessárias para descobrir os nós do ElastiCache e grava em um arquivo sempre que o cache muda. Também é possível copiar o arquivo de nodejs-example-express-elasticache.zip. Para obter mais informações sobre as propriedades do ElastiCache, consulte Exemplo: ElastiCache.nota
YAML depende de um recuo 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
-
No computador local, crie um arquivo de configuração
nodejs-example-express-elasticache/.ebextensions/elasticache_settings.config
com o seguinte snippet para configurar o ElastiCache.option_settings: "aws:elasticbeanstalk:customoption": CacheNodeType: cache.t2.micro NumCacheNodes: 1 Engine: memcached NodeListPath: /var/nodelist
-
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 usarmemcached
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); });
-
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": "*" }
-
Executar npm install.
~/nodejs-example-express-elasticache$
npm install
-
Implante o aplicativo atualizado.
~/nodejs-example-express-elasticache$
eb deploy
-
O ambiente será atualizado após alguns minutos. Depois que seu ambiente estiver verde e pronto, verifique se o código funcionou.
-
Verifique o console do Amazon CloudWatch
para visualizar as métricas do ElastiCache. Para visualizar as métricas do ElastiCache, selecione Metrics (Métricas) no painel esquerdo e pesquise por CurrItems. Selecione ElastiCache > Cache Node Metrics (ElastiCache > Métricas do nó de cache) e selecione o nó de cache para visualizar o número de itens no cache. nota
Verifique se você está visualizando a mesma região na qual implantou seu aplicativo.
Se você copiar e colar o URL do aplicativo em outro navegador da Web e atualizar a página, deverá ver a contagem do CurrItem subir após 5 minutos.
-
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.
-
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.