在本教程中,您将学习使用App ID服务时如何实现可伸缩的Node.js应用程序。 通过此IBM Cloud服务,您可以向移动和Web应用程序添加身份验证,并保护在IBM Cloud上运行的API和后端。 App ID通过可扩展的用户注册表提供电子邮件/密码身份验证,或者您可以添加社交登录名,以便用户可以使用其Facebook或Google凭据登录。 借助App ID,您还可以托管用户个人资料信息,以用于建立引人入胜的体验。
成功的云规模应用程序设计需要计划如何正确实现应用程序组件和服务的水平扩展。 对于本教程,您将在IBM Cloud中创建一个针对App ID修改的Node.js入门应用程序。 该应用程序在单个实例上运行良好。 但是您会看到,在将应用程序缩放到两个实例时,它表现出不可靠的行为。 然后,我将说明问题出在哪里,并在IBM Cloud中的Redis Cloud服务的帮助下为您提供一个解决方案。
“为了实现最佳的缩放,每道工序的设计应是无状态的,并始终坚持的数据提供给所有进程的支持服务。 ”
完成本教程所需的知识
- IBM Cloud帐户
- 安装了以下软件的工作站:
- Git(克隆基本应用程序存储库)
- IBM Cloud CLI版本0.6.5或更高版本。
- 文本编辑器,用于对提供的源代码进行较小的更新
在运行演示应用程序时,请使用用户名clouduser@example.com
和密码IBMcloud123
。
步骤1.设置初始应用程序
您的第一个任务是在IBM Cloud中创建一个使用App ID服务的简单Node.js应用程序。 您将创建一个新应用,添加并配置一个App ID服务实例,然后将该服务绑定到该应用。
- 登录到IBM Cloud,单击创建资源 。
- 单击Cloud Foundry Apps>用于Node.js的SDK 。
- 为您的应用指定唯一的名称。 例如,您可以使用
scaleApp ID
开头名称,后跟连字符,然后使其唯一,添加您的姓名缩写和日期,如scaleApp ID-tor1803
:<your app name>
替换为您在此处输入的名称。 - 点击创建 。 您可以在创建应用程序时继续执行以下步骤。
- 转到IBM Cloud Catalog,然后在安全性服务部分中单击应用程序标识 :
- 保留所有默认值,然后单击创建 。 等待服务创建,然后等待仪表板启动。
- 在“ App ID”面板的左侧菜单上,选择“ 用户”以打开“ Cloud Directory” 。
- 单击添加用户 。
- 在“ 添加用户”对话框中,输入您选择的用户名和密码,以及其他配置文件属性。 单击保存以添加用户。
- 返回到Apps仪表板,然后单击您的应用程序以打开其概述页面。
- 在“ 连接”下的应用程序概述中,单击“ 创建连接” 。
- 选择刚刚创建的App ID服务的图标,然后单击“ 连接”:
- 如果提示重新启动应用程序,请单击“ 取消” 。
- 连接服务后,您将看到带有应用程序ID服务图标的“ 应用程序连接”面板。
您的初始应用设置已完成。
步骤2.修改应用程序代码并部署
在此步骤中,您将克隆一个GitHub项目,该项目已将Node.js入门应用程序配置为使用应用程序ID。 您将对清单进行少量修改,以将其部署到您在步骤1中创建的Cloud Foundry应用程序上。
- 在本地工作站上打开命令提示符,然后运行以下命令:
git clone https://github.com/ibmecod/bluemix-scaleAppID.git <your app name>
- 更新
manifest.yml
文件,替换应用程序host
和name
属性:applications: - name: <your app name> host: <your app name> memory: 128M
- 将命令行工作目录更改为项目目录,然后使用IBM Cloud命令行工具登录到IBM Cloud:
bx login -a https://api.ng.bluemix.net
- 通过运行以下命令在IBM Cloud中更新和部署您的应用程序:
bx app push
- 观看来自
bx app push
命令的登台消息。 部署后,该应用程序将启动,您将看到该应用程序实例的running
状态:
该应用现在可以进行测试了。
步骤3.在IBM Cloud中扩展应用程序
在此步骤中,您将首先使用单个应用程序实例,然后使用添加的第二个实例测试应用程序的身份验证。
- 在新的浏览器窗口或标签中,打开您的应用程序的URL:
https://<your app name>.mybluemix.net
。 单击登录按钮。 - 您将看到默认的App ID登录屏幕。 您可以更改App ID登录选择器中可用的身份验证选项,还可以使用App ID仪表板自定义颜色和显示的徽标。
输入在配置App ID服务时添加到Cloud Directory的用户名和密码,然后单击Log in 。
您会收到一个问候语,其中包含经过身份验证的用户名和身份验证领域,例如“ Hello,Cloud User!”。 —表示您已成功为此应用程序实例进行身份验证。 - 返回到IBM Cloud Apps仪表板以扩展应用程序。 打开应用程序概述,单击“ 实例”转盘上的+按钮以增加实例编号2,然后单击“ 保存” 。
- IBM Cloud启动第二个实例。 片刻之后,实例运行状况将更新为新的实例数量:
- 关闭用于测试App ID的浏览器会话,然后打开一个新的浏览器窗口或标签。 浏览至
https://<your app name>.mybluemix.net
,然后单击“ 登录”按钮。 验证到应用程序ID登录屏幕。 - 您可能会看到登录面板再次出现,而不是简单的问候。 或者,您可能会看到简单的问候语,但是如果单击一次重新加载一次或多次,则最终返回登录面板。 如果稍作尝试,您可能还会观察到成功登录,该应用程序将返回首页,而不会通知或确认成功登录。 简而言之,应用程序行为已变得不可预测。
步骤4.了解测试结果
这个简单的应用程序对单个实例没有身份验证问题,但是两个实例是一个问题,因为该应用程序不遵循十二要素应用程序方法。 具体来说,它违反了因素6:“将应用作为一个或多个无状态进程执行”。
这种意外故障是IBM Cloud中的Node.js应用程序如何在实现与OpenID Connect一起使用的会话接口时使用express-session
中间件和Passport的副产品。 默认情况下,express-session服务将会话数据存储在内存中,因此仅两个实例之一可用。 这个问题实际上会影响任何尝试将HTTP会话与Express-Session一起使用的应用程序,因此我们在此描述的解决方案也适用于所有其他应用程序。
下图说明了会话数据仅可用于应用程序中的实例0:
有什么解决方案? 因素6继续说:“任何需要保留的数据都必须存储在有状态的支持服务中,通常是数据库。” GitHub上的快速会话文档列出了几个兼容的后备存储。 您将使用Redis实现此持久性,Redis提供了内存中键值缓存。 此更改会将用于快速会话的会话数据移出实例内存,并移入所有实例可用的持久性存储中:
步骤5.使用Redis添加会话持久性
IBM Cloud中的Redis Cloud服务与您的应用程序托管在相同的云环境中,从而最大程度地缩短了访问此支持服务的响应时间。
- 在IBM Cloud中,导航到目录,然后从“数据和分析”类别中选择“ Redis Cloud ”:
- 从定价计划列表中选择30MB免费计划。
- 单击创建以添加服务。
- 单击重新上载以完成将服务添加到您的应用程序。
- 返回到Apps仪表板,然后单击您的应用程序以打开其概述页面。
- 在“连接”下的应用程序概述中,单击“ 创建连接” 。
- 选择刚刚创建的Redis服务的图标,然后单击连接 。
- 单击重新上载以完成将服务添加到您的应用程序。
- 在应用程序源代码的本地副本中,通过在第25行上添加一个逗号和另外两个条目来更新package.json中的
dependencies
部分:"passport": "^0.4.0", "connect-redis" : "^3.3.0", "redis" : "^2.8.0" },
- 在server.js中,将
redis
和connect-redis
添加到require
部分,并在第6行之后追加:const passport = require("passport"); const redis = require('redis'); const RedisStore = require('connect-redis')(session);
- 在第112行之后,添加代码以从环境中获取Redis Cloud服务的配置详细信息并连接到该服务:
// additions for App ID support // get configuration for redis backing service and connect to service var redisConfig = appEnv.getService(/Redis.*/) var redisPort = redisConfig.credentials.port; var redisHost = redisConfig.credentials.hostname; var redisPasswd = redisConfig.credentials.password; var redisclient = redis.createClient(redisPort, redisHost, {no_ready_check: true}); redisclient.auth(redisPasswd, function (err) { if (err) { throw err; } }); redisclient.on('connect', function() { console.log('Connected to Redis'); });
- 在第130行的
app.use (session (...
语句中,添加一个选项以将Redis用作会话的存储:app.use(session({ store: new RedisStore({ client: redisclient }), secret: '123456', resave: true, saveUninitialized: true })); app.use(passport.initialize()); app.use(passport.session());
- 如果尚未保存,请保存app.js和package.json。
- 在命令行中,更新应用程序:
bx app push
- 应用启动后,将Cloud Foundry
logs
命令与recent
选项一起使用:bx app logs <your app name> --recent
- 检查启动时应用程序已连接到Redis的消息:
- manifest.yml文件未指定活动实例的数量,因此该应用程序以两个实例重新启动,并且示例输出来自实例1。
- 通过
https://<your app name>.mybluemix.net/
返回您的应用程序,然后重复步骤3中的登录测试。
成功! 现在,该应用程序可以在两个(或更多)实例上正常运行。
结论
在本教程中,您创建了一个简单的应用程序,该应用程序使用IBM Cloud的App ID服务,然后在运行一个和两个实例的情况下测试了该应用程序。 对于两个实例,该应用程序不可靠,因为Node.js express-session
中间件默认为本地内存存储。
通过使用IBM Cloud中的Redis Cloud服务添加用于express-session
的持久存储来解决此问题。 尽管非常适合本教程,但Redis Cloud免费计划没有责任/ SLA。 对于生产用途,请考虑Compose for Redis服务或Redis Enterprise Cloud中的一项服务。