基本介绍

首先展示一张简单的架构图,会发现所有的流程几乎都是是通过api server通信的。

在开始之前先区分一些概念
• Pod:拥有一个Pod IP,是一个或一组容器组成。
• Service:为Pod实现负载均衡
• Endpoints:Endpoints表示了一个Service对应的所有Pod副本的访问地址,它负责监听Service和对应的Pod副本的变化。
• Ingress:通过Service获取其同名的Endpoints对象,使用是Endpoints存储的IP地址。

至于它们的关系,照惯例还是上个图比较清晰一些。

创建Pod

我们先大概看一下pod创建的整个流程。

基本分为三个部分:

  1. 通过各种方式去调用api server的接口,然后它会按照一定的格式存入etcd
  2. Master节点上的 Scheduler 监听api server
    • Scheduler:简单的说就是通过一定的算法,把这个Pod分配到某个Worker节点上
  3. Worker节点上的 Kubelet 监听api server
    1. 创建容器(CRI)
    2. 创建网络(CNI)
    3. 创建存储(CSI)
    4. 分配IP地址
    5. 更新Pod状态

以上流程没有涉及到Worker上的另一个组件,也就是Kube-proxy。

删除Pod

流程比较简单,也是通过api server去同步配置存储到etcd,然后Kubelet收到通知后负责删除Pod。

但Kubelet的步骤却完全相反,分别是:

  1. 删除存储(CSI)
  2. 删除网络(CNI)
  3. 删除容器(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:就绪检测,检测容器是否准备好提供服务。

具体配置就不在这里详细叙述了。