容器编排之战(二十五)连载

控制器模式解析

 k8s 项目通过一个称作"控制器模式"(controller pattern)的设计方法,来统一地实现对各种不同的对象或者资源进行的编排操作。#k8s核心就是用一个东西去控制另一个东西,所有的内容都是被控制的,
 容器镜像虽然好用,但是容器这样一个"沙盒"的概念,对于描述应用来说太过简单。好比,集装箱固然好用,如果它四面都光秃秃的,吊车还怎么把这个集装箱吊起来并摆放好呢?
​
   所以,Pod 对象,其实就是容器的升级版。它对容器进行了组合,添加了更多的属性和字段。这就好比给集装箱四面安装了吊环,使得 Kubernetes 这架"吊车",可以更轻松地操作它。
​
   而 k8s 操作这些"集装箱"的逻辑,都由控制器(Controller)完成

回顾 Deployment 这个最基本的控制器对象。之前讲过一个 nginx-deployment 的例子:

例1:
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  selector:
    matchLabels:
      app: nginx
  replicas: 2
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.7.9
        ports:
        - containerPort: 80

这个 Deployment 定义的编排动作为:

确保携带了 app=nginx 标签的 Pod 的个数,永远等于 spec.replicas 指定的个数,即 2 个。如果在这个集群中,携带 app=nginx 标签的 Pod 的个数大于 2 的时候,就会有旧的 Pod 被删除;反之,就会有新的 Pod 被创建。

究竟是 Kubernetes 项目中的哪个组件,在执行这些操作呢?

kube-controller-manager 组件:这个组件,就是一系列控制器的集合

所有控制器:

deployment             job                   podautoscaler          
cloud                  disruption             namespace              
replicaset             serviceaccount         volume
cronjob                garbagecollector       nodelifecycle          replication            statefulset            daemon

上面的每一个控制器,都以独有的方式负责某种编排功能。而Deployment,正是这些控制器中的一种。

而被控制对象的定义,则来自于一个"模板"。比如,Deployment 里的 template 字段。
​
Deployment 这个 template 字段里的内容,跟一个标准的 Pod 对象的 API 定义,丝毫不差。而所有被这个 Deployment 管理的 Pod 实例,都是根据这个 template 字段的内容创建出来的。 

对 Deployment 以及其他类似的控制器,做一个总结:

如图,类似 Deployment 的一个控制器,都是由两部分组成:

上半部分的控制器定义(包括期望状态)
下半部分的被控制对象的模板组成的。

也正是在这个统一的编排框架下,不同的控制器可以在具体执行过程中,设计不同的业务逻辑,从而达到不同的编排效果。

这个实现思路,正是 k8s 进行容器编排的核心原理。

滚动更新

概念:

将一个集群中正在运行的多个 Pod 版本,交替地逐一升级的过程,就是"滚动更新"。

实验:

[root@kub-k8s-master prome]# kubectl get deploy
NAME               READY   UP-TO-DATE   AVAILABLE   AGE
dep01              2/2     2            2           4h41m
nginx-deployment   2/2     2            2           5h13m
​
我们将nginx-deploument的副本数量变成4个,现在2个
[root@kub-k8s-master prome]# vim deployment.yaml  #修改如下内容
将replicas: 2
修改为:
replicas: 4

创建上节儿的:nginx-deployment

[root@kub-k8s-master prome]# kubectl apply -f deployment.yaml --record
deployment.apps/nginx-deployment configured
​
--record  记录下每次操作所执行的命令,以方便后面查看

检查nginx-deployment 创建后的状态信息:

[root@kub-k8s-master prome]# kubectl get deploy
NAME               READY   UP-TO-DATE   AVAILABLE   AGE
dep01              2/2     2            2           4h53m
nginx-deployment   4/4     4            4           5h25m

返回结果中四个状态字段含义:

DESIRED: 
如果有就表示用户期望的 Pod 副本个数(spec.replicas 的值);
​
CURRENT:
当前处于 Running 状态的 Pod 的个数;
​
UP-TO-DATE:
当前处于最新版本的 Pod 的个数,所谓最新版本指的是 Pod 的 Spec 部分与 Deployment 里 Pod 模板里定义的完全一致;
​
AVAILABLE:
当前已经可用的 Pod 的个数,即:既是 Running 状态,又是最新版本,并且已经处于 Ready(健康检查正确)状态的 Pod 的个数。只有这个字段,描述的才是用户所期望的最终状态。

修改 Deployment:

