https://yq.aliyun.com/articles/743865javascript
前言
本文以一个Nodejs前端开发者角度出发,从零基于阿里云平台能力搭建一个弹性的Serverless平台的记录。但愿对也想了解这个产品总体的小伙伴们有必定帮助。html
官方文档:https://help.aliyun.com/document_detail/121509.html
控制台:https://cs.console.aliyun.com/
前端
为何是Knative
项目主页:https://knative.dev/
项目仓库:https://github.com/knative
java
总结为下面两张以前我分享的PPTnode
- knative 定位:
- knative 三大组件:
前置依赖
- 建立一个k8s集群,且集群中Worker节点的数量大于等于3个。
- 部署 Istio。
下图可知它们之间的关系:
git
部署k8s集群
文档:https://help.aliyun.com/document_detail/86488.html
Kubernetes 是流行的开源容器编排技术,按照如下步骤快速建立一个k8s集群
github
- 选择标准托管k8s
- 建立专有网络和虚拟交换机, 不然没法选择购买实例规格
- 选择worker实例规格,由于是体验平台,故我选择了3台最小规格支持Pod的实例, 这是最低要求。由于是托管k8s集群,故不须要选择master
- 建立和选择 密钥对,后面在本机电脑操做远端服务的认证
- 公网访问:使用 EIP 暴露 API Server 记得选择上,
集群建立好不能修改
, 否则没法在本机电脑上经过http url 访问服务 - 选择上日志服务
- 保障帐户余额不低于100
- 其余默认配置
点击建立k8s集群,全部检查项经过后,约10 分钟建立成功全部资源
算法
部署Istio
文档:https://help.aliyun.com/document_detail/89805.html
Istio为解决微服务的分布式应用架构在运维、调试、和安全管理等维度存在的问题,可经过部署Istio建立微服务网络,并提供负载均衡、服务间认证以及监控等能力,同时Istio不须要修改服务便可实现以上功能
经过下面步骤快速在上面的k8s中部署istio
docker
- 选择对应集群部署istio
- 若是要实现 Tracing 分布式追踪服务,勾选开启
- 在链路追踪服务,打开Region对应信息查看token, 复制与集群region一直的内网接入http url 到istio配置中
- 其余默认配置,点击部署,很快相应服务部署成功再k8s集群上
部署Knative
文档:https://help.aliyun.com/document_detail/121509.html
在控制台左侧,找到Knative(公测),选择组件管理,点击右上方一键部署,部署咱们前面讲到的Knative 三大组件
express
- Tekton 组件 (原build 组件不在推荐) - v0.9.2
- Serving 组件 - v0.11.0
- Eventing 组件 - v0.11.0
检查未经过,须要开启 istio-ingressgateway,解决:
在控制台> 服务网格 > istio管理, 点右侧更新
将以下,光标高亮 gateways enabled 默认false 修改成 true, 点击更新后,
再次部署kantive组件,很快便可部署成功
部署服务
下载Knative 官方服务demo 工程
git clone https://github.com/knative/docs # nodejs demo 服务 cd docs/serving/samples/hello-world/helloworld-nodejs
查看修复成,你想要的服务
const express = require('express'); const app = express(); app.get('/', (req, res) => { console.log('Hello world received a request.'); const target = process.env.TARGET || 'World'; // 我添加了输出,能够查看流量访问的不一样服务版本 const kRevision = process.env.K_REVISION || ''; res.send(`Hello ${target} (revision: ${kRevision}) \n`); }); const port = process.env.PORT || 8080; app.listen(port, () => { console.log('Hello world listening on port', port); });
镜像构建与发布
# 目前 Docker 官方维护了一个公共仓库Docker Hub 咱们将本身构建的镜像发布上去 # https://hub.docker.com/ # 进行镜像构建, 其中859652049替换成你的帐号名 docker build -t 859652049/helloworld-nodejs . # 推送镜像到公共仓库Docker Hub docker push 859652049/helloworld-nodejs
控制台可视化部署
- 回到控制面板 > Knative > 服务管理 > 选择k8s集群命名空间default, 建立服务
- 支持根据模板快速建立 和 可视化编辑建立。
- 咱们选择可视化建立
- 镜像名称输入:docker.io/859652049/helloworld-nodejs (也能够用你上面本身建立的镜像)
- 配置环境变量 TARGET: NodeX 1 (服务代码里用到这个环境变量)
-
其余默认配置,能够自由配置
- 最大并发不控制
- 弹性实例最小0, 最大100
- CPU 0.25Core, 内存 125M
- 不挂载额外存储数据卷
服务部署成功
访问服务,其中下面的ip 和 host 对应,上图中默认域名和访问网关ip
curl -H "HOST: nodejs.default.example.com" http://47.111.223.97
或者经过绑定公网ip 到默认域名上
# 推荐工具SwitchHosts https://github.com/oldj/SwitchHosts/blob/master/README_cn.md 47.111.223.97 nodejs.default.example.com
两种方式,接口数据返回成功
Kubectl命令行部署
文档:https://help.aliyun.com/document_detail/86494.html
- 安装 kubectl 客户端,根据文档, 我这边mac 经过docker 客户端 Preferences 设置中 enable kubernetes 后安装了。
- 配置登陆凭据
- 集群列表,点击集群名,选择KubeConfig(公网访问)页签,并单击复制,将内容复制到本地计算机的 $HOME/.kube/config
- 执行 kubectl get revisions 查看部署服务的版本,以下能够看到咱们上面经过控制台可视化部署的服务nodejs, 一个版本nodejs-dn5vh
5.经过kubectl 部署新的一个版本
仍是咱们以前使用的 helloworld-nodejs 工程, 将配置文件service.yaml
apiVersion: serving.knative.dev/v1alpha1 kind: Service metadata: name: nodejs # 服务名 namespace: default # 服务部署的命名空间 spec: template: metadata: name: nodejs-dn5vh-v2 spec: containers: - image: docker.io/859652049/helloworld-nodejs env: - name: TARGET value: "NodeX 2" # 环境变量更新为2 traffic: # 设置流量分配到不一样服务版本, 也可经过以下图可视化修改配置 - tag: current revisionName: nodejs-dn5vh # 修改成自动可视化自动生成的版本号 percent: 50 # 50% 流量版本1 - tag: candidate revisionName: nodejs-dn5vh-v2 # 与当前版本号一致 percent: 50 # 50% 流量版本2 - tag: latest latestRevision: true percent: 0
- 部署服务
kubectl --namespace default apply -f ./service.yaml
- 屡次访问服务,流量按比例导入到2个版本
自定义域名
在Knative Serving route 路由中默认使用 example.com 做为默认域名,route 彻底定义的域名格式默认为:
{service}.{namespace}.{default-domain} ,如:nodejs.default.example.com
域名A记录到网关
- 首先你要有个阿里云备案过的域名,不然最后访问会显示须要接入备案
- 将域名 A记录 指向本身的公网网关地址,如上:47.111.223.97
这个有个注意点,由于服务部署的命名空间和服务名 都会不断变化,或者有多个。故A记录时候使用泛域名绑定
好比 dev.lianxuify.com 这个子域名是我用来开发测试的
dev.lianxuify.com
nodejs.default.dev.lianxuify.com
nodejs-1.default.dev.lianxuify.com
- 修改默认域名example.com 为 dev.lianxuify.com
经过控制台配置
菜单 Knative > 组件管理 > 点击核心组件Serving 详情 > 自定义域名模板 > 点击查看yaml
apiVersion: v1 data: _example: | ################################ # # # EXAMPLE CONFIGURATION # # # ################################ # This block is not actually functional configuration # .... example.org: | selector: app: nonprofit # Routes having domain suffix of 'svc.cluster.local' will not be exposed # through Ingress. You can define your own label selector to assign that # ... svc.cluster.local: | selector: app: secret # 以上都是注释 dev.lianxuify.com: '' # 自定义域名,仅须要添加该行,前面添加两个空格,与顶部_example对齐 kind: ConfigMap metadata: creationTimestamp: '2020-02-05T15:21:13Z' labels: serving.knative.dev/release: v0.11.0 name: config-domain namespace: knative-serving resourceVersion: '83466654' selfLink: /api/v1/namespaces/knative-serving/configmaps/config-domain uid: 257133b2-482b-11ea-9d30-8e59b18ed506
yaml语法 基本语法 http://www.ruanyifeng.com/blog/2016/07/yaml.html
yaml转换为json: http://www.bejson.com/validators/yaml/
- 大小写敏感
- 使用缩进表示层级关系,几个空格不重要
- 缩进时不容许使用Tab键,只容许使用空格 已验证
- 缩进的空格数目不重要,只要相同层级的元素左侧对齐便可
- #表示注释
- | 保留换行符 字符串
经过 kubectl 配置
kubectl edit cm config-domain --namespace knative-serving # 同上添加一行,保存即生效 # 验证生效 kubectl get route # NAME URL READY REASON # nodejs http://nodejs.default.dev.lianxuify.com True
路由转发
当咱们有多个服务使用相同的域名,经过请求的Path不一样,将流量转发到不一样服务中
坑:knative 官方demo 工程,不支持路径访问,只处理根路径访问。 由于这个一直接口返回失败,觉得配置搭建问题。
const express = require('express'); const app = express(); // 修改/ 为 * // app.get('/', (req, res) => { app.get('*', (req, res) => { // ... }); //
- 修改代码路由为*,从新构建镜像,发布镜像 (docker.io/859652049/helloworld-nodejs:latest 已经修改过)
- 从新部署服务, 按照上面可视化、或者 kubectl 方式从新部署两个服务 nodejs、nodejs2
- 选择 Knative > 服务管理 > 点击服务名 > 选择路由转发 > 点击配置
-
配置保存后当即生效,访问符合预期
- dev.lianxuify.com/nodejs 到服务1 nodejs
- dev.lianxuify.com/nodejs 到服务2 nodejs2
弹性验证与配置
kubectl get pods -w // 查看运行的容器组,sidecar+业务服务
以下所示,当没有流量后 pod 自动会删除,流量进来会弹性扩展
流量根据以下配置进行扩缩容,可根据业务场景要求配置
Knative > 组件管理 > 点击Serving组件详情> 点击扩缩容配置
这些参数是服务弹性算法的关键配置,须要结合业务配置出最佳实践,鼠标hover小绿点有详细说明。
日志监控
在Knative 上对分布式的日志,监控接入这里没有进行深度探索。文档总体看下来,流程与常规服务接入没区别,开通对应产品进行接入便可。
如下是建立集群默认建立的部分日志和监控
回滚
在Knative 上对发布进行回滚,没有进行深度探索。大体理解以下
- 回滚历史版本,经过流量配置修改,将流量切到老版本
- 对应同版本回滚,找到以下回滚面板
CICD
持续集成持续交付这块,还在探索中。看到 GitHub 事件源add-on 组件,经过github 仓库的钩子事件能触发到
Knative平台去构建镜像、部署服务。另外一种方式本身监听gitlab 钩子事件,构建推送镜像,调用平台OpenAPI接口 (如上图有个触发从新部署的接口)或者 本身的部署平台调用kubectl 命令行工具部署
总结
以上咱们利用阿里云K8s+Istio+Knative 搭建Serverless平台
- 部署了k8s集群
- 部署了Istio
- 部署了Knative 三大组件
- 部署了业务服务,验证了弹性扩缩容
- 自定义了域名 + 路由转发 到不一样服务
- 不停服蓝绿部署、按流量灰度发布, 同个服务多个版本
该平台提供可视化配置 + 以及其yaml配置文件,对一个新手认识、使用这个生态能力有很好的帮助。
整套方案对应传统服务迁移到Serverless平台上灵活性、友好性较高,将来大有可为。但目前开发者工具相关还不是这么丰富,平台在公测中,总体使用成本和门槛相对阿里云函数计算更高些。由于最低集群3台worker要求,一直占用, 我目前是体验,选择了低配置,大概是4元多一个小时 (不知道能不能更低)
这里还有篇我对阿里云函数计算总体调研的文章: https://yq.aliyun.com/articles/743665但愿两篇文章对你们总体上认识两款产品,以及搭建serverless有帮助。若有理解有误,欢迎指出,共同成长。其间感谢阿里云 @元毅 的帮助与解答。