You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

267 lines
17 KiB
Markdown

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# 08 | 搭建私有ServerlessK8s和云原生CNCF
你好我是秦粤。上节课我们只是用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/)
2. 在阿里云的容器镜像服务里,找到镜像加速器,复制你的镜像加速器地址;
3. 打开桌面版Docker的控制台找到Docker Engine。
```
{
"registry-mirrors" : [
"https://你的加速地址.mirror.aliyuncs.com"
],
"debug" : true,
"experimental" : true
}
```
4. 预下载K8s所需要的所有镜像执行我目录下的docker-k8s-prefetch.sh如果你是Windows操作系统建议使用gitBash\[1\]
```
chmode +x docker-k8s-prefetch.sh
./docker-k8s-prefetch.sh
```
5. 上面拉取完运行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的原理图
![](https://static001.geekbang.org/resource/image/70/f8/7084735b118636816d1284a80e67d0f8.png)
通过图示我们可以知道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
```
![](https://static001.geekbang.org/resource/image/91/bc/910eae7773766239c81400991d4568bc.png)
如果不对,则需要执行切换集群:
```
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部署我的应用。具体如下图所示
![](https://static001.geekbang.org/resource/image/f9/31/f92f4b5abd24b1e25ea269d1c2528b31.png)
通过获取容器的运行状态对照上图我粗略地讲解一下我们的myapp.yaml文件吧。
* 首先我们指定要创建一个service/myapp它选中打了"app:myapp"标签的Pod集群内访问端口号3001并且暴露service的端口号30512。
* 然后我们创建了部署服务deployment.apps/myapp它负责保持我们的Pod数量恒久为1并且给Pod打上"app:myapp"的标签也就是负责我们的Pod持久化一旦Pod挂了部署服务就会重新拉起一个。
* 最后我们的容器服务申明了自己的Docker镜像是什么拉取镜像的secret以及需要什么资源。
现在我们再回看K8s的原理图不过这张是实现“待办任务”Web服务版本的
![](https://static001.geekbang.org/resource/image/a1/4c/a11f760ad9e3d8ba42da0d878a61a04c.png)
首先我们可以看出使用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隔离一定程度上隐藏了系统配置这可以避免我们误操作。另外它也提供给我们一种逻辑隔离手段将不同用途的服务和节点划分开来。
![](https://static001.geekbang.org/resource/image/fb/13/fb15835cb57a3e7d587aa2d401123213.png)
没错K8s自己的服务也是运行在自己的集群中的不过是通过命名空间将自己做了隔离。这里需要你注意的是这些服务我不建议你尝试去修改因为它们涉及到了K8s集群的稳定性但同时K8s集群本身也具备扩展性我们可以通过给K8s安装组件Component扩展K8s的能力。接下来我先向你介绍K8s中的性能指标metrics组件\[5\]。
我的代码根目录下已经准备好了metric组件的YAML文件你只需要执行安装就可以了
```
kubectl apply -f metrics-components.yaml
```
安装完后我们再看K8s的系统命名空间
![](https://static001.geekbang.org/resource/image/34/ff/34fe0c9268d5913607fd25464227efff.png)
对比你就能发现我们已经安装并启动了metrics-server。那么metrics组件有什么用呢我们执行下面的命令看看
```
kubectl top node
```
![](https://static001.geekbang.org/resource/image/f0/08/f0e5f436d48c47899ebcdf5045ed2a08.png)
安装metrics组件后它就可以将我们应用的监控指标metrics显示出来了。没错这里我们又可以用到上一讲的内容了。既然我们有了实时的监控指标那么我们就可以依赖这个指标来做我们的自动扩缩容了
```
kubectl autoscale deployment myapp --cpu-percent=30 --min=1 --max=3
```
上面这句话的意思就是添加一个自动扩缩容部署服务cpu水位是30%最小维持1个Pod最大维持3个Pod。执行完后我们就发现会多了一个部署服务。
```
kubectl get hpa
```
![](https://static001.geekbang.org/resource/image/56/2d/56a7a23302c7feabf3df14ae341bf52d.png)
接下来,我们就可以模拟压测了:
```
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实现的应用可以扛住的流量比较大单机模拟的压测轻易还压测不到扩容的水位。
![](https://static001.geekbang.org/resource/image/1e/76/1eaa1c830583326cb0bd5fa919270c76.png)
## 总结
这节课我向你介绍了云原生基金会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/)