转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具、解决方案和服务,赋能开发者。
在上节中,我们为大家介绍了 Pod 的基础内容,Kubernetes 如何站在上帝视角上处理容器和容器之间的关系。但仅仅有 Pod 却还不够,对于大部分用户而言如何调度和管理自己的应用才是真正核心的问题,而对这一内容的解决方案才是 Kubernetes 最终极大杀器。
让我们从一个例子出发,假设现在的用户需求是:
以 3 机负载均衡的形式部署一个私有云客户的活字格应用,应该如何实现呢?
在活字格公有云版开发组之前开发的版本中,实现方法大概是这样:使用三个不同的物理机,先把用户的应用 run 成容器,然后安装在在这三个物理机上,在三台服务器之外再买一个负载均衡服务,最后通过域名解析配置,将流量分别导向三个不同的服务机。
听起来似乎也挺简单的。
但是在现实中,我们会遇到考虑其他问题,比如: 如果我们只有两台服务器呢?如果有一台服务器中的 container 挂了呢?如果两台服务器 CPU 跑满了呢?
这些调度方面的内容看起来很简单,但是实现起来却需要长时间的编码和调试。而且一通输出之后,最终做出来也可能只是个 Docker Swarm 而已。
现在我们把上述需求看做是我们最终的目标,来看 kubernetes 是如何一步一步进行容器编排从而解决了这个问题。相信大家看完这部分内容之后,以上问题便会迎刃而解。
Kubernetes 所做的容器编排核心内容其实是 Pod 编排,如何让这些 Pod 配合起来协同工作,则是编排的核心。在上一节中我们一起了解了 kubernetes 所做的是将各种关系进行了抽象,这些关系本质其实是 Pod 之间的关系。kubernetes 将 Pod 的关系抽象成了以下几种,并且为这些关系定义了相对的控制器便于进行编排管理:
l 无状态 Pod 副本之间的协同关系——Deployment
l 有状态 Pod 副本之间的拓扑关系——StatefulSet
l 容器化守护进程——DaemonSet
l 离线业务——Job 和 CronJob
这些概念看起来可能让你有些不知所云,其实这些内容只是不同上述的控制器对 Pod 的不同的管理方式而已。
限于篇幅和对这部分内容的理解深度,这里我们将只分享活字格公有云版开发组中最多使用到 kubernetes 最常用的一种控制器——Deployment 。
我们先解释什么是控制器:控制器是 kubernetes 中管理待编排对象的程序,我们把一个对象管理另一个对象的模式称为控制器模式。
kubernetes 中的所有待编排对象都是通过控制器模式管理的。
其核心就是一个死循环,在循环中不停地判断当前编排对象的状态,如果不满足预期状态就更新它,如下的伪代码就是描述一个控制器的工作原理:
Deployment 控制器的功能是:维护多个相同的无状态 Pod 副本以规定的数量运行,并且支持水平扩展以及滚动更新。
有了这个控制,为了实现我们的最终需求——负载均衡中的活字格服务,这个 Pod 就可以通过 Deployment 管理。我们可以通过 Deployment 让我们的 Pod 在 kubernetes 集群中始终以 3 个副本的形式存在。
只需要用 Deployment 来编排我们定义的 Pod,并且要求副本数量是 3,Deployment 控制循环中就会不停地判断我们的 Pod 的副本数量是否是 3,如果不是,就会触发水平扩展功能进行调整,最终达到满足期望状态(副本数==3 )。
介绍了这么多,我们从实例出发为大家演示 Deployment 是如何工作的。
由于活字格的镜像配置过于复杂,因此这里我们通过一个 Nginx 的多副本配置来感受一下 Deployment 控制器的控制结果。
我们可以通过以下 yaml 定义一个维护了 3 个 nginx 副本的 deployment: 其实 Kubernetes 在最初的版本中只有 ReplicaSet 这种控制器模式,控制的是多副本 Pod 编排逻辑,后来出现了滚动更新逻辑,为了解决滚动更新的需求,在 ReplicaSet 基础上扩展出了 Deployment 。
apiVersion: apps/v1
kind: Deployment
metadata:
name: sample-deployment-nginx
spec:
selector:
matchLabels:
app: sample-deployment-nginx
replicas: 3
template:
metadata:
labels:
app: sample-deployment-nginx
spec:
containers:
- name: sample-nginx
image: nginx:1.9.1
ports:
- containerPort: 80
这里出现了三个特殊字段:
1. selector:选择器,类似于 js 中的选择器,其功能就是选择指定的 pod 运行,这个实例中我们指定所有 app==sample-deployment-nginx 的 pod 才会被这个 Deployment 所部署
2. replicas:指明这个 Deployment 维护的副本个数
3. template:控制器中提供了 template 这个语法,可以让我们直接在控制器的 yaml 中直接编写所需要编排的 Pod 信息
编写完这个 sample-deployment-nginx.yaml 后,执行一下:
kubectl apply -f sample-deployment-nginx.yaml
这个三副本的控制器就被成功运行了,使用该指令查看运行结果:
kubectl get pods -l app=sample-deployment-nginx
可以看到 3 副本 Pod 已经成功在 kubernetes 中运行了
如果这时我们执行以下命令删除 podname==sample-deployment-nginx-54545f95cd-wtllm 的副本
kubectl delete pod sample-deployment-nginx-54545f95cd-wtllm
可以自动生成一个新的 pod 来维持 replicas==3:
通过上述实例,我们可以看到 Deployment 控制器对副本数量的控制结果,其实是 ReplicaSet 控制器在控制副本的数量。Deployment 是 ReplicaSet 控制器的控制器,这种多层之间相互控制的模式在 kubernetes 也十分常见,其之间的关系如下图所示:
至此,一个 deployment 管理 pod 的所有功能都已经展示完成了,可以看到 kubernetes 中控制器管理之间的精巧关系:多个控制器协同工作,既<del>能</del>保证精准控制,也能拆分进程阻塞从而提升性能。
当你理解了 deployment 控制器,就很容易理解其他控制器的工作原理。
在这里我们简单做个说明,为大家介绍其他控制器的控制逻辑:
l StatefulSet:控制满足有拓扑状态或者持久化存储的 Pod,拓扑状态的意思就是 Pod 之间存在明确的先后生成关系,持久化存储就是当副本被删除或者修改了,其内部保存的数据还会存在
l DaemonSet:守护进程控制器,是一个 Node (服务器节点)仅能存在一个的 Pod,比如系统的日志采集器等就应该用这种方式调度
l Job 与 CronJob:Job 就是任务调度,一个 Pod 在调度完成后就结束了不会再有新的任务产生,Job 用于维护一个任务 Pod 运行中的各种状态正常,异常状态重启等。对应的 CronJob 就是定时任务,使用过 Quartz 的同学一定不陌生
综上,kubernetes 中就是通过上述的各种控制器维护所有 Pod 的编排工作的,并且其还提供了完善的 API 可以让用户自行定义满足自己需求的各种 Pod 编排控制器。但是对于 deployment 本文只是简单的展示了一些常用的功能点,其内部还有滚动更新的最大资源、金丝雀发布和灰度发布等各种功能需要继续细致的学习。
本章中以活字格公有云为例,为大家介绍了 k8s 容器编排部分的实现。在下节中我们将继续为大家分享,为了实现这个终极需求的另一部分——如何实现 “人与狗的交往过程”。