This commit is contained in:
louzefeng
2024-07-11 05:50:32 +00:00
parent bf99793fd0
commit d3828a7aee
6071 changed files with 0 additions and 0 deletions

View File

@@ -0,0 +1,266 @@
<audio id="audio" title="08 | 搭建私有ServerlessK8s和云原生CNCF" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/ba/10/bad826855608b5a3e2dcde8b8bd08210.mp3"></audio>
你好我是秦粤。上节课我们只是用Docker部署了index.js如果我们将所有拆解出来的微服务都用Docker独立部署我们就要同时管理多个Docker容器也就是Docker集群。如果是更复杂一些的业务可能需要同时管理几十甚至上百个微服务显然我们手动维护Docker集群的效率就太低了。而容器即服务CaaS恰好也需要集群的管理工具。我们也知道FaaS的底层就是CaaS那CaaS又是如何管理这么多函数实例的呢怎么做才能提升效率
我想你应该听过Kubernetes它也叫K8s后面统一简称K8s用于自动部署、扩展和管理容器化应用程序的开源系统是Docker集群的管理工具。为了解决上述问题其实我们就可以考虑使用它。K8s的好处就在于它具备跨环境统一部署的能力。
这节课我们就试着在本地环境中搭建K8s来管理我们的Docker集群。但正常情况下这个场景需要几台机器才能完成而通过Docker我们还是可以用一台机器就可以在本地搭建一个低配版的K8s。
下节课我们还会在今天内容的基础上用K8s的CaaS方式实现一套Serverless环境。通过这两节课的内容你就可以完整地搭建出属于自己的Serverless了。
话不多说,我们现在就开始,希望你能跟着我一起多动手。
## PC上的K8s
那在开始之前,我们先得把安装问题解决了,这部分可能会有点小困难,所以我也给你详细讲下。
首先我们需要安装[kubectl](https://kubernetes.io/zh/docs/tasks/tools/install-kubectl/)它是K8s的命令行工具。
你需要在你的PC上安装K8s如果你的操作系统是MacOS或者Windows那么就比较简单了桌面版的Docker已经自带了[K8s](https://www.docker.com/products/kubernetes);其它操作系统的同学需要安装[minikube](https://kubernetes.io/zh/docs/tasks/tools/install-minikube)。
不过要顺利启动桌面版Docker自带的K8s你还得解决国内Docker镜像下载不了的问题这里请你先下载[第8课的代码](https://github.com/pusongyang/todolist-backend/tree/lesson08)。接着,请你跟着我的步骤进行操作:
1. 开通阿里云的[容器镜像仓库](https://cr.console.aliyun.com/)
1. 在阿里云的容器镜像服务里,找到镜像加速器,复制你的镜像加速器地址;
1. 打开桌面版Docker的控制台找到Docker Engine。
```
{
&quot;registry-mirrors&quot; : [
&quot;https://你的加速地址.mirror.aliyuncs.com&quot;
],
&quot;debug&quot; : true,
&quot;experimental&quot; : true
}
```
1. 预下载K8s所需要的所有镜像执行我目录下的docker-k8s-prefetch.sh如果你是Windows操作系统建议使用gitBash[1]
```
chmode +x docker-k8s-prefetch.sh
./docker-k8s-prefetch.sh
```
1. 上面拉取完运行K8s所需的Docker镜像你就可以在桌面版Docker的K8s项中勾选启动K8s了。
**现在K8s就能顺利启动了启动成功后请你继续执行下面的命令。**
查看安装好的K8s系统运行状况。
```
kubectl get all -n kube-system
```
查看K8s有哪些配置环境对应~/.kube/config。
```
kubectl config get-contexts
```
查看当前K8s环境的整体情况。
```
kubectl get all
```
按照我的流程走在大部分的机器上本地运行K8s都是没有问题的如果你卡住了请在留言区告知我我帮你解决问题。
## K8s介绍
安装完K8s之后我们其实还是要简单地了解下K8s这对于你后面应用它有重要的意义。
我想你应该知道K8s是云原生Cloud Native[2] 的重要组成部分目前K8s的文档[3]已经全面中文化建议你多翻阅而云原生其实就是一套通用的云服务商解决方案。在我们的前几节课中就有同学问“如果我使用了某个运营商的Serverless就和这个云服务商强制绑定了怎么办我是不是就没办法使用其他运营商的服务了”这就是服务商锁定vendor-lock而云原生的诞生就是为了解决这个问题通过云原生基金会CNCF(Cloud Native Computing Foundation)[4],我们可以得到一整套解锁云服务商的开源解决方案。
那K8s作为云原生Cloud Native的重要组成部分之一它的作用是什么呢这里我先留一个悬念通过理解K8s的原理你就能清楚这个问题并充分利用好K8s了。
我们先来看看K8s的原理图
<img src="https://static001.geekbang.org/resource/image/70/f8/7084735b118636816d1284a80e67d0f8.png" alt="">
通过图示我们可以知道PC本地安装kubectl是K8s的命令行操作工具通过它我们就可以控制K8s集群了。又因为kubectl是通过加密通信的所以我们可以在一台电脑上同时控制多个K8s集群不过需要指定当前操作的上下文context。这个也就是云原生的重要理念我们的架构可以部署在多套云服务环境上。
在K8s集群中Master节点很重要它是我们整个集群的中枢。没错Master节点就是Stateful的。Master节点由API Server、etcd、kube-controller-manager等几个核心成员组成它只负责维持整个K8s集群的状态为了保证职责单一Master节点不会运行我们的容器实例。
Worker节点也就是K8s Node节点才是我们部署的容器真正运行的地方但在K8s中运行容器的最小单位是Pod。一个Pod具备一个集群IP且端口共享Pod里可以运行一个或多个容器但最佳的做法还是一个Pod只运行一个容器。这是因为一个Pod里面运行多个容器容器会竞争Pod的资源也会影响Pod的启动速度而一个Pod里只运行一个容器可以方便我们快速定位问题监控指标也比较明确。
在K8s集群中它会构建自己的私有网络每个容器都有自己的集群IP容器在集群内部可以互相访问集群外却无法直接访问。因此我们如果要从外部访问K8s集群提供的服务则需要通过K8s service将服务暴露出来才行。
### 案例“待办任务”K8s版本
现在原理我是讲出来了但可能还是有点不好理解接下来我们就还是套进案例去看依然是我们的“待办任务”Web服务我们现在把它部署到K8s集群中运行一下你可以切身体验。相信这样你就非常清楚这其中的原理了。不过我们本地搭建的例子中为了节省资源只有一个Master节点所有的内容都部署在这个Master节点中。
还记得我们上节课构建的Docker镜像吗我们就用它来部署本地的K8s集群。
我们通常在实际项目中会使用YAML文件来控制我们的应用部署。YAML你可以理解为就是将我们在K8s部署的所有要做的事情都写成一个文件这样就避免了我们要记录大量的kubectl命令执行。不过K8s也细心地帮我们准备了K8s对象和YAML文件互相转换的能力。这种能力可以让我们快速地将一个K8s集群中部署的结构导出YAML文件然后再在另一个K8s集群中用这个YAML文件还原出同样的部署结构。
我们需要先确认一下我们当前的操作是在正确的K8s集群上下文中。对应我们的例子里也就是看当前选中的集群是不是docker-desktop。
```
kubectl config get-contexts
```
<img src="https://static001.geekbang.org/resource/image/91/bc/910eae7773766239c81400991d4568bc.png" alt="">
如果不对,则需要执行切换集群:
```
kubectl config use-context docker-desktop
```
然后需要我们添加一下拉取镜像的证书服务:
```
kubectl create secret docker-registry regcred --docker-server=registry.cn-shanghai.aliyuncs.com --docker-username=你的容器镜像仓库用户名 --docker-password=你的容器镜像仓库密码
```
这里我需要解释一下通常我们在镜像仓库中可以设置这个仓库公开或者私有。如果是操作系统的镜像设置为公开是完全没有问题的所有人都可以下载我们的公开镜像但如果是我们自己的应用镜像还是需要设置成私有下载私有镜像需要验证用户身份也就是Docker Login的操作。因为我们应用的镜像仓库中包含我们的最终运行代码往往会有我们数据库的登录用户名和密码或者我们云服务的ak/sk这些重要信息如果泄露很容易让我们的应用受到攻击。
当你添加完secret后就可以通过下面的命令来查看secret服务了
```
kubectl get secret regcred
```
另外我还需要再啰嗦一下secret也不建议你用YAML文件设置毕竟放着你用户名和密码的文件还是越少越好。
做完准备工作,对我们这次部署的项目而言就很简单了,只需要再执行一句话:
```
kubectl apply -f myapp.yaml
```
这句话的意思就是告诉K8s集群请按照我的部署文件myapp.yaml部署我的应用。具体如下图所示
<img src="https://static001.geekbang.org/resource/image/f9/31/f92f4b5abd24b1e25ea269d1c2528b31.png" alt="">
通过获取容器的运行状态对照上图我粗略地讲解一下我们的myapp.yaml文件吧。
- 首先我们指定要创建一个service/myapp它选中打了"app:myapp"标签的Pod集群内访问端口号3001并且暴露service的端口号30512。
- 然后我们创建了部署服务deployment.apps/myapp它负责保持我们的Pod数量恒久为1并且给Pod打上"app:myapp"的标签也就是负责我们的Pod持久化一旦Pod挂了部署服务就会重新拉起一个。
- 最后我们的容器服务申明了自己的Docker镜像是什么拉取镜像的secret以及需要什么资源。
现在我们再回看K8s的原理图不过这张是实现“待办任务”Web服务版本的
<img src="https://static001.geekbang.org/resource/image/a1/4c/a11f760ad9e3d8ba42da0d878a61a04c.png" alt="">
首先我们可以看出使用K8s仍然需要我们上节课的Docker发布流程build、ship、run。不过现在有很多云服务商也会提供Docker镜像构建服务你只需要上传你的Dockerfile就会帮你构建镜像并且push到镜像仓库。云服务商提供的镜像构建服务的速度比你本地构建要快很多倍。
而且相信你也发现了K8s其实就是一套Docker容器实例的运行保障机制。我们自己Run一个Docker镜像会有许多因素要考虑例如安全性、网络隔离、日志、性能监控等等。这些K8s都帮我们考虑到了它提供了一个Docker运行的最佳环境架构而且还是开源的。
还有既然我们本地都可以运行K8s的YAML文件那么我们在云上是不是也能运行你还记得前面我们留的悬念吧现在就解决了。
通过K8s我们要解开云服务商锁定vendor-lock就很简单了。我们只需要将云服务商提供的K8s环境添加到我们kubectl的配置文件中就可以让我们的应用运行在云服务商的K8s环境中了。目前所有的较大的云服务商都已经加入CNCF所以当你掌握K8s后就可以根据云服务商的价格和自己喜好自由地选择将你的K8s集群部署在CNCF成员的云服务商上甚至你也可以在自己的机房搭建K8s环境部署你的应用。
到这儿我们就部署好了一个K8s集群那之后我们该如何实时监控容器的运行状态呢K8s既然能管理容器集群控制容器运行实例的个数那应该也能实时监测容器帮我们解决扩缩容的问题吧是的其实上节课我们已经介绍到了容器扩缩容的原理但并没有给你讲如何实现那接下来我们就重点看看K8s如何实现实时监控和自动扩缩容。
## K8s如何实现扩缩容
首先我们要知道的一点就是K8s其实还向我们隐藏了一部分内容就是它自身的服务状态。而我们不指定命名空间默认的命名空间其实是default空间。要查看K8s集群系统的运行状态我们可以通过指定namespace为kube-system来查看。K8s集群通过namespace隔离一定程度上隐藏了系统配置这可以避免我们误操作。另外它也提供给我们一种逻辑隔离手段将不同用途的服务和节点划分开来。
<img src="https://static001.geekbang.org/resource/image/fb/13/fb15835cb57a3e7d587aa2d401123213.png" alt="">
没错K8s自己的服务也是运行在自己的集群中的不过是通过命名空间将自己做了隔离。这里需要你注意的是这些服务我不建议你尝试去修改因为它们涉及到了K8s集群的稳定性但同时K8s集群本身也具备扩展性我们可以通过给K8s安装组件Component扩展K8s的能力。接下来我先向你介绍K8s中的性能指标metrics组件[5]。
我的代码根目录下已经准备好了metric组件的YAML文件你只需要执行安装就可以了
```
kubectl apply -f metrics-components.yaml
```
安装完后我们再看K8s的系统命名空间
<img src="https://static001.geekbang.org/resource/image/34/ff/34fe0c9268d5913607fd25464227efff.png" alt="">
对比你就能发现我们已经安装并启动了metrics-server。那么metrics组件有什么用呢我们执行下面的命令看看
```
kubectl top node
```
<img src="https://static001.geekbang.org/resource/image/f0/08/f0e5f436d48c47899ebcdf5045ed2a08.png" alt="">
安装metrics组件后它就可以将我们应用的监控指标metrics显示出来了。没错这里我们又可以用到上一讲的内容了。既然我们有了实时的监控指标那么我们就可以依赖这个指标来做我们的自动扩缩容了
```
kubectl autoscale deployment myapp --cpu-percent=30 --min=1 --max=3
```
上面这句话的意思就是添加一个自动扩缩容部署服务cpu水位是30%最小维持1个Pod最大维持3个Pod。执行完后我们就发现会多了一个部署服务。
```
kubectl get hpa
```
<img src="https://static001.geekbang.org/resource/image/56/2d/56a7a23302c7feabf3df14ae341bf52d.png" alt="">
接下来,我们就可以模拟压测了:
```
kubectl run -i --tty load-generator --image=busybox /bin/sh
$ while true; do wget -q -O- http://10.1.0.16:3001/api/rule; done
```
这里我们用一个K8s的Pod启动busybox镜像执行死循环压测我们的MyApp服务。不过我们目前用Node.js实现的应用可以扛住的流量比较大单机模拟的压测轻易还压测不到扩容的水位。
<img src="https://static001.geekbang.org/resource/image/1e/76/1eaa1c830583326cb0bd5fa919270c76.png" alt="">
## 总结
这节课我向你介绍了云原生基金会CNCF的重要成员Kubernetes。**K8s是用于自动部署、扩展和管理容器化应用程序的开源系统。**云原生其实就是一套通用的云服务商解决方案。
然后我们一起体验了在本地PC上通过Docker desktop搭建K8s。搭建完后我还向你介绍了K8s的运行原理K8s Master节点和Worker节点。其中Master节点负责我们整个K8s集群的运作状态Worker节点则是具体运行我们容器的地方。
之后我们就开始把“待办任务”Web服务通过一个K8s的YAML文件来部署并且暴露NodePort让我们用浏览器访问。
为了展示K8s如何通过组件Component扩展能力接着我们介绍了K8s中如何安装使用组件metrics我们通过一个YAML文件将metrics组件安装到了K8s集群的kube-system命名空间中后就可以监控到应用的运行指标metrics了。给K8s集群添加上监控指标metrics的能力我们就可以通过autoscale命令让应用根据metrics指标和水位来扩缩容了。
最后我们启动了一个BusyBox的Docker容器模拟压测了我们的“待办任务”Web服务。
总的来说这节课我们的最终目的就是在本地部署一套K8s集群通过我们“待办任务”Web服务的K8s版本让你了解K8s的工作原理。我们已经把下节课的准备工作做好了下节课我们将在K8s的基础上部署Serverless可以说实现属于你自己的Serverless你已经完成了一半。
## 作业
这节课是实战课所以作业就是我们今天要练习的内容。请在你自己的电脑上安装K8s集群部署我们的“待办任务”Web服务到自己的K8s集群并从浏览器中访问到K8s集群提供的服务。
另外你可以尝试一下手动删除我们部署的MyApp Pod。
```
kubectl delete pod/你的pod名字
```
但你很快就会发现这个Pod会被K8s重新拉起而我们要清除部署的MyApp的所有内容其实也很简单只需要告诉K8s删除我们的myapp.yaml文件创建的资源就可以了。
```
kubectl delete -f myapp.yaml
```
快来动手尝试一下吧,期待你也能分享下今天的成果以及感受。另外,如果今天的内容让你有所收获,也欢迎你把它分享给身边的朋友,邀请他加入学习。
## 参考资料
[1] [https://gitforwindows.org/](https://gitforwindows.org/)
[2] [https://www.cncf.io/](https://www.cncf.io/)
[3] [https://kubernetes.io/zh/](https://kubernetes.io/zh/)
[4] [https://github.com/cncf/landscape](https://github.com/cncf/landscape)
[5] [https://github.com/kubernetes-incubator/metrics-server/](https://github.com/kubernetes-incubator/metrics-server/)

View File

@@ -0,0 +1,266 @@
<audio id="audio" title="09 | 搭建私有Serverless基于K8s的Serverless" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/a2/47/a29155c426f683d24ad4bc302d15f447.mp3"></audio>
你好我是秦粤。上节课我向你介绍了云原生基金会CNCF的重要成员K8s它是用于自动部署、扩展和管理容器化应用程序的开源系统。通过实践我们在本地搭建K8s并将“待办任务”Web服务案例部署到了本地K8s上。K8s这门技术我推荐你一定要学习下不管是前端还是后端因为从目前的发展趋势来看这门技术必定会越来越重要。
今天这节课我们就继续学习如何搭建私有的Serverless环境。具体来说我们会在上节课部署本地K8s的基础上搭建Serverless底座然后继续安装组件扩展K8s的集群能力最终让本地K8s集群支持Serverless。
## 搭建Serverless的前提
在开始之前我们先得清楚一个问题之前在基础篇讲Serverless Computing也就是FaaS的时候也有同学提问到“微服务、Service Mesh和Serverless到底是什么关系
这些概念确实很高频地出现在我们的视野不过你不要有压力我在学习Serverless的时候也被这些概念所困扰。我们可以先回顾下微服务我们在用微服务做BaaS化时相信你也发现了微服务中有很多概念和Serverless的概念很接近。
Service Mesh简单来说就是让微服务应用无感知的微服务网络通讯方案。我们可以将Serverless架构的网络通讯也托管给ServiceMesh。通过Service MeshServerless组件可以和K8s集群复杂且精密地配合在一起最终支撑我们部署的应用Serverless化。我们看下下面这张架构图
<img src="https://static001.geekbang.org/resource/image/9d/31/9d7da97db12f285d62b317c3ff894731.png" alt="">
通过图示我们可以清楚地看到Serverless的底层可以基于Service Mesh来搭建。但Service Mesh其实只是实现Serverless网络通讯的其中一种方案除此之外还有RSocket、gRPC、Dubbo等方案而我选择Service Mesh的原因是这套方案是可以基于K8s组件的而且还提供了可视化工具帮助我们理解Serverless的运行机制比如如何做到零启动如何控制灰度流量等等。如果要实践Service Mesh无疑是首选。
## Serverless底座Service Mesh
有人把Kubernetes、 Service Mesh和Serverless技术称为云原生应用开发的三驾马车到现在我估摸着你也理解这其中的缘由了吧。这里我还是要说明下我们后面几节课里引入了很多新名词这些名词我基本都是走马观花大致给你过了下让你有个宏观的了解。有时间的话你还是应该再深入进去看看。
那么言归正传我们现在具体看下Service Mesh的应用原理。
我们在讲微服务的时候只是讲了拆解与合并的理论指导并没有涉及到具体实现。那如果切换到实现的话业界其实就有很多的微服务框架了但大多数都是限定语言的SDK尤其是Java的微服务框架特别多。
而SDK版本的微服务框架其实很重的一块都在于微服务之间网络通讯的实现。例如服务请求失败重试调用多个服务实例的负载均衡服务请求量过大时的限流降级等等。这些逻辑往往还需要微服务的开发者关心而且在每种SDK语言中都需要重复实现一遍。那有没有可能将微服务的网络通信逻辑从SDK中抽离出来呢让我们的微服务变得更加轻量甚至不用去关心网络如何通讯呢
答案就是Service Mesh。我们举例来说明还是用咱们的“待办任务”Web服务来举例。
我们如果把拆解后的应用部署到K8s集群Pod中过程就如下图所示MyApp应用会通过HTTP直接去调用集群内的用户微服务和待办任务微服务。
<img src="https://static001.geekbang.org/resource/image/a0/00/a0a9b05966e8761be2e72ba4532ec700.png" alt="">
但HTTP直接访问带来的安全性问题又怎么办呢如果有人在我们的集群中启动一个BusyBox容器那不就直接可以对我们的用户微服务和待办任务微服务进行攻击了吗还有当我们有多个用户微服务实例时我们又该如何分配流量呢
所以通常我们使用传统微服务架构SDK它里面会有大量的这种逻辑而且有很多策略需要我们自己在调用SDK时去判断开启我们的代码也将会和微服务架构的SDK大量地耦合在一起。
服务网格Service Mesh则是换了一种思路它将微服务中的网络通信逻辑抽离了出来通过无侵入的方式接管我们的网络流量让我们不用再去关心那么重的微服务SDK了。下面我们看看Service Mesh是怎么解决这个问题的。
<img src="https://static001.geekbang.org/resource/image/d1/75/d11343ddee25c4c28d6df0f822558975.png" alt="">
通过图示可知Service Mesh可以分为数据面板和控制面板数据面板负责接管我们的网络通讯控制面板则控制和反馈网络通讯的状态。Service Mesh将我们网络的通讯通过注入一个边车Sidecar全部承接了过去。
数据面板中我们的应用和微服务看上去直接跟Sidecar通信但实际上Sidecar可以通过流量劫持来实现所以通常我们的应用和微服务是无感的不用有任何的改动只是使用HTTP请求数据。
控制面板则复杂一些它也是Service Mesh的运作核心。pilot是整个Control Plane的驾驶员它负责服务发现、流量管理和扩缩容citadel则是控制面板的守护堡垒它负责安全证书和鉴权Mixer则是通讯官将我们控制面板的策略下发并且收集每个服务的运行状况。
现在你应该清楚Service Mesh是怎么回事了它是怎么把微服务的网络通信逻辑从SDK中抽离出来的我们又为什么说Service Mesh就是Serverless的网络通讯底座。
## Serverless底座搭建K8s组件Istio
那接下来我们就要动手搭建Service Mesh了。
首先我们得扩大一下Docker Desktop操作系统的占用资源这是因为我们后面在搭建的过程中需要创建一堆容器。我推荐你将CPUs配置到4核内存至少8GB这是从我的经验出发一个较为合适的参数。
<img src="https://static001.geekbang.org/resource/image/50/ec/50d7e965a9734aacf39bb7f77e55a1ec.png" alt="">
设置好后我们需要用到CNCF的另外一位重要成员Istio[1] 了它是在K8s上Service Mesh的实现方式用于连接、保护、控制和观测服务。有关它的详细介绍我们在这就不展开了不清楚的话可以查看我们的参考资料。
Istio的安装脚本我已经放在我们这节课的[Github仓库代码](https://github.com/pusongyang/todolist-backend/tree/lesson09)中了。下面我们要进入根目录下的install-istio这里Istio官方其实提供了Istio 1.4.3 K8s安装包但为了简化大家的操作我直接放到项目代码中了。
然后kubectl apply安装Istio。
```
kubectl apply -f .
```
安装完毕后我们就可以通过命名空间istio-system来查看Istio是否安装成功。
```
kubectl get all -n istio-system
```
相信你也发现了吧这跟我们上节课中安装metrics组件一样Istio也是采用K8s组件Component的方式来安装的。
<img src="https://static001.geekbang.org/resource/image/a3/b5/a3cadbeebf92e839ac0b4a76c35d26b5.png" alt="">
不过使用了Istio以后还有一个细节需要我们注意默认Istio不会开启Sidecar注入这个需要我们手动开启。
我们可以通过给命名空间default打上label让我们部署的Pod自动打开Sidecar。
```
kubectl label ns default istio-injection=enabled
```
Istio会根据我们的标签去判断当前部署的应用是否需要开启Sidecar。
```
kubectl describe ns default
```
<img src="https://static001.geekbang.org/resource/image/19/42/19d917ec41aa365693d4830d88c0ad42.png" alt="">
好了我们现在可以部署我们的应用了。我们将项目目录下的Dockerfile、Dockerfile-rule、Dockerfile-user都用Docker构建一遍并且上传到我们的Registry。
```
docker build --force-rm -t registry.cn-shanghai.aliyuncs.com/jike-serverless/todolist:lesson09 -f Dockerfile .
docker build --force-rm -t registry.cn-shanghai.aliyuncs.com/jike-serverless/rule:lesson09 -f Dockerfile-rule .
docker build --force-rm -t registry.cn-shanghai.aliyuncs.com/jike-serverless/user:lesson09 -f Dockerfile-user .
docker push registry.cn-shanghai.aliyuncs.com/jike-serverless/todolist:lesson09
docker push registry.cn-shanghai.aliyuncs.com/jike-serverless/rule:lesson09
docker push registry.cn-shanghai.aliyuncs.com/jike-serverless/user:lesson09
```
然后修改项目istio-myapp目录中的YAML文件改成你自己仓库中的URI。接着在istio-myapp目录下执行kubectl apply“点”部署所有YAML文件。
```
kubectl apply -f .
```
部署完成后我们通过kubectl describe查看一下MyApp服务暴露的端口号
```
kubectl describe service/myapp
```
<img src="https://static001.geekbang.org/resource/image/03/97/0331db708282a70543c4c4ef3bcab997.png" alt="">
接下来我们用浏览器访问[http://localhost:31947](http://localhost:31947%EF%BC%8C)就可以看到我们新部署的MyApp应用了。
你也许会好奇这跟我们之前的有什么不同Istio都做了什么
我们将Istio的控制面板服务kiali也通过Service暴露到端口上访问一下看看。
```
kubectl expose deployment.apps/kiali --type=NodePort --port=20001 --name='kiali-local' -n istio-system
```
然后查看一下kiali的本地端口号。
```
kubectl describe svc kiali-local -n istio-system
```
接着用浏览器打开kiali进入后你就可以看到我们应用调用微服务的网络拓扑图了。怎么样是不是很惊艳
<img src="https://static001.geekbang.org/resource/image/c8/7c/c86557779fd349ee8032a62d2bcfc57c.png" alt="">
Service Mesh可以协助我们处理应用和微服务网络的连接、保护、控制和观测问题。综上再次总结下Serverless的底层我们完全可以依赖Service Mesh来处理复杂的网络问题。
最后演示完我们就可以通过kubectl delete清除刚刚部署的应用注意要在istio-myapp目录下执行。
```
kubectl delete -f .
```
到这儿部署好Istio Service MeshServerless的底层部署我们就已经实现了一大半。
## Serverless完整实现K8s组件Knative
现在就还剩最后一步安装组件了。如果你能想到在Service Mesh的底座上还需要加上哪些组件才能满足我们Serverless的需求说明你已经真正地理解了K8s的组件Component的威力了。
接下来我们就基于Istio看看Serverless在K8s的架构方案上还需要添加哪些内容。
Knative是通过整合工作负载管理和动态扩缩以及事件模型来实现的Serverless标准也叫容器化Serverless。
Knative社区的主要贡献者有Google、Pivotal、IBM、Red Hat可见其阵容强大。还有CloudFoundry、OpenShift这些PaaS提供商都在积极地参与Knative的建设。参考资料中我还放了“由阿里云提供Knative”的[电子书](https://github.com/cloudnativeapp/meetup/blob/master/Knative%20%E4%BA%91%E5%8E%9F%E7%94%9F%E5%BA%94%E7%94%A8%E5%BC%80%E5%8F%91%E6%8C%87%E5%8D%97.pdf),这里作为福利送给你。
接下来我们看看Knative是怎么做到Serverless的吧。
Knative在Istio的基础上加上了流量管控和灰度发布能力、路由Route控制、版本Revision快照和自动扩缩容就组成了Server集合它还将触发器、发布管道Pipeline结合起来组成了Event集合。
<img src="https://static001.geekbang.org/resource/image/f9/3d/f963da41d4c978542e685e74c9c5903d.png" alt="">
我们近几节课都有操作K8s其实你应该能感觉到它还是有些复杂的。Knative提供的应用托管服务可以大大降低直接操作K8s资源的复杂度和风险提升应用的迭代和服务交付效率。
我们还是以“待办任务”Web服务为例看看Knative是怎么做到的吧。
首先进入项目install-knative目录执行kubectl apply安装Knative。
```
kubectl apply -f .
```
安装完毕你就可以通过命名空间knative-eventing和knative-serving看到我们都安装了哪些组件。
```
kubectl get all -n knative-serving
kubectl get all -n knative-eventing
```
Knative帮我们部署了一套自动运维托管应用的服务因此我们要部署应用才能看到效果。我们再进入项目knative-myapp目录执行kubectl apply。
```
kubectl apply -f .
```
到这我们的应用就部署起来了。要访问应用也比Istio要简单通过get kservice我们就可以查看部署的应用域名。
```
kubectl get ksvc
```
这个域名其实是通过Istio-ingress部署的我们再看看Istio-ingressgateway的信息。
```
kubectl get svc istio-ingressgateway -n istio-system
```
<img src="https://static001.geekbang.org/resource/image/84/90/84bacc4deff3166b7a444dc5bec12590.png" alt="">
我们可以看到它绑定到我们本地IP:localhost上了所以我们只需要添加一下Host绑定我们MyApp的域名到127.0.0.1就可以了。
```
// Mac上host文件地址是/etc/hosts
127.0.0.1 myapp.default.example.com
```
然后我们就可以用浏览器直接访问我们的域名myapp.default.example.com进入“待办任务”Web服务了。如果你多刷新几次页面就可以看到右上角我的名字有时是“秦粤”有时是“粤秦D”。这其实是因为我的user服务开启了2个版本而且我设置了50%的流量进入版本v150%的流量进入版本v2。另外我们还需要在页面上多点击几下这是为了让我们查看Kiali的网络拓扑图时有数据。
目前Knative还没有官方的控制台所以最后我们再看看Istio中Kiali的网络拓扑图如果忘记了如何访问Kiali请看上一节介绍Istio中的内容。
<img src="https://static001.geekbang.org/resource/image/7f/26/7f2b922b186b38f4eb324967b094de26.png" alt="">
你看网络拓扑图是不是变得更复杂了当然因为Knative也是隐藏了一堆的内容来简化应用和微服务的部署。好了实践完我们就再来看看原理请看下图
<img src="https://static001.geekbang.org/resource/image/f4/1f/f4a79ce34e82d0f72cf5a0ed3153e81f.png" alt="">
我来解释下这张图。为了让你更好地识别我用红色表示Knative添加的组件橙色表示Istio的组件。首先我们看到Knative又给每个Pod里面添加了一个伴生容器queue它是专门用来实时采集反馈我们部署应用容器的监控指标metrics的收集到的信息会反馈到autoscale由autoscale决定是否需要扩缩容。
然后我们看看请求从上面的操作我们知道浏览器的HTTP请求是访问Istio-ingressGateway的我们还需要绑定域名。这是因为Istio-ingressGateway是域名网关它会验证请求的域名。我们的MyApp应用接收到请求会调用用户微服务和待办任务微服务这时就会访问activator了这个是Knative比较重要的组件它会hold住我们的请求并查看一下目前有没有活跃的服务如果没有它会负责拉起一个服务等服务启动后再将请求转接过去。这也就是为什么Serverless可以缩容到0的原因。
另外我再啰嗦一下当我们的autoscale配置了可以缩容到0如果一段时间没有请求那么我们每个应用都会处于很低的水位这时autoscale就会缩容到0了。当然我们的MyApp应用不可以缩容到0因为它需要接收入口请求。
当MyApp有流量进来请求用户服务时此时activator就会临时接收请求让请求等待然后通知autoscale扩容到1等待autoscale扩容到1完毕后activator再让用户容器处理等待的请求。
而我们在Knative中每次发布服务都会被Revision组件拍一个快照这个快照可以用于我们管理版本号和灰度流量分配。我们“待办任务”Web服务中的用户微服务的2个版本流量切换其实就是利用Revision和Route实现的。
## 总结
这节课我首先介绍了Service Mesh。Service Mesh通过Pod给我们的应用容器注入了一个伴生容器Sidecar配合控制面板来接管我们应用和微服务的网络流量从而实现网络流量的连接、保护、控制和观测。
接着我介绍了CNCF的另一位重要成员Istio它是基于K8s组件实现的Service Mesh。我们在Istio的基础上又搭建了Knative它也是基于K8s组件实现的一套Serverless方案。
总结来说就是Service Mesh是一种微服务网络通讯方案它通过Sidecar和控制面板接管了上层的网络通讯可以让上层开发者无感知地使用网络通讯。我们可以复用Service Mesh的网络通讯能力部署Serverless架构。通过Service Mesh、Serverless组件和K8s集群复杂且精密地配合支撑我们部署的应用Serverless化。
另外我需要提醒你一下Knative是容器Serverless方案所以你在容器里面运行函数、微服务或者应用都可以这完全取决于你的Dockerfile里面“编排”的是什么内容。我们这节课介绍的Knative可以让你既部署FaaS也部署BaaS。还记得我们[[第1课]](https://time.geekbang.org/column/article/224559) 讲过FaaS和BaaS都是基于CaaS实现的Knative正是一种容器服务Serverless化的产物。我们将[第 1 课]和这节课的架构图映射一下相信你对Serverless的实现会有新的体会。
<img src="https://static001.geekbang.org/resource/image/77/64/7771e2621ac14fddad00657a1909c564.jpg" alt="">
## 作业
这节课是实战课所以作业就是我们今天课程中的内容。请在上节课安装的K8s集群的基础上先安装Istio组件部署Istio版本的“待办任务”Web服务再安装Knative组件部署Knative版本的“待办任务”Web服务。实践结束后你可以在Docker Desktop中关闭K8s集群这样就能清掉我们这两节课创建的所有资源了。
大胆尝试一下吧,期待你能与大家分享成果。如果今天的内容让你有所收获,也欢迎你把文章分享给更多的朋友。
## 参考资料
[1] [https://istio.io/](https://istio.io/)

View File

@@ -0,0 +1,158 @@
<audio id="audio" title="10 | 经验Serverless架构应该如何选型" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/53/0a/531db92429abb485932dce72ce709c0a.mp3"></audio>
你好我是秦粤。通过前面的两节实践课我们体验了在本地环境中搭建K8s并且我们利用K8s的组件扩展能力在本地的K8s上安装了Istio和Knative。正如我在前面课程中所说的K8s可以让我们的集群架构轻松迁移到其他集群上那么今天我就带你将我们本地K8上部署的“待办任务”Web服务部署到云上的K8s集群。
实践课里还有这么个小细节不知道你注意没我们使用Knative时应用和微服务部署都需要关心项目应用中的Dockerfile而我在使用FaaS函数时连Dockerfile都不用管了其实这就是Serverless带来的变革之一。当然现在有很多应用托管PaaS平台也做了Serverless化让我们部署一个应用时只需要关心Release分支的代码合并例如Heroku、SAE等等。
这里我需要先解释一下K8s集群的运维工作对于很多个人开发者来说是有些重的。我们通常了解基本知识用kubectl调用K8s集群就可以了。咱们课程里我是为了让你更好理解Serverless的工作原理所以才向你介绍Knative在K8s上的搭建和使用过程。
实际工作中K8s集群的运维还是应该交给专业的运维人员。另外云服务商的K8s集群都会提供控制面板一键安装组件。我们在使用Serverless的部署应用时不用关心底层“被透明化”的类似Knative、Istio等等插件能力这也是Serverless应用的价值所在虽然它本身的底层构建在复杂且精密的各种服务上但我们使用Serverless却极其精简。
在开始部署K8s上云之前我们要先选择一个云服务商。正如我们上节课所说K8s整体架构迁移能力可以帮我们破解Vendor-lock只要我们部署的云服务商是CNCF的成员支持K8s集群就可以了。实际上目前几乎所有的云服务商都加入了CNCF阵营。因此我们的K8s版本的“待办任务”Web服务可以任意选择云服务商部署你完全可以横向对比云服务商的各项指标去选择适合自己的。当我们有了选择权也反向促进了云服务商的良性竞争。
## 云服务商
我们先看看2019年的[全球云服务商的市场占有率](https://www.canalys.com/newsroom/canalys-worldwide-cloud-infrastructure-Q4-2019-and-full-year-2019)数据,我也将按照这个数据排名,依次向你介绍云服务商和他的主要特色:
1. 亚马逊的AWS市占率32.4%。亚马逊凭借庞大复杂的全球电商业务,让其机房做到了覆盖全球,并引领云服务的发展,提供最全面的生态和最高稳定性的服务。云服务商老大的地位近年内都难以撼动。
1. 微软的Azure市占率17.6%。依赖微软Windows全家桶的优势和近年的JavaScrpit技术社区的收购或者并购他的市场地位紧跟亚马逊之后。整体云服务产品的报价也紧盯AWS所有服务价格略低于AWS。
1. 阿里巴巴的阿里云市占率6.0%。国内市场占有率第一,随着阿里电商业务出海,阿里云机房也部署到了海外。在国内云里生态建设得比较完备,每年都经受双十一流量的洗礼,不断打磨稳定性。客服响应速度是一大亮点。
1. 谷歌的谷歌云市场占有率5.4%。谷歌是后起之秀凭借15年提出CNCF云原生白皮书通过建立规范和开源生态迅速切入云服务领域并占有一席之地。价格策略上紧盯AWS并依靠Google的搜索引擎对大规模集群调度能力的积累。云服务商中最高的物理机资源利用率让谷歌云的价格做到了云服务商中的最低。
1. 其他云市场占有率38.5%。腾讯云、华为云等其他的云服务商都归并到了这里还有一些专门做专有云服务的比如CDN全球加速的AkamaiPaaS应用托管的Heroku等等。值得一提的是腾讯云腾讯云从2019年开始大力发展Serverless并积极和Serverless生态合作估计是希望以此为突破点提升自己的市场占有率。
下面是我按我目前(注意只是目前)掌握的数据和认知整理的表格,在选择云服务商时你可以作为参考。其中访问限制应该是最优先考虑的,国内运营部署的应用,肯定是要首选国内云服务商。
<img src="https://static001.geekbang.org/resource/image/d3/63/d3f31145aa72d7390db032b81b947663.png" alt="">
当我们完成云服务商的选择后理论上我们可以通过Docker容器创建我们所需要的各种服务例如Redis、MySQL、Kafka等等。具体怎么做你应该很熟悉了先去Docker Hub 官网找到我们所需要的服务镜像在这个镜像的基础上加上我们自己的用户名和密码生成私有Docker镜像上传到我们的Registry然后在K8s集群中就可以部署了。这也是前面我们讲到的Docker容器带来的颠覆式体验。
不过我们在重度使用Docker技术的同时也必须深入了解Docker和我们所用的具体镜像的限制。比如如何解决应用镜像硬盘持久化的问题、如何解决MySQL镜像的容器扩缩容的问题、Kafka镜像集群如何搭建等等。这些都是新技术引入的新的问题而且解决方案和传统运维虚拟机也不一样。
另外为了提升我们的研发效能我们还应该进一步了解云服务商还能为我们提供哪些能力节省我们的时间和成本。当我们开发一个云上项目时云服务商已经为我们准备了各种行业解决方案来提升我们的开发速度例如文件存储服务、视频媒体流转码服务、物联网MQTT解决方案等等。利用这些服务和我们前面讲的服务编排可以进一步加速我们的研发速度。
## 云服务如何选型?
现在云服务商都提供数以百计的各种服务但大体上我们可以分为以下3类IaaS、PaaS和SaaS。
<img src="https://static001.geekbang.org/resource/image/af/42/af06bd8f061823956d558be91b446442.png" alt="">
我们先看看图示中的金字塔这里我需要引入新的概念服务级别协议SLA服务提供商与受服务用户之间具体达成了承诺的服务指标——质量、可用性、责任。看上去有些绕简单来说就是服务不达标我们可以向云服务商索赔损失。
我们前面课程中所说的消息队列的稳定性达到10个9其实就是指SLA指标数据可靠性为99.99999999%但是消息队列的服务可用性其实是99.95%也就是说消息队列服务服务一年中不可使用时间为4.38小时,一旦不可用时间超过了这个要求,云服务商则需要向客户赔付(如果这部分知识你没接触过的话,可以看下赵成老师的[这篇文章](https://time.geekbang.org/column/article/212722))。
因此对于云服务商来说要维持资源的高可用性必须保证资源调度及时宁可浪费部分资源也不能牺牲用户的可用性。而云服务的价格则和物理机虚拟化比例强相关虚拟化比例越低说明你对这个资源独占性越高当然价格也就越高。物理机虚拟化比例也是云服务商的资源调度能力对云服务商来说核心指标就是CPU利用率。
了解了一些前提接下来我们具体看看这3类。
- IaaS层是面向运维人员服务器或虚拟机服务。可用性也最高通常可以到4个999.99%。可控性高虚拟机从操作系统开始你可以登录虚拟机并且任意安装各种自己所需的函数库和二进制包。资源的物理机虚拟化比例通常是2:1的性能是最稳定的。
- PaaS层是面向开发者通常部署在IaaS层之上服务种类最为繁多。可用性低于IaaS通常是99.95%。可控性中等PaaS通常都提供特定的服务例如应用托管、数据库等等我们只能通过提供的控制台登录。资源的物理机虚拟化比例通常是4:1性能较稳定。
- SaaS层是面向终端用户通常部署在PaaS层之上。可用性低于PaaS通常是99.9%。可控性低SaaS直接面向用户提供服务我们只能登录后台操作部分数据进行增删改查。资源的物理机虚拟化比例不太确定但肯定超过8:1性能一般。
FaaS则是一个特例虽然它也属于面向开发者的但利用FaaS极速的冷启动特性它并不需要关心底层的高可用性。反而用它可以填满闲置的机器资源提升物理机的资源利用率。这也是为什么在云服务商这么高的运作成本下FaaS还能免费提供给大家使用。
<img src="https://static001.geekbang.org/resource/image/41/9b/4162456b4550db3be9be6daead865d9b.png" alt="">
我介绍SLA主要是希望你能对云服务商提供的服务层级有个认识。我们在设计和运维自己的应用时需要综合考虑到可用性和价格。FaaS是性价比最高的所以我们在日常使用时如果有适合FaaS的场景应该尽可能地使用FaaS。
如果要深入了解云服务我的经验是可以从云服务商网站的行业解决方案出发。先粗略了解一下有哪些行业解决方案便于我们掌握云服务商的能力边界。如果感觉比较凌乱的话最好自己用“脑图”梳理一次。另外再说句题外话我不建议你学习别人的脑图因为脑图都是自己梳理思考的过程你自己大脑的Map不一定适合别人别人的Map也不适合你。
言归正传我们自己在云上搭建K8s集群主要有2种方式购买虚拟机自建和购买K8s集群。当然首推购买K8s集群可以节省我们更多成本。K8s集群的Master节点阿里云K8s集群是不收费的而我们自己搭建则需要至少一台虚拟机。虚拟机自建比较适合大型或拥有强大运维团队的互联网公司。但无论是自建还是购买K8s集群我们搭建的K8s集群的底层都是IaaS。
## 云上部署K8s集群Knative
了解完选型相关的知识,接下来我们还是动手实操一下。
我们这节课的K8s例子选择了阿里云的Serverless K8s集群ASK。这个K8s集群的特点是Master节点是免费的只收取网关的费用Worker节点是虚拟节点而我们Pod中的容器是通过ECI容器创建的。传统的K8s集群ACK的Worker节点需要我们自己购买虚拟机授权K8s集群初始化成Worker节点。ECI是轻量级的Docker容器同时具备高性能和低价格的优势。另外ASK的Knative功能是新上线公测的推荐它还是因为性价比。
我们使用K8s集群同样可以自己安装Istio再安装Knative只需要注意K8s集群的版本就可以了。但云服务商提供的K8s集群通常都已经帮你准备好了控制台操作。所以实际上我们使用云端的K8s集群要比本地搭建还要简单。所以我们只需要在ASK控制台左边Knative公测中选择我们的K8s集群点击“一键部署”就可以了。当然如果你选择的云服务商不支持“一键部署”你可以通过查看K8s集群的版本号选择对应的Istio版本和Knative版本按照我们上节课所讲的内容自行安装K8s组件。
另外为了方便新手我还是需要提示一下如何在本地同时管理多个K8s集群。
首先我们打开本地的kubectl的配置文件$HOME/.kube/config我们可以看到这个K8s集群的配置文件主要分为3个部分clusters、contexts、users。
```
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: xxx
server: https://kubernetes.docker.internal:6443
name: docker-desktop
- cluster:
certificate-authority-data: xxx
server: https://k8s集群IP:6443
name: kubernetes
contexts:
- context:
cluster: docker-desktop
user: docker-desktop
name: docker-desktop
- context:
cluster: kubernetes-ask
user: kubernetes-ask-admin
name: kubernetes-admin-id
current-context: docker-desktop
kind: Config
preferences: {}
users:
- name: docker-desktop
user:
client-certificate-data: xxx
client-key-data: xxx
- name: kubernetes-admin
user:
client-certificate-data: xxx
client-key-data: xxx
```
我们将云上K8s给我们提供的集群凭据的cluster、context、user分别添加到config文件对应的clusters、contexts、users部分下面就可以了。
我们再次查看kubectl config get contexts就可以看到新添加的云上K8s集群了。
```
kubectl config get-contexts
```
剩下的操作就跟我们上节课保持一致了。我们只需要在knative-myapp里面执行kubectl apply就可以让我们的例子运行在云上的K8s集群了。
我们想访问云上K8s集群版本的“待办任务”Web服务时同样也是用kubectl查看kservice我们的域名。
```
kubectl get kservice
```
<img src="https://static001.geekbang.org/resource/image/d3/20/d3810957c110ba84a71085d20a510820.png" alt="">
紧接着通过查看ingress-gateway了解K8s集群的外网入口IP。
```
kubectl get svc -n knative-serving
```
<img src="https://static001.geekbang.org/resource/image/3c/b2/3cdd4a0a5affe9724a7c15755aa7beb2.png" alt="">
我们在本地通过Host绑定域名和EXTERNAL-IP就可以访问了。我再啰嗦一句如果是你自己的域名你可以通过修改域名的DNS解析A值指向这个EXTERNAL-IP就可以了。
<img src="https://static001.geekbang.org/resource/image/e6/55/e6d014f06a7a6047fef335052372b555.png" alt="">
我们同样也可以通过命名空间namespace看看这个K8s集群中都给我们安装了哪些组件。还记得我们讲过的FaaS的HTTP触发器认证方式吗我们部署在云上的K8s集群调用我们的FaaS函数就可以通过我们自己的容器实现函数鉴权的算法走函数鉴权流程了。
到这儿云上部署K8s集群Knative这个例子我们就实践完了不知道你有没有跟着我一起动手操作最后还有一点需要提示你一下如果你为了体验我们这节课的内容在云上自己购买了K8s集群测试那等部署完成后云上的K8s集群你一定要清理干净了除了通过kubectl delete清除我们部署的应用还要在云上删除K8s集群和worker节点否则还会持续产生费用。
## 总结
这节课我们学习了如何让本地的Knative应用打破云服务商的锁定部署上云。因为CNCF的K8s集群的可移植性我们可以在CNCF的云服务商成员中任意选择。我根据我自己的经验总结了一份云服务商的对比表格这个表格的内容对比了我们自身业务的特点还有价格等因素让我们自由选择适合自己的云服务商。
我们在云上创建好K8s集群使用K8s集群就跟我们本地使用是一样的而且很多云服务商还提供“一键部署”让我们快速安装K8s组件。最后我们就可以将Knative的应用部署上云了。
然而我们虽然可以用Knative解决Container Serverless的云服务商锁但却无法解决云服务商用FaaS构建起的新壁垒。每个云服务商FaaS的Runtime都不一样我们的函数代码要兼容多个云服务商部署要写很多额外的代码处理兼容性的问题。那么下节课我们就再看看如何破解FaaS的新Vendor-lock。
## 作业
这节课建议你创建一个云上的K8s集群并且将我们上节课的内容部署到云上的K8s集群。感受一下云上的K8s如何打通部署和提供给互联网用户访问。
期待你的实践总结,欢迎留言与我交流。如果今天的内容让你有所收获,也欢迎你把文章分享给更多的朋友。

View File

@@ -0,0 +1,222 @@
<audio id="audio" title="11 | 经验Serverless开发最佳实践" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/b5/02/b5748378ca4f1036894f1df5c7bf0702.mp3"></audio>
你好我是秦粤。上节课我们了解了利用K8s集群的迁移和扩展能力可以解决云服务商锁定的问题。我们还横向对比了各大云服务商的特点和优势纵向梳理了云服务商提供的各种服务能力。最后我们可以看到利用Knative提供的Container Serverless能力我们可以任意迁移部署我们的应用架构选择适合我们的云服务商。
但同时我们也发现FaaS相对于Knative反而是我们的瓶颈我们无法平滑地迁移FaaS的函数。云服务商大力发展FaaS其实部分原因也是看中了FaaS新建立起来的Vendor-lock因此目前各大运营商都在拼FaaS的体验和生态建设。
那这节课我们就来看看FaaS是如何解除云服务商锁定的吧。但在正式开始之前呢我们先得了解一些FaaS的使用场景以免一些同学误会要是你的实践是为了Serverless而去Serverless那就不好了我们还是应该从技术应用的角度出发。
## FaaS场景
我从[[第5课]](https://time.geekbang.org/column/article/229905) 开始就在讲FaaS和BaaS的底层实现原理Container Serverless是希望通过底层实现原理帮助你更好地掌握Serverless的思想。但在日常工作中使用Serverless只需要借助云服务商提供的Serverless化的FaaS和BaaS服务就可以了。
就像我上节课中所讲的FaaS因为可以帮助云服务商利用碎片化的物理机算力所以它是最便宜的。在日常工作中我十分鼓励你去使用FaaS。
那么说到使用FaaS以我的经验来说我们可以将FaaS的最佳使用场景分为2种事件响应和Serverless应用。
### FaaS事件响应
FaaS最擅长的还是处理事件响应所以我们应该先了解清楚你选择的云服务商的FaaS函数具体支持哪些触发器例如阿里云的触发器列表[1]、腾讯云的触发器列表[2]。因为这些触发器通常都是云服务商根据自身Serverless的成功案例所制定的下沉方案也就是说这些触发器都具备完整的使用场景。基于FaaS支持的触发器设计事件响应函数我们就可以最大限度地享受FaaS的红利而且不用担心用法不正确。
### Serverless应用
那如果FaaS是作为Serverless应用的使用场景我们则需要关注大型互联网公司的成功案例所沉淀出来的成熟方案。这样既可以轻松简单地搭建出Serverless应用还能帮我们节省不少费用。
因为我们尝试用FaaS去解构自己的整个应用时如果超出了目前FaaS的适应边界那么技术挑战还是比较大的。所以我并不推荐你将整个现存的应用完全Serverless化而是应该去找出适用FaaS事件响应的场景去使用FaaS。
如果你关注Serverless就不难发现至少目前它还处在发展阶段很多解决方案还在摸索之中。大厂具备技术实力也乐于在拓展Serverless边界的同时发现痛点、解决痛点并占领技术高地。那如果你是一般用户最好的选择还是持续关注Serverless动向及时了解哪些方案可以为自己所用。当然这是Serverless的舒适圈但技术挑战也意味着机遇我确实也看到有不少同学因为拓展Serverless的边界而被吸收进入大厂去参与Serverless共建。
## FaaS痛点
以上就是我对FaaS应用场景的一些看法和建议。虽然FaaS最擅长是事件响应但是如果可以改造Serverless应用无疑FaaS的附加值会更高。接下来我们就看看FaaS在Serverless应用过程中切实存在的痛点相信随着课程一路跟下来的同学一定深有体会。
- 首先,调试困难,我们每次在本地修改和线上运行的函数都无法保持一致,而且线上的报错也很奇怪,常见的错误都是超时、内存不足等等,让我们根本无法用这些信息去定位问题。
- 其次部署麻烦每次改动都要压缩上传代码包而且因为每个云服务商的函数Runtime不一致导致我们也很难兼容多云服务商。
- 最后,很多问题客服无法跟进,需要自己到处打听。
但如果你有仔细阅读文档的话,你就会发现各大云服务商都会提供命令行调试工具,例如阿里云提供的"fun"工具[3]、腾讯云合作的Serverless Framework等等。不过云服务商提供的工具都是云服务商锁定的。为了破解FaaS的新Vendor-lock我从目前热门的Serverless社区中选择了3个Serverless应用框架和1个平台介绍给你帮助你破解Vendor-lock同时也能更好地解决痛点。
## Serverless应用框架
### Serverless Framework [4]
Serverless框架作为第一款支持跨云服务商的Serverless应用解决方案一旦进入首页我们就可以看到Serverless X Tencent Cloud。其实最早的Serverless框架官方例子是AWS的不过从去年开始被腾讯云强势入驻了。正如我上节课中所讲腾讯云将Serverless作为切入云服务商市场的突破口正在大力推进Serverless腾讯云的生态建设。
Serverless框架具备先发优势而且已经有很多成熟的应用方案我们可以直接拿来使用。我们可以通过Serverless Component用yaml文件编排整个Serverless应用架构。
另外Serverless Framework也支持将应用部署到其他ProviderAWS、阿里云、Azure还有Knative等等正如以下图示。不过这里有个小问题就是我们只有在[英文版Serverless框架的官网](https://www.serverless.com/framework/docs/providers/)上才能看到其他云服务商的Provider和文档介绍[中文版Serverless框架官网](https://www.serverless.com/cn)一并给出)。
<img src="https://static001.geekbang.org/resource/image/8b/19/8b389343945134f7a0782ae1eb2d6919.jpg" alt="">
Serverless Framework官方本身主要解决跨云服务商Serverless应用的部署运维问题。它利用类似K8s组件Component的概念让开发者可以自己开发并且共享组件。通过组件来支持多语言的模板而且Serverless组件的扩展能力还让Serverless框架具备生态优势。
目前Serverless的确是前端参与的比较多因此在Serverless应用框架中除了Node.js外其他语言的选择并不多。下面我就再介绍2款Node.js新的Serverless框架。
### Malagu [5]
Malagu是基于 TypeScript 的 Serverless First、可扩展和组件化的应用框架。为了提升Serverless的开发体验只专注Node.js Serverless应用。
首先Malagu的理念是支持前后端一体化基于JSON RPC前端像调用本地方法一样调用后端方法。前后端支持RPC和MVC两种通信形式MVC可以满足传统纯后端Rest风格接口的开发。
其次Malagu框架本身也是基于组件化实现的将复杂的大型项目拆解成一个个Malagu组件可以提高代码的复用能力、降低代码的维护难度。
最后,命令行工具插件化,默认提供初始化、运行、构建、部署能力,通过插件可以扩展命令行的能力。
我有幸与Malagu的开发者共事过Malagu汲取了众家所长我觉得这是一个值得关注的Serverless框架。而且目前Malagu已经有很多合作伙伴他们正在积极使用和推广Malagu的解决方案。
### Midway FaaS [6]
接着是我今天想给你介绍的重点就是Midway Faas和它的工具链"f"。Midway FaaS 是用于构建 Node.js 云函数的 Serverless 框架,可以帮助你在云原生时代大幅降低维护成本,更专注于产品研发。
Midway FaaS诞生于Node.js老牌框架Midway我也有幸与Midway的开发者一起共事过。Midway FaaS 是阿里巴巴集团发起的开源项目,由一个专业的 Node.js 架构团队进行维护。目前已大规模应用于阿里集团各 BU 线上业务,稳定承载了数千万的流量。
Midway FaaS有这样一些特点也可以说是特色。
- **跨云厂商:**一份代码可在多个云平台间快速部署,不用担心你的产品会被云厂商所绑定。
- **代码复用:**通过框架的依赖注入能力,让每一部分逻辑单元都天然可复用,可以快速方便地组合以生成复杂的应用。
- **传统迁移:**通过框架的运行时扩展能力让Egg.js 、Koa、Express.js等传统应用无缝迁移至各云厂商的云函数。
我们的“待办任务”Web服务也将采用这个方案进行重构。
首先,我们通过命令行全局安装工具链"f"。
```
npm install -g @midwayjs/faas-cli
```
然后,拉取我们最新的[lesson11代码分支](https://github.com/pusongyang/todolist-backend/tree/lesson11)注意这个分支跟之前的分支相比改动比较大。因此我们需要重新安装NPM依赖包。
```
npm install
```
前端代码还是在public目录后端代码在src目录项目里面的代码逻辑也比较简单你可以自己看一下。我们需要讲解的是比较核心的配置文件f.yml这里有我放的f.yml的文件结构。
```
service: fc-qinyue-test
provider:
name: aliyun
runtime: nodejs10
functions:
index:
handler: index.handler
events:
- http:
path: /*
getUser:
handler: user.get
events:
- http:
path: /user/234534
method: get
package:
include:
- public/*
aggregation:
agg-demo-all:
deployOrigin: false
functions:
- index
- getUser
custom:
customDomain:
domainName: lesson11-ali.jike-serverless.online
```
这里我们主要关注的是Provider目前Midway FaaS支持阿里云和腾讯云后续还会陆续增加其他云服务商。我们切换云服务商只需要修改Provider就可以了。其次你也可以看到Functions部分我们定义了所有的入口函数和路径path的映射关系。最后我们在部署环节自己指定了域名。我们在配置域名解析时根据云服务商提供的方式通常都是修改域名的CNAME指向云服务提供的FaaS地址就可以了。
Midway FaaS的强大之处就在于我们可以借助它提供的工具链"f"根据我们的f.yml文件配置内容从而直接在本地模拟云上事件触发调试我们的应用。
这里你只需要执行:
```
f invoke -p
```
我们就可以通过浏览器访问:[http://127.0.0.1:3000](http://127.0.0.1:3000) 调试我们的FaaS函数代码了。并且因为执行就在我们本地所以调试时我们可以借助现代IDE提供的Node.js debug能力逐行调试。而我们部署时也只需要一行代码
```
f deploy
```
然后Midway FaaS就会根据我们的f.yml文件配置内容帮我们部署到云上。
下面这2个URL地址就是我用Midway FaaS分别部署在阿里云和腾讯云上的“待办任务”Web服务。
阿里云“待办任务”Web服务[http://lesson11-ali.jike-serverless.online/](http://lesson11-ali.jike-serverless.online/)
腾讯云“待办任务”Web服务[http://lesson11-tx.jike-serverless.online/](http://lesson11-tx.jike-serverless.online/)
这里我需要提醒你一下这2个云服务都是以阿里云的OTS服务作为数据库存储。这也是FaaS服务编排的强大之处现在有些云服务商提供的BaaS服务是支持其他云服务商通过ak/sk访问的。另外如下图所示如果我们采用ak/sk编排云服务商的HTTP API服务那么利用FaaS就可以实现混合云编排服务了。
<img src="https://static001.geekbang.org/resource/image/62/37/623069c983b6359bd5418ee1f35cc337.jpg" alt="">
如果你留意过GitHub你会发现Midway FaaS和Malagu都是非常新的GitHub仓库。Serverless作为一门新兴技术还有非常大的想象空间。
另外阿里云也推出了自己的云开发平台而且将Serverless应用的生态集成了进去。目前Midway FaaS和Malagu也都在其中作为应用创建模板供你使用。
### 阿里云开发平台 [7]
阿里云开发平台就是由咱们专栏特别放送中的被采访者,杜欢(笔名风驰)负责的。
他的核心理念呢就是将大厂成熟的Serverless应用场景抽象成解决方案并且透出到云开发平台上来为各个中小企业和个人开发者赋能。
正如下图所示云开发平台是将大厂的行业应用场景沉淀成了解决方案解析生成Serverless架构这样我们就可以把云开发平台上实例化的“解决方案”快速应用到我们的Serverless应用中来。基于成熟Serverless的应用“反序列化”快速沉淀为解决方案这也是云服务平台会收录Midway FaaS和Malagu的原因。
而且我相信以后还会有更多的Serverless应用解决方案被收录到云开发平台中的。另外阿里云开发平台并不限制开发语言但截止到咱们这节课的发布时间阿里云开发平台的模板仅支持Node.js和Java的Serverless应用其它语言还需要等成功案例沉淀。
<img src="https://static001.geekbang.org/resource/image/bd/06/bd7cfa2c4711ad7c0533d5a198323306.jpg" alt="">
## 总结
这节课我向你介绍了如何打破FaaS的Vendor-lock并且介绍了我经验中FaaS的最佳使用场景事件响应和Serverless应用。事件响应无疑就是FaaS的最佳使用场景而Serverless应用则需要我们在云服务商提供的FaaS服务上利用我们专栏前面学习到的知识和原理挑战将完整的应用完全Serverless化。
为了解决FaaS的痛点和云服务商锁定我向你介绍了3个框架和一个平台。
- 目前由腾讯云主导的Serverless Framework它支持多语言具备组件扩展性。目前仅在英文版官网可以看到其支持的云服务商Provider文档。
- 由阿里云FC团队主导的Malagu解决方案目前仅支持Node.js同样具备扩展性。目前正在积极的和很多开发团队合作共建Serverless应用生态。
- 由阿里巴巴Node.js框架Midway团队主导的Midway FaaS解决方案它仅支持Node.js扩展性由Midway团队官方保障。Midway团队的社区响应迅速很多GitHub上的issue会在第一时间响应。
- 由阿里云主导的阿里云开发平台它支持多语言具备模板扩展性扩展性由官方提供的模板保障。目前收录了Serverless生态比较成熟的方案可以快速部署到阿里云FC上。虽然开发平台有一定的云服务商锁定嫌疑但其采用的模板却可以支持解除云服务商锁定例如Midway FaaS。
作为本专栏的最后一课我还想再啰嗦一句。Serverless确实是一门新兴技术其未来无限可能接下来该由你探索了
>
<p>想要我的财宝吗?想要的话就给你,去找出来吧,这世上所有的一切都放在那里。<br>
世界吗?没错!去追求自由。<br>
去超越吧!在信念的旗帜的带领下。</p>
—— 海贼王 罗杰
## 作业
Serverless技术实践还是很重要的最后一节课的作业我们就继续实操。请你将这节课“待办任务”Web服务的Midway FaaS版本在本地调试运行起来并且通过 `f deploy` 把它部署到阿里云或者腾讯云上。
期待你的成果,有问题欢迎随时留言与我交流。如果今天的内容让你有所收获,也欢迎你把文章分享给更多的朋友。
## 参考资料
[1] [https://help.aliyun.com/document_detail/74707.html](https://help.aliyun.com/document_detail/74707.html?)
[2] [https://cloud.tencent.com/document/product/583/31927](https://cloud.tencent.com/document/product/583/31927)
[3] [https://help.aliyun.com/document_detail/140283.html](https://help.aliyun.com/document_detail/140283.html?)
[4] [https://www.serverless.com/cn/framework/docs/getting-started/](https://www.serverless.com/cn/framework/docs/getting-started/)
[5] [malagu框架项目地址](https://github.com/alibaba/malagu)[malagu框架详细文档](https://www.yuque.com/cellbang/malagu)
[6] [https://github.com/midwayjs/midway-faas](https://github.com/midwayjs/midway-faas)
[7] [https://workbench.aliyun.com/](https://workbench.aliyun.com/)