[root@kub-k8s-master prome]# kubectl get deploy
NAME               READY   UP-TO-DATE   AVAILABLE   AGE
dep01              2/2     2            2           4h59m
nginx-deployment   4/4     4            4           5h32m
​
将dep01的副本将2变为3个
[root@kub-k8s-master prome]# kubectl edit deployment/dep01
​
# reopened with the relevant failures.
#
apiVersion: apps/v1
...
spec:
  progressDeadlineSeconds: 600
  replicas: 3   #将这里原来的2改为3
  revisionHistoryLimit: 10
  selector:
    matchLabels:
...
保存退出,vim的方式
[root@kub-k8s-master prome]# kubectl edit deployment/dep01
deployment.apps/dep01 edited
[root@kub-k8s-master prome]# kubectl get deploy
NAME               READY   UP-TO-DATE   AVAILABLE   AGE
dep01              3/3     3            3           5h16m
nginx-deployment   4/4     4            4           5h48m

进行版本的升级

创建一个新的deploy
[root@kub-k8s-master prome]# cp nginx-depl.yml nginx-depl02.yml
[root@kub-k8s-master prome]# vim nginx-depl02.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: dep02 #注意修改
spec:
  selector:
    matchLabels:
      app: web1
  replicas: 2
  template:
      metadata:
        name: testnginx9
        labels:
          app: web1
      spec:
        containers:
          - name: testnginx9
            image: daocloud.io/library/nginx:1.14 #注意修改
            ports:
              - containerPort: 80
[root@kub-k8s-master prome]# kubectl apply -f nginx-depl02.yml 
deployment.apps/dep02 created
[root@kub-k8s-master prome]# kubectl get pods
NAME                                READY   STATUS    RESTARTS   AGE
dep01-58f6d4d4cb-997jw              1/1     Running   0          16m
dep01-58f6d4d4cb-g6vtg              1/1     Running   0          5h32m
dep01-58f6d4d4cb-k6z47              1/1     Running   0          5h32m
dep02-78dbd944fc-47czr              1/1     Running   0          44s
dep02-78dbd944fc-4snsj              1/1     Running   0          25s
​
将nginx的版本从1.14升级到1.16
[root@kub-k8s-master prome]# kubectl edit deployment/dep02
# Please edit the object below. Lines beginning with a '#' will be ignored,
# and an empty file will abort the edit. If an error occurs while saving this file will be
...
spec:
      containers:
      - image: daocloud.io/library/nginx:1.16  #将这里原来的nginx:1.14修改为nginx:1.16
        imagePullPolicy: Always
        name: testnginx9
        ports:
        - containerPort: 80
...
保存退出,vim的方式
[root@kub-k8s-master prome]# kubectl edit deployment/dep01
deployment.apps/dep01 edited

这时可以通过查看 Deployment 的 Events,看到这个"滚动更新"的流程:

[root@kub-k8s-master prome]# kubectl describe deployment dep02
...
Events:
  Type    Reason             Age   From                   Message
  ----    ------             ----  ----                   -------
  Normal  ScalingReplicaSet  50s   deployment-controller  Scaled up replica set dep02-846bf8775b to 2
  Normal  ScalingReplicaSet  9s    deployment-controller  Scaled up replica set dep02-58f8d5678 to 1
  Normal  ScalingReplicaSet  8s    deployment-controller  Scaled down replica set dep02-846bf8775b to 1
  Normal  ScalingReplicaSet  8s    deployment-controller  Scaled up replica set dep02-58f8d5678 to 2
  Normal  ScalingReplicaSet  5s    deployment-controller  Scaled down replica set dep02-846bf8775b to 0
如此交替进行,新 ReplicaSet 管理的 Pod 副本数,从 0 个变成 1 个,再变成 2 个,最后变成 3 个。而旧的 ReplicaSet 管理的 Pod 副本数则从 3 个变成 2 个,再变成 1 个,最后变成 0 个。这样,就完成了这一组 Pod 的版本升级过程。

验证

[root@kub-k8s-master prome]# kubectl get pods
NAME                                READY   STATUS    RESTARTS   AGE
dep02-78dbd944fc-69t8x              1/1     Running   0          11h
dep02-78dbd944fc-7cn86              1/1     Running   0          11h
[root@kub-k8s-master prome]# kubectl exec -it dep02-78dbd944fc-69t8x /bin/bash 
root@dep02-78dbd944fc-69t8x:/# nginx -v 
nginx version: nginx/1.16.1
root@dep02-78dbd944fc-69t8x:/# exit

"滚动更新"的好处:

在升级刚开始的时候,集群里只有 1 个新版本的 Pod。如果这时,新版本 Pod 有问题启动不起来,那么"滚动更新"就会停止,从而允许开发和运维人员介入。而在这个过程中,由于应用本身还有两个旧版本的 Pod 在线,所以服务并不会受到太大的影响。

猜你喜欢

转载自blog.csdn.net/qfyangsheng/article/details/108448132