将具有集群功能的 Express 应用程序部署到 Elastic Beanstalk
本教程向您演示了如何使用 Elastic Beanstalk 命令行界面 (EB CLI) 将示例应用程序部署到 Elastic Beanstalk,然后更新该应用程序以使用 Express
本示例将创建Amazon资源,您可能要为其付费。有关 Amazon 定价的更多信息,请参阅 http://www.amazonaws.cn/pricing/
先决条件
本教程要求使用 Node.js 语言、其程序包管理器 NPM 以及 Express Web 应用程序框架。有关安装这些组件和设置本地开发环境的详细信息,请参阅设置 Node.js 开发环境。
在本教程中,您不需要安装适用于 Node.js 的 Amazon,这在 设置 Node.js 开发环境 中也有提到。
本教程还需要 Elastic Beanstalk 命令行界面 (EB CLI)。有关安装和配置 EB CLI 的详细信息,请参阅 安装 EB CLI 和 配置 EB CLI。
创建 Elastic Beanstalk 环境
为您的应用程序配置 EB CLI 存储库,并创建运行 Node.js 平台的 Elastic Beanstalk 环境。
-
使用 eb init 命令创建存储库。
~/node-express$
eb init --platform node.js --region us-east-2
Application node-express has been created.此命令在名为
.elasticbeanstalk
的文件夹中创建配置文件,该配置文件指定用于为您的应用程序创建环境的设置;并创建以当前文件夹命名的 Elastic Beanstalk 应用程序。 -
使用 eb create 命令创建运行示例应用程序的环境。
~/node-express$
eb create --sample node-express-env
此命令使用 Node.js 平台的默认设置以及以下资源来创建负载均衡环境:
-
EC2 实例 – 配置为在您选择的平台上运行 Web 应用程序的 Amazon Elastic Compute Cloud(Amazon EC2)虚拟机。
各平台运行一组特定软件、配置文件和脚本以支持特定的语言版本、框架、Web 容器或其组合。大多数平台使用 Apache 或 NGINX 作为 Web 应用程序前的反向代理,向其转发请求、提供静态资产以及生成访问和错误日志。
-
实例安全组 - 配置为允许端口 80 上的入站流量的 Amazon EC2 安全组。通过此资源,HTTP 流量可以从负载均衡器到达运行您的 Web 应用程序的 EC2 实例。默认情况下,其他端口不允许流量进入。
-
负载均衡器 – 配置为向运行您的应用程序的实例分配请求的 Elastic Load Balancing 负载均衡器。负载均衡器还使您无需将实例直接公开在 Internet 上。
-
负载均衡器安全组 – 配置为允许端口 80 上的入站流量的 Amazon EC2 安全组。利用此资源,HTTP 流量可从 Internet 到达负载均衡器。默认情况下,其他端口不允许流量进入。
-
Auto Scaling 组 – 配置为在实例终止或不可用时替换实例的 Auto Scaling 组。
-
Amazon S3 存储桶 – 使用 Elastic Beanstalk 时创建的源代码、日志和其他构件的存储位置。
-
Amazon CloudWatch 警报 – 用于监控环境中的实例负载的两个 CloudWatch 警报,它们将在负载过高或过低时触发。警报触发后,您的 Auto Scaling 组会扩展或收缩以进行响应。
-
Amazon CloudFormation 堆栈 – Elastic Beanstalk 使用 Amazon CloudFormation 启动您环境中的资源并传播配置更改。这些资源在您可通过 Amazon CloudFormation 控制台
查看的模板中定义。 -
域名 – 一个域名,它以下面的形式路由到您的 Web 应用程序:
subdomain
.region
.elasticbeanstalk.com。
-
-
当环境创建完成后,使用 eb open 命令在默认浏览器中打开环境 URL。
~/node-express$
eb open
更新应用程序
更新 Elastic Beanstalk 环境中的示例应用程序以使用 Express 框架。
您可以从 nodejs-example-express-elasticache.zip 下载最终源代码。
先决条件开发环境设置可实现 node-express
文件夹中的 Express 项目结构。如果尚未生成 Express 项目,请运行以下命令。有关更多信息,请参阅 安装 Express。
~/node-express$ express && npm install
更新您的应用程序以使用 Express
-
将
node-express/app.js
重命名为node-express/express-app.js
.node-express$ mv app.js express-app.js
-
将
var app = express();
中的行node-express/express-app.js
更新为以下内容:var app = module.exports = express();
-
在本地计算机上,使用以下代码创建一个名为
node-express/app.js
的文件。var cluster = require('cluster'), app = require('./express-app'); var workers = {}, count = require('os').cpus().length; function spawn(){ var worker = cluster.fork(); workers[worker.pid] = worker; return worker; } if (cluster.isMaster) { for (var i = 0; i < count; i++) { spawn(); } cluster.on('death', function(worker) { console.log('worker ' + worker.pid + ' died. spawning a new process...'); delete workers[worker.pid]; spawn(); }); } else { app.listen(process.env.PORT || 5000); }
-
部署更新的应用程序。
node-express$ eb deploy
-
您的环境将在几分钟后进行更新。在环境变为绿色并准备就绪后,刷新 URL 以验证环境是否工作。您应看到一个显示“欢迎使用 Express”的网页。
您可访问运行应用程序的 EC2 实例的日志。有关访问日志的说明,请参阅查看您的 Elastic Beanstalk 环境中的 Amazon EC2 实例的日志。
接下来,让我们更新 Express 应用程序以使用 Amazon ElastiCache。
更新 Express 应用程序以使用 Amazon ElastiCache
-
在本地计算机上的源包顶级目录中,创建
.ebextensions
目录。在此示例中,我们使用的是node-express/.ebextensions
。 -
使用以下代码段创建配置文件
node-express/.ebextensions/elasticache-iam-with-script.config
。有关配置文件的更多信息,请参阅Node.js 配置命名空间。此配置文件会创建一个 IAM 用户(该用户拥有发现 ElastiCache 节点所需的权限),只要缓存发生变化就向某个文件写入数据。您也可以从 nodejs-example-express-elasticache.zip 复制该文件。有关 ElastiCache 属性的更多信息,请参阅“示例:ElastiCache”。注意 YAML 依赖一致的缩进。当替换示例配置文件中的内容时,应匹配缩进级别,并且确保您的文本编辑器使用空格而不是字符来进行缩进。
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
-
在本地计算机上,使用以下代码段创建配置文件
node-express/.ebextensions/elasticache_settings.config
以配置 ElastiCache。option_settings: "aws:elasticbeanstalk:customoption": CacheNodeType: cache.t2.micro NumCacheNodes: 1 Engine: memcached NodeListPath: /var/nodelist
-
在本地计算机上,使用以下代码段替换
node-express/express-app.js
。此文件会从磁盘读取节点列表 (/var/nodelist
) 并配置 Express,以便在节点存在的情况下将memcached
用作会话存储。您的文件应类似以下内容。/** * 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); });
-
在本地计算机上,更新
node-express/package.json
以添加四个依赖项。{ "name": "node-express", "version": "0.0.0", "private": true, "scripts": { "start": "node ./bin/www" }, "dependencies": { "cookie-parser": "*", "debug": "~2.6.9", "express": "~4.16.0", "http-errors": "~1.6.2", "jade": "~1.11.0", "morgan": "~1.9.0", "connect-memcached": "*", "express-session": "*", "body-parser": "*", "method-override": "*" } }
-
部署更新的应用程序。
node-express$ eb deploy
-
您的环境将在几分钟后进行更新。在环境变为绿色并准备就绪后,验证代码是否正常。
-
检查 Amazon CloudWatch 控制台
以查看 ElastiCache 指标。要查看 ElastiCache 指标,请在左侧窗格中选择指标,然后搜索当前项目数。选择 ElastiCache > 缓存节点指标,然后选择缓存节点以查看缓存中的项目数。 注意 确保您查看的是您的应用程序所部署到的相同地区。
如果您复制您的应用程序 URL 并将其粘贴到其他 Web 浏览器中,则在刷新页面之后,您应看到您的当前项目数在 5 分钟后上升。
-
制作日志的快照。有关检索日志的更多信息,请参阅查看您的 Elastic Beanstalk 环境中的 Amazon EC2 实例的日志。
-
检查日志文件包中的文件
/var/log/nodejs/nodejs.log
。您应看到类似如下所示的内容:Using memcached store nodes: [ 'aws-my-1oys9co8zt1uo.1iwtrn.0001.use1.cache.amazonaws.com:11211' ]
-
清除
如果不再希望运行您的应用程序,您可通过终止环境并删除应用程序进行清除。
请使用 eb terminate
命令终止环境并使用 eb delete
命令删除应用程序。
终止环境
从您在其中创建本地存储库的目录中,运行 eb terminate
。
$ eb terminate
此过程可能耗时数分钟。成功终止环境后,Elastic Beanstalk 会立即显示一条消息。