基本介绍
首先展示一张简单的架构图,会发现所有的流程几乎都是是通过api server通信的。
在开始之前先区分一些概念
• Pod:拥有一个Pod IP,是一个或一组容器组成。
• Service:为Pod实现负载均衡
• Endpoints:Endpoints表示了一个Service对应的所有Pod副本的访问地址,它负责监听Service和对应的Pod副本的变化。
• Ingress:通过Service获取其同名的Endpoints对象,使用是Endpoints存储的IP地址。
至于它们的关系,照惯例还是上个图比较清晰一些。
创建Pod
我们先大概看一下pod创建的整个流程。
基本分为三个部分:
- 通过各种方式去调用api server的接口,然后它会按照一定的格式存入etcd
- Master节点上的 Scheduler 监听api server
- Scheduler:简单的说就是通过一定的算法,把这个Pod分配到某个Worker节点上
- Worker节点上的 Kubelet 监听api server
- 创建容器(CRI)
- 创建网络(CNI)
- 创建存储(CSI)
- 分配IP地址
- 更新Pod状态
以上流程没有涉及到Worker上的另一个组件,也就是Kube-proxy。
删除Pod
流程比较简单,也是通过api server去同步配置存储到etcd,然后Kubelet收到通知后负责删除Pod。
但Kubelet的步骤却完全相反,分别是:
- 删除存储(CSI)
- 删除网络(CNI)
- 删除容器(CRI)
在删除Pod的时候,会同时删除endpoint,kubelet也会接收到信号。
由于事件是并行的,可能会产生没有即时同步的情况,也就是endpoint还没有完成同步的时候,Pod已经同步完成了,这个时候访问就会出现问题。
如下图所示,运气最好的时候,也就是在endpoint完全同步之后,Pod才被删除。
怎么样保证优雅的删除呢?通常有以下几种方法:
- 当Pod即将被删除时,会收到SIGTERM信号,应用程序可以捕获该信号并开始关闭。
默认情况下,Kubernetes 将发送 SIGTERM 信号并等待 30 秒,然后强制终止该进程。
- 使用preStop钩子,等待15秒
以下是一个最简单的示例
apiVersion: v1
kind: Pod
metadata:
name: my-pod
spec:
containers:
- name: web
image: nginx
ports:
- name: web
containerPort: 80
lifecycle:
preStop:
exec:
command: ["sleep", "15"]
那么它的流程会变成这样
仔细的朋友可能注意到有个Gracefule shutdown环节,此部分用于处理应用程序的优雅关闭。
假如你启动的是Nginx服务,那么YAML配置将会变成这样
apiVersion: v1
kind: Pod
metadata:
name: my-pod
spec:
containers:
- name: web
image: nginx
ports:
- name: web
containerPort: 80
lifecycle:
preStop:
exec:
command: ["sleep", "15", "&&", "nginx", "-s", "stop"]
更新Pod
如果您有三个副本,并且一旦提交新的 YAML 资源 Kubernetes,则:
- 用新的容器镜像创建一个 Pod。
- 销毁现有的 Pod。
- 等待 Pod 准备就绪。
并重复上述步骤,直到所有 Pod 都迁移到较新的版本。
Kubernetes 仅在新的 Pod 准备好接收流量(通过 Readiness 检查)之后才重复每个周期。
这里顺便介绍一下Pod需要关注的两个探针
- liveness:存活检测,如果探测失败了将会杀死容器。
- readiness:就绪检测,检测容器是否准备好提供服务。
具体配置就不在这里详细叙述了。