前阵子看到 @于江水 分享了其获取到 AWS Certification 认证的成果,联想到可以将这篇我发布在公司内网的教程分享出来。毕竟,纸上得来终觉浅,绝知此事要躬行。本文演示了如何上线一个 Node.js 应用到阿里云,详尽地记录了对阿里云相关产品和开发链路的完整体验过程。
阿里云也有相似的认证证书。
无论未来是什么 less,相信本文介绍的在阿里云平台上部署、管理和操作方面的技术都会对你有益。——岁月静好,只因有人替你负重前行。
背景:一个社区类应用,技术选型上采用了开源软件 NodeBB。
目录:
- 刀耕火种,ECS 模式
- 创建 ECS 实例
- 创建 MongoDB 实例
- 配置数据库
- 部署应用
- 启用 Nginx
- 初始化 NodeBB
- Nginx 配置和重启
- 域名映射及 HTTPS 配置
- 企业级分布式,EDAS 模式
- 创建 Kubernetes 集群
- 创建 Docker 镜像
- 创建 EDAS 应用
- 配置负载均衡
- 多人协作,云效模式
- 创建 Kubernetes 集群
- 创建 MongoDB 实例
- 创建镜像仓库
- 创建云效应用
- 配置流水线
- 构建和启动脚本
- 监控和日志
- 日志服务
- 云监控
- 前端监控
- NodeBB 相关
- Scoket.io 长连接保持
- Taobao OAuth 2.0 登录
- 皮肤加载 Google 资源问题
- 相关链接
一、刀耕火种,ECS 模式
最容易最省钱的方式就是购买 ECS 主机然后部署应用。此时应用的架构是这样的:
首次部署上线:
- ECS 实例环境和 MongoDB 数据库创建;
- 发布代码到阿里云代码托管平台;
- 登录 ECS 实例,从阿里云代码托管平台拉取代码;
- 启动应用。
往后迭代:
- 发布代码到阿里云代码托管平台;
- 登录 ECS 实例,重启应用。
以下是通过 ECS 部署 NodeBB 的指引教程。
1.1 创建 ECS 实例
首先我们需要一个 ECS 实例。访问 ECS 控制台 点击“创建实例”。
如果没有开通过 ECS 服务,则需要先开通服务。 阿里云文档中已经有关于 ECS 的详细介绍,这里不再解释。
以下是笔者的配置:
- 基础配置:
- 计费方式选择“按量付费”;
- 地域和可用区(如何选择):
- 地域选择“华东1(杭州)”;
- 可用区选择“随机分配”(请记录该可用区,后续创建 MongoDB 实例时选择同一可用区)。
- 实例:
- 架构选择“x86”;
- 分类选择“入门级”;
- 实例规格选择“ecs.t5-c1m4.large”(突发性能实例)
- 镜像选择“公共镜像” - “CenterOS/7.6/64位”;
- 存储:(如何选择)
- 系统盘选择“高效云盘” - “20G”。
- 网络和安全组:
- 网络
- 选择“专有网络”(什么是专有网络);
- 创建一个专有网络。
- 公网带宽:
- 勾选“分配公网IPv4地址”;
- 选择“按使用流量”付费。
- 安全组:选择上一步专有网络创建的安全组
- 网络
- 系统配置:
- 登录凭证:
- 选择“自定义密码”(作为示例更方便管理,后续有需要可创建密钥对);
- 牢记密码。
- 登录凭证:
创建实例完成后,默认会获得一个固定公网 IP ,可以使用该 IP 通过 SSH(22端口)或浏览器(80端口)访问该 ECS 实例:
1.2 创建 MongoDB 实例
其次,NodeBB 支持 Redis 和 MongoDB 作为数据存储,笔者这里选择了 MongoDB,因此需要创建一个 MongoDB 实例。
访问 MongoDB 控制台 点击“创建实例”:
如果没有开通过 MongoDB 服务,则需要先开通服务。 阿里云文档中已经有关于 MongoDB 的详细介绍,这里不再解释。
- 选择“副本集(按量付费)”;
- 基本配置:
- 地域和可用区的选择和上一步创建的 ECS 实例一致。
- 网络类型:
- 专有网络和虚拟交换机的选择和上一步创建的 ECS 实例一致。
- 规格配置:规格:1核2G/存储空间:10G;
- 密码配置:立即设置并牢记密码。
1.3 配置数据库
创建数据库和用户(也可以通过 Mongo Shell 方式,笔者这里以通过 DMS 为例)。
访问 MongoDB 控制台并进入实例:
点击登录数据库:(输入账号密码,数据库名称填入“admin”(MongoDB 默认数据库)
创建数据库,笔者命名为 club;
创建用户(阿里云数据库不允许使用 root 角色进行远程连接,因此在此新建一个用户,赋予其 club 数据库的增删改查权限):
- 目标库:club;
- 用户名:xxx;
- 密码:xxx;
- 当前库权限:read/readWrite/dbAdmin(选填)。
数据安全性 - 白名单设置(参考):
将 ECS 实例 IP 设置为白名单,访问 ECS 控制台找到刚创建的实例的私有 IP:
1.4 部署应用
安装必要的软件环境并启动 NodeBB。
1.4.1 启用 Nginx
- 安装 Nginx(参考:《How To Install Nginx on CentOS 7》);
- 检查实例的安全组内配置规则,允许 80 端口访问:
- 该规则默认已创建,如果没有则需创建(参考:允许公网通过HTTP、HTTPS等服务访问实例):
- 准备就绪,通过公网 IP 访问实例。看到如下的输出则代表 Nginx 已启用成功:
1.4.2 初始化 NodeBB
安装 Node.js。
准备代码:
- 将应用代码上传到云效 - 代码托管;
- 安装 git(参考:《Download for Linux and Unix》):
yum install git
; - 将代码下载到实例内:
- 在主机上生成 SSH;
- 在云仓库增加 SSH 密钥。
初始化 NodeBB(初始化数据库、构建静态资源和生成 config.json 文件):./nodebb setup
-
- URL 填写实际的服务域名;
- MongoDB connection URI 从实例的连接信息中获取,注意替换用户名、密码及数据库名为上一步中创建的信息;
- 中间将需要设置论坛的管理员账号密码,需牢记。
初始化过程:
生成的 config.json(字段含义参考《The NodeBB Config (config.json)》):
使用 Cluster 模式启动应用:对 NodeBB 源码进行阅读,了解其启动过程,很容易就能看出 NodeBB 的启动流程支持 Cluster 模式——配置 config.json 中 port
为数组即可:
启动 NodeBB:
./nodebb start
;ps -ef | grep node
;
1.4.3 Nginx 配置和重启
- 配置请参考:《Configuring nginx as a proxy: Basic with multiple ports》,重点是:
- http://Socket.IO 的配置;
- 多节点的配置(参考:《Socket.IO: Sticky load balancing》)。
- 重启 nginx:
service nginx restart
; - 查看 nginx 运行状态:
service nginx status
。 - 通过公网访问检验:
1.5 域名映射及 HTTPS 配置
域名映射:通过内部的 IDNS 将 http://xxx.taobao.com A 记录到公网 IP。
HTTPS 配置:
- 申请和下载 HTTPS 证书:在内部的 cert 平台进行操作(你在哪里申请的域名就在该域名供应商处申请)。
- 将证书和私钥上传到 ECS 实例(可通过 git);
- 修改 Nginx 配置(参考:《Configuring nginx as a proxy: Basic with SSL》),重点关注:
- 80 端口的 302 跳转;
- ssl_certificate/ssl_certificate_key/ssl_ciphers 字段的填写。
- 通过公网访问验证:https://xxx.taobao.com 。
二、企业级分布式,EDAS 模式
部署在 ECS 实例后应用仅仅处于「可用」的状态,还面临着如下问题和隐患:
- 迭代能力不足,无法优雅终止和快速启动应用 —— 每次重新部署都将会造成应用不可用;
- 健壮性不足,物理或系统出现的问题将可能导致应用不可用;
- 并发性不足,虽然在网站前期不会是瓶颈,但单机的模式扩容有其上限。
很容易就能想到使用容器化技术和集群模式。
这就可以应用 Docker 和 Kubernetes(以下简称 k8s),阿里云提供了容器服务 Kubernetes 版。此时应用的架构是这样:
- 首次部署:
- 创建 k8s 集群,将集群控制权授予 EDAS;
- 创建镜像仓库,通过发布 git 标签触发构建镜像;
- 创建 EDAS 应用,关联镜像,部署应用:;
- 添加负载均衡,允许公网访问 EDAS 应用。
- 往后迭代:
- 通过发布 git 标签触发构建镜像;
- 访问 EDAS 应用,访问新版本镜像进行重新部署。
参考:
- 什么是 Docker?
- 什么是 Kubernetes?
- 什么是阿里云容器服务 Kubernetes 版?
以下是通过 EDAS 部署 NodeBB 的指引教程。
2.1 创建 Kubernetes 集群
首先我们需要一个 k8s 集群用于部署我们的应用。访问创建 Kubernetes 集群:
- 地域选择“华东 1”;
- 可用区选择“可用区 G”;
- 专有网络选择和上一步“ECS 部署”的一致(因为接下来将需要连接 MongoDB)。
参考:
- 如何创建 Kubernetes 集群?:
- 如何创建 Kubernetes 托管版集群? > 相比于默认的 Kubernetes 集群,托管版本会主动替您运维一套高可用的 Master 组件,免去了默认版本集群中三个 Master ECS 节点,从而节约所需的资金成本及维护时的人力成本。-- 《使用 Terraform 创建托管版 Kubernetes》
- 如何创建多可用区 Kubernetes 集群? > 为了保证业务应用的高可用,有些客户会要求关键应用部署到多个机房,一个机房一旦出问题,其他机房正常工作,从而让应用保持不间断连续运行。阿里云支持多 Region(地域),每个 Region 下又有不同的可用区。可用区是指在同一地域内,电力和网络互相独立的物理区域。多可用区能够实现跨区域的容灾能力。同时也会带来额外的网络延时。
2.2 创建 Docker 镜像
紧接着,我们需要构建出应用的 Docker 镜像。访问容器镜像服务控制台:
创建镜像仓库:
- 代码仓库选择上一步“ECS 部署”中的仓库;
- 勾选“代码变更时自动构建镜像”。
构建镜像:
在代码仓库的根目录下创建配置文件 config.json:
{ "url": "http://xxx.taobao.com", "secret": "xxx", "database": "mongo", "mongo": { "uri": "mongodb://xxxx" }, "port": "4567" }
Dockerfile 中使用配置文件启动 NodeBB:
FROM node:8.15.0
RUN mkdir -p /usr/src/app WORKDIR /usr/src/app
ARG NODE_ENV ENV NODE_ENV $NODE_ENV COPY install/package.json /usr/src/app/package.json RUN npm install && npm cache clean --force COPY . /usr/src/app
ENV NODE_ENV=production daemon=false silent=false
RUN ./nobebb build CMD ./nodebb start
EXPOSE 4567
通过发布标签触发镜像构建:release-v$version
2.3 创建 EDAS 应用
然后我们创建一个 EDAS 应用,并使用刚创建的镜像部署该应用。访问 EDAS 控制台:
- 访问“EDAS - 资源管理 - 集群”:导入刚创建的 K8S 集群;
- 访问“EDAS - 应用管理 - 应用列表”:创建新应用:
- 集群类型:选择“容器服务K8S集群” - 选择刚导入的 K8S 集群;
- 镜像:选择上一步构建的镜像和版本。
- 配置应用:
- 添加负载均衡(公网):
- 通过负载均衡 IP 验证应用部署是否成功。
2.4 配置负载均衡
最后,我们在负载均衡层强制启用 HTTPS,并将域名解析到负载均衡的公网 IP。
访问负载均衡控制台操作:
- 创建证书:
- 访问“负载均衡 - 实例 - 证书管理”;
- 点击创建证书;
- 选择“上传第三方签发证书“;
- 上传“ECS 部署”章节中下载的证书。
- 负载均衡配置:
- 通过 IP 找到对应的负载均衡实例;
- 添加 HTTPS 监听(参考《如何添加 HTTPS 监听》):
- 协议选择“HTTS”;
- 监听端口输入“443”;
- 高级配置中,开启会话保持;
- SSL 证书选择上一步创建的证书;
- 后端服务器选择“虚拟服务器组”。
- 删除原 TCP 80 的监听;
- 添加 HTTP 监听:
- 协议选择“HTTP”;
- 监听端口输入“80”;
- 高级配置开启“监听转发”;
- 目的监听选择“HTTPS 443”。
- 通过 HTTPS 访问 IP 验证负载均衡配置成功:
- 域名映射:通过 IDNS 将 http://xxx.taobao.com A 到负载均衡公网 IP。
三、多人协作,云效模式
使用 EDAS 已经在一定程度上加强了我们应用的迭代能力、健壮性和并发性,但是在多人协作、持续集成、持续交付上依然空缺。云效则可以应付此类场景。不过云效并不会在创建应用时自动为我们分配机器资源,也没有提供 Node.js 的最佳实践的镜像、构建和部署脚本。
3.1 创建 Kubernetes 集群
云效内需要自己创建集群资源,并授予云效进行管理。例如,笔者搭建了日常、预发、线上集群:
操作步骤如下:
- 创建日常、线上专有网络;
- 线上专有网络配置线上和预发交换机;
- 创建日常集群,创建预发集群(选择线上专有网络预发交换机),创建线上集群(选择线上专有网络线上交换机)。
这样便做到了日常与线上环境的隔离,预发和线上环境的隔离:
这里还有一个命题是,如何实现日常和预发环境只允许特定的客户端进行访问?目前通过负载均衡连接 VPC 的方式,只要知道了负载均衡 IP ,任何客户端都可以访问我们日常和预发环境的应用,这是我们不希望的。
3.2 创建 MongoDB 实例
为了和日常、线上环境配合,我们可以创建两个 MongoDB 数据库,并将两个数据库设置在日常和线上专有网络。如何创建请参考上文中“ECS - 创建 MongoDB 实例”章节。
3.3 创建镜像仓库
应用构建依赖容器镜像服务,在创建应用时就需要指定镜像仓库,因此我们提前创建。
访问 Aliyun Code 新项目来创建镜像的代码仓库(创建镜像仓库时需关联一个代码仓库):
访问容器镜像服务控制台,创建镜像仓库:
3.4 创建云效应用
在云效创建应用的过程与 Aone 类似,遵循项目 - 应用的结构,此前的过程不再赘述。这里简单罗列创建 Node.js 应用的配置:
- 基本信息:
- 开发模式:选择“分支模式”(参考:《什么是分支模式》),该模式与 Aone 一致;
- 配置代码库:
- 代码源:选择“Aliyun”;
- 仓库:选择“关联已有”;
- 地址:输入前面“ECS 部署”章节的代码仓库地址;
- 应用模板:该步骤将会向代码仓库内写入
应用名.release
文件,该文件将会在构建阶段被读取用于决定构建过程。- 编程语言:选择“NodeJS”;
- 部署选项:选择“Kubernetes 部署”;
- 选择 Node 模板。
- 构建配置:
- 勾选“Docker构建”;
- 选择上一步创建的镜像仓库。
3.5 配置流水线
在云效内我们需要手动配置流水线及各环节的构建和部署配置。
我配置了三条流水线:
以日常流水线为例,需要配置最基本的两个阶段:构建和部署。
构建配置:
- 构建配置文件(即在创建应用阶段写入仓库根目录的 "应用名.release"):参考:《Web 应用构建配置 》
- 包标签:根据不同的标签实现不同的 Dockerfile 构建不同的包,这里主要目的是为了针对不同的环境构建不同包。(参考:《使用传入参数改变构建行为》)
部署配置(云效将根据这些配置将构建好的包进行下发并部署):
将 k8s 集群导入到云效,选择需要部署的集群。
如果是首次配置,则需要新建服务,保存时云效将创建 k8s 的 service 资源,并在首次部署时创建 k8s 的 deployment 资源:
- 类型选择“LoadBalancer”即负载均衡;
- 服务端口,即负载均衡监听的端口;
- 容器端口即启动的 Docker 容器监听的端口
3.6 构建和启动脚本
在 Aone 内 begg 和 midway 已经为我们封装好了镜像、构建和部署脚本的细节,在云效的上线流程中其过程相似,但相关的环节则需要自定义。
在仓库根目录创建如下文件,定义构建和启动脚本。
- 构建脚本(
/bin/build.sh
):在 club.release 中指定,在构建环境将被执行。主要是安装依赖和构建 Nodebb 资源(参考:《NodeBB Development》);
sh echo "Target environment is ${PACKAGE_LABEL}"
npm config set registry https://registry.npm.taobao.org
npm install --production || exit 1
./nodebb build -c config.${PACKAGE_LABEL}.json || exit 1
echo "All building process done."
/Dockerfile
:主要是安装 Nginx 和 Node.js ,复制启动脚本之类工作。/bin/start.sh
:启动脚本,启动 NodeBB 和 Nigix。
然后在云效新建特效分支,提交到集成,进行一次流水线的部署,云效便会构建并下发创建 k8s 应用:
3.7 监控和日志
在应用上线后,为确保应用在持续健康地运行,还需要有相应的监控及日志(在出现问题时进行现场回溯)。在集团内部,Sandbox 提供了全链路的监控能力。
在云上,有云监控、业务实时监控服务、日志服务。以下简单介绍一下如何接入和查看指标。
3.8 日志服务
在 k8s 集群已开通日志服务的前提下,可以针对集群内的应用进行日志配置。点击应用编辑即可进行配置,首次点击保存 k8s 服务将会自动创建日志服务。
例如笔者就针对应用级别、标准输出进行了存储:
保存后访问阿里云日志服务控制台即看到相关的日志服务已创建:
点击查询即可看到相应的日志,例如笔者配置的 NodeBB 应用日志:
更多内容可参考:《使用日志服务进行Kubernetes日志采集》
3.9 云监控
对于每个应用,可以通过 k8s 容器服务与云监控的集成,提供监控功能查看应用的资源使用情况。还可以通过可用性监控快速发现本地或依赖的远程服务无响应的情况。
3.10 前端监控
使用业务实时监控服务可从页面打开速度(测速)、页面稳定性(JS Error)和外部服务调用成功率(API)这三个方面监测 Web 页面的健康度。接入后在应用控制台审视相关数据:
更多内容可参考:《前端监控接入概述》
四、NodeBB 相关
除此之外,笔者还踩了一些 NodeBB 的定制的坑,在此分享给有需要的同学。
4.1 http://Scoket.io 长连接保持
主要是两个配置:
- SLB 配置会话保持(参考:《会话保持常见问题》);
- k8s 服务配置(参考:《Kubernetes 下实现 socket.io 的集群模式》):
- sessionAffinity: ClientIP
- externaltrafficpolicy: Local
4.2 Taobao OAuth 2.0 登录
笔者已封装 nodebb-plugin-sso-taobao 插件,只需要申请并填写 Appkey 信息即可使用。
- 访问 https://open.taobao.com/ 申请应用,得到 Appkey;
- 申请 API(taobao.user.identity.get) 授权 Appkey。
4.3 皮肤加载 Google 资源问题
NodeBB 的前端基于 Bootstrap 实现,皮肤方案则使用了 bootswatch。bootswatch 中的一些皮肤(例如 simplex)使用了 Google 的字体资源。这些资源由于网络原因在国内无法加载,将会造成网页的渲染阻塞。
在 NodeBB@1.11.x 版本中,目前笔者还没有比较好的办法解决这一问题。唯一的方法就是不使用皮肤,如果确实希望复用某个皮肤的样式,可以通过创建 NodeBB 主题(参考:《如何创建主题》)的方式,将这些资源放入主题包中。
五、相关链接
- 阿里云相关产品
- 云效
- 云数据库 MongoDB 版(ApsaraDB for MongoDB)
- 弹性伸缩(Auto Scaling)
- NAT 网关(NAT Gateway)
- 容器镜像服务(Container Registry)
- 容器服务 Kubernetes 版(Container Service for Kubernetes)
- 负载均衡(Server Load Balancer)
- 企业级分布式应用服务(Enterprise Distributed Application Service, 简称 EDAS)
- 专有网络(Virtual Private Cloud,简称 VPC)
- 日志服务(Log Service,简称 LOG)
- 云服务器(Elastic Compute Service,简称 ECS)
- 资源编排服务(Resource Orchestration Service,简称 ROS)
- 弹性公网IP(Elastic IP Address,简称 EIP)
- 业务实时监控服务(Application Real-Time Monitoring Service,简称 ARMS)
- 云监控(CloudMonitor)
- 阿里云企业控制台