正常创建一个pod资源时,可以直接创建一个kind:Pod类型的自主式pod,这种自主式pod被删除后,不能自我恢复,会被彻底删除;

使用控制器就能管理pod,监测pod的运行状况,当pod发生故障时,可以自动恢复pod,也就是说能够代我们去管理pod中间层,并确保每一个pod资源始终处于一个我们所期待或者所定义的一个目标状态;

一旦pod资源出现故障,那么控制器会尝试重启pod或者里面的容器,如果一直重启有问题的话那么它可能会基于某种策略来进行重新布派或者重新编排;如果pod副本数量低于用户所定义的目标数量,它也会自动补全;如果多余,也会自动终止pod资源。

一、控制器Replicaset

1.1 Replicaset 概述

ReplicaSet是kubernetes中的一种副本控制器,简称rs,主要作用是控制由其管理的pod,使pod副本的数量始终维持在预设的个数。它的主要作用就是保证一定数量的Pod能够在集群中正常运行,它会持续监听这些Pod的运行状态,在Pod发生故障时重启pod,pod数量减少时重新运行新的 Pod副本。

 

官方推荐不要直接使用ReplicaSet,用Deployments取而代之,Deployments是比ReplicaSet更高级的概念,它会管理ReplicaSet并提供很多其它有用的特性,最重要的是Deployments支持声明式更新,声明式更新的好处是不会丢失历史变更。所以Deployment控制器不直接管理Pod对象,而是由 Deployment 管理ReplicaSet,再由ReplicaSet负责管理Pod对象。

1.2 Replicaset工作原理

Replicaset核心作用在于代用户创建指定数量的pod副本,并确保pod副本一直处于满足用户期望的数量, 起到多退少补的作用,并且还具有自动扩容缩容等机制。


Replicaset控制器主要由三个部分组成:

1、用户期望的pod副本数:用来定义由这个控制器管控的pod副本有几个

2、标签选择器:选定哪些pod是自己管理的,如果通过标签选择器选到的pod副本数量少于我们指定的数量,需要用到下面的组件

3、pod资源模板:如果集群中现存的pod数量不够我们定义的副本中期望的数量怎么办,需要新建pod,这就需要pod模板,新建的pod是基于模板来创建的。

1.3 Replicaset 资源清单文件编写技巧

kubectl explain rs   (rs 简称) 如下图

apiVersion  <string>    #当前资源使用的api版本,跟VERSION:  apps/v1保持一致
kind        <string>    #资源类型,跟KIND: ReplicaSet保持一致
metadata    <Object>    #元数据,定义Replicaset名字的
spec        <Object>    #定义副本数、定义标签选择器、定义Pod模板
status      <Object>    #状态信息,不能改

k8s控制器管理,Replicaset、Deployment进行pod扩容缩容更新及回滚,蓝绿部署及金丝雀发布_k8s

1.4 使用控制器创建pod

[root@k8s-master ~]# vim rs-pod01.yaml

apiVersion: apps/v1     #根据上图中格式定义apiversion 及 kind
kind: ReplicaSet
metadata:
  name: rs-pod001
  namespace: default
  labels:
    a01: a001
    a02: a002
spec:
  replicas: 3       #指定pod副本数,当控制器检测到少于pod副本数3的时候,将跟据下方 matchLabels定义匹配标签,根据标签匹配到模板,然后从模板中定义的pod进行创建
  selector:
    matchLabels:    #表示匹配具有哪个标签的pod
      b01: b001     #定义匹配pod的标签
  template:         #表示pod模板,下方定义的内容都是指定义pod的信息
    metadata:       #这里注意,使用控制器管理pod时,上方定义了name,这里再次定义name将不起作用,pod的名字将由上方定义的name指定。
      labels:
        b01: b001
    spec:           #这里定义创建pod资源
      containers:
      - name: mytomcat
        image: tomcat
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 8080


#创建
[root@k8s-master ~]# kubectl apply -f rs-pod01.yaml 
replicaset.apps/rs-pod001 created

#查看pod状态 (创建三个pod ,pod名称跟yaml中控制器下metadata定义的name一致,-后面是随机的)
NAME              READY   STATUS    RESTARTS   AGE   IP              NODE          NOMINATED NODE   READINESS GATES
rs-pod001-2s8fg   1/1     Running   0          14s   10.244.126.3    k8s-worker2   <none>           <none>
rs-pod001-5xw8r   1/1     Running   0          14s   10.244.126.4    k8s-worker2   <none>           <none>
rs-pod001-vws56   1/1     Running   0          14s   10.244.194.67   k8s-worker1   <none>           <none>

#查看控制器pod资源  (依次表示 期望pod数-当前pod数-就绪pod数)
NAME        DESIRED   CURRENT   READY   AGE
rs-pod001   3         3         3       22s

#测试删除一个pod  也会根据yaml中定义的pod副本数自动创建补齐为3个
[root@k8s-master ~]# kubectl delete pods rs-pod001-2s8fg
pod "rs-pod001-2s8fg" deleted

#查看确认补充创建一个 运行时间1
[root@k8s-master ~]# kubectl get pods 
NAME              READY   STATUS    RESTARTS   AGE
rs-pod001-5xw8r   1/1     Running   0          6m53s
rs-pod001-rp2gt   1/1     Running   0          12s
rs-pod001-vws56   1/1     Running   0          6m53s

1.5 使用 Replicaset 管理pod,进行扩容、缩容、更新

1.5.1 Replicaset 实现pod的动态扩容

ReplicaSet最核心的功能是可以动态扩容和回缩,当pod副本数不满足需求数量时,想要增加,只需要修改上方实验中创建pod时的配置文件“rs-pod01.yaml”里的replicas的值即可,修改之后执行此命令进行更新:“kubectl apply -f replicaset.yaml”

#修改为5个副本数
[root@k8s-master ~]# cat rs-pod01.yaml | grep replicas
  replicas: 5 
  
#更新yaml文件
[root@k8s-master ~]# kubectl apply -f rs-pod01.yaml 
replicaset.apps/rs-pod001 configured

#验证
[root@k8s-master ~]# kubectl get pods 
NAME              READY   STATUS    RESTARTS      AGE
rs-pod001-gm7wv   1/1     Running   0             7s
rs-pod001-gsw9b   1/1     Running   0             7s
rs-pod001-td7g5   1/1     Running   0             10m
rs-pod001-vws56   1/1     Running   0             3m
rs-pod001-w6x8p   1/1     Running   0             10m

1.5.2 Replicaset 实现pod的动态缩容

与扩容同理,修改yaml文件 replicas的值即可。

#修改为2个副本数
[root@k8s-master ~]# cat rs-pod01.yaml | grep replicas
  replicas: 2   
  
#更新yaml文件
[root@k8s-master ~]# kubectl apply -f rs-pod01.yaml 
replicaset.apps/rs-pod001 configured

#验证
[root@k8s-master ~]# kubectl get pods 
NAME              READY   STATUS    RESTARTS      AGE
rs-pod001-td7g5   1/1     Running   0             12m23
rs-pod001-w6x8p   1/1     Running   0             12m23s

1.5.3 Replicaset 实现pod的更新

所谓更新就是更换镜像,同样修改yaml文件,更新配置文件中定义pod中 containers下 image的镜像值

#将tomcat镜像修改为nginx
[root@k8s-master ~]# cat rs-pod01.yaml  | grep -A 3 containers
      containers:
      - name: mynginx
        image: nginx
        imagePullPolicy: IfNotPresent

#更新前需要将已经存在的pod删除,负责无法更新pod资源
[root@k8s-master ~]# kubectl delete pods rs-pod001-td7g5
pod "rs-pod001-td7g5" deleted
[root@k8s-master ~]# kubectl delete pods rs-pod001-w6x8p
pod "rs-pod001-w6x8p" deleted

#删除pod之后会自动根据yaml文件中定义的副本数创建补足出来新的pod
[root@k8s-master ~]# kubectl get pods 
NAME              READY   STATUS    RESTARTS   AGE
rs-pod001-qnw9m   1/1     Running   0          62s
rs-pod001-w6925   1/1     Running   0          74s

#验证:此时访问 tomcat 8080端口 已经拒绝链接
[root@k8s-master ~]# curl 10.244.126.10:8080 
curl: (7) Failed connect to 10.244.126.10:8080; 拒绝连接

#访问nginx 80 端口 正常
[root@k8s-master ~]# curl 10.244.126.10:80
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>



#PS: 删除pod时 最好不要直接根据yaml文件中进行删除“kubectl delete -f rs-pod01.yaml”
      这样会将定义的replicaset也一起删除,从而导致整个pod层级全部删除,最好一个pod一个pod的删除。
      如果需要自动更新 就使用到 Deployment 控制器。

二、Deployment控制器

2.1 Deployment 概述

1、Deployment是kubernetes中最常用的资源对象,创建deployment时它会创建replicaset和pod,由replicaset去管理pod,deployment也能指定pod 的副本数,换言之就是replicase有的功能deployment都有 且更强大。


2、而使用Deployment而不直接使用ReplicaSet是因为Deployment对象拥有许多ReplicaSet没有的特性,例如滚动升级、金丝雀发布、蓝绿部署和回滚。


3、Deployment可以为ReplicaSet和Pod的创建提供了一种声明式的定义方法,就是说可以直接修改资源清单yaml文件,然后通过kubectl apply -f 资源清单yaml文件,就可以更改资源。


4、Deployment控制器是建立在rs之上的一个控制器,可以管理多个rs,每次更新镜像版本,都会生成一个新的rs,把旧的rs替换掉,多个rs同时存在,但是只有一个rs运行。也就是说如上方replicaset更新pod资源yaml文件时,需要手动删除pod,而使用deployment时更新yaml文件中的镜像资源时,它会直接将rs给删除掉然后创建一个新的出来,用新的rs管理新的镜像创建的pod,旧的也会保留。


2.2 Deployment 工作原理

如何管理 rs 和 pod 


Deployment可以使用声明式定义,直接在命令行通过纯命令的方式完成对应资源版本的内容的修改,也就是通过打补丁的方式进行修改,还可以修改yaml文件,然后使kubectl apply -f 更新,Deployment能提供滚动式自定义自控制的更新;对Deployment来讲,我们在实现更新时还可以实现控制更新节奏和更新逻辑。


通过Deployment对象,你可以轻松的做到以下事情:

1、创建ReplicaSet和Pod

2、滚动升级(不停止旧服务的状态下升级)和回滚应用(将应用回滚到之前的版本)

3、平滑地扩容和缩容

4、暂停和继续Deployment

2.3 Deployment YAML文件编写技巧

kubectl explain deployment 通过该命令查看deployment控制器的字段,如下图所示
  
apiVersion	<string>    #该资源使用的api版本
kind	<string>          #创建的资源是什么?
metadata	<Object>       #元数据,包括资源的名字和名称空间
spec	<Object>          #定义容器的
status	<Object>       #状态,不可以修改

#deployment下的spec字段
minReadySeconds	<integer>       #k8s在等待设置的时间后才进行升级,如果没有设置该字段,会默认容器启动后就执行
paused	<boolean>                #暂停,当更新的时候创建pod先暂停,而不是立即更新创建
progressDeadlineSeconds	<integer> #k8s 在升级过程中有可能由于各种原因升级卡住(这个时候还没有明确的升级失败),
                                   比如在拉取被墙的镜像,权限不够等错误。那么这个时候就需要有个 deadline ,
                                   在 deadline 之内如果还卡着,那么就上报这个情况,
                                   这个时候这个 Deployment 状态就被标记为 False,并且注明原因。
                                   但是它并不会阻止 Deployment 继续进行卡住后面的操作。完全由用户进行控制。
replicas	<integer>                #定义副本数
revisionHistoryLimit	<integer>    #保留的历史版本,默认是10
selector	<Object> -required       #标签选择器,选择它关联的pod
strategy	<Object>                 #更新策略
template	<Object> -required       #定义的pod模板

#查看Deployment下的spec.strategy字段
#更新方式
type                    #更新的类型包含两个类型,该字段不定义的话,默认就是使用rollingUpdate
                         Recreate:重建式更新,删除一个更新一个
                         RollingUpdate:滚动更新,定义滚动更新方式,也就是pod能多几个,少几个
                     
#查看Deployment下的spec.strategy.rollingUpdate字段
maxSurge	<string>       #更新的过程当中最多允许超出的指定的目标副本数有几个;
                         它有两种取值方式,第一种直接给定数量,
                         第二种根据百分比,百分比表示原本是5个,最多可以超出20%,那就允许多一个,
                         最多可以超过40%,那就允许多两个
maxUnavailable	<string> #最多允许几个不可用,比如假设有5个副本,最多一个不可用,就表示最少有4个可用

#查看Deployment下的spec.template字段
#template为定义Pod的模板,Deployment通过模板创建Pod
metadata	<Object>  #定义模板的名字
spec	<Object>   
deployment.spec.template为Pod定义的模板,和Pod定义不太一样,template中不包含apiVersion和Kind属性,
要求必须有metadata。deployment.spec.template.spec为容器的属性信息,其他定义内容和Pod一致。

k8s控制器管理,Replicaset、Deployment进行pod扩容缩容更新及回滚,蓝绿部署及金丝雀发布_控制器_02

2.4 使用控制器创建pod

#编写yaml文件 使用deploymen控制器创建两个pod,容器启用nginx服务,并使用探测进行探测80端口后一切正常之后进行创建。
[root@k8s-master ~]# vim deploy-pod01.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: deploy-01    #定义deployment 的名字
  labels:
    dep01: dep02     #定义deployment 的标签
spec:
  replicas: 2        #定义pod副本数,让deployment管理两个pod
  selector:          #标签选择器,定义管理哪个具有匹配标签的pod    
    matchLabels:     #定义匹配下方模板中定义的标签,这样才能通过匹配的标签找到关联的pod
      app: pod01
      version: v1
  template:          #定义pod模板,无需定义pod的name,因为模板中的pod name是跟据 deployment中定义的name来的
    metadata:
      labels:
        app: pod01
        version: v1
    spec:           #定义pod中容器的信息
      containers:
      - name: mynginx    #定义容器的名称
        image: nginx
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 80
        startupProbe:         #定义启动探测
          periodSeconds: 5
          initialDelaySeconds: 20
          timeoutSeconds: 10
          httpGet:
            scheme: HTTP
            port: 80
            path: /
        livenessProbe:        #定义存活探测
          periodSeconds: 5
          initialDelaySeconds: 20
          timeoutSeconds: 10
          httpGet:
            scheme: HTTP
            port: 80
            path: /
        readinessProbe:       #定义就绪探测
          periodSeconds: 5
          initialDelaySeconds: 20
          timeoutSeconds: 10
          httpGet:
            scheme: HTTP
            port: 80
            path: /

#创建
[root@k8s-master ~]# kubectl apply -f deploy-pod01.yaml 
deployment.apps/deploy-01 created

#查看deployment 副本数状态
[root@k8s-master ~]# kubectl get deploy  #列表依次排列name-就绪状态-pod启动数量-pod可用数量
NAME        READY   UP-TO-DATE   AVAILABLE   AGE
deploy-01   2/2     2            2           32s

#查看replicaset状态。创建deploymen之后 也会自动创建一个replicaset,名字也是根据deployment来的
[root@k8s-master ~]# kubectl get rs      ##列表依次排列name-期望管理pod数量-当前pod数量-就绪pod数量
NAME                   DESIRED   CURRENT   READY   AGE
deploy-01-59774cd67f   2         2         2       89s

#查看pod状态
[root@k8s-master ~]# kubectl get pods -owide
NAME                         READY   STATUS    RESTARTS   AGE   IP              NODE          NOMINATED NODE   READINESS GATES
deploy-01-59774cd67f-4d95v   1/1     Running   0          98s   10.244.126.12   k8s-worker2   <none>           <none>
deploy-01-59774cd67f-dlkcj   1/1     Running   0          98s   10.244.194.74   k8s-worker1   <none>           <none>

#请求nginx端口测试,见下图

总结:使用deploymen控制器创建pod时,不仅创建了deploy 还创建了 rs及pod,三层结构。

k8s控制器管理,Replicaset、Deployment进行pod扩容缩容更新及回滚,蓝绿部署及金丝雀发布_linux_03

2.5 使用Deployment 管理pod 扩容 缩容及滚动更新和更新后的回滚

2.5.1  Deployment 实现pod扩容

#将原来2个副本数改为3,修改yaml文件中replicas字段的值为3

[root@k8s-master ~]# cat deploy-pod01.yaml | grep replicas 
  replicas: 3    #修改为3

#更新yaml文件
[root@k8s-master ~]# kubectl apply -f deploy-pod01.yaml 
deployment.apps/deploy-01 configured

#查看 deploy、rs 及pod状态(已经由2改为3 并新增了一个pod)
[root@k8s-master ~]# kubectl get deploy
NAME        READY   UP-TO-DATE   AVAILABLE   AGE
deploy-01   3/3     3            3           64m
[root@k8s-master ~]# kubectl get rs
NAME                   DESIRED   CURRENT   READY   AGE
deploy-01-59774cd67f   3         3         3       64m
[root@k8s-master ~]# kubectl get pods 
NAME                         READY   STATUS    RESTARTS   AGE
deploy-01-59774cd67f-4d95v   1/1     Running   0          64m
deploy-01-59774cd67f-dlkcj   1/1     Running   0          64m
deploy-01-59774cd67f-grvww   1/1     Running   0          36s

2.5.2  Deployment 实现pod缩容

#缩容也是同理 修改修改yaml文件中replicas字段的值为2

[root@k8s-master ~]# cat deploy-pod01.yaml | grep replicas
  replicas: 2
  
#更新yaml文件
[root@k8s-master ~]# kubectl apply -f deploy-pod01.yaml 
deployment.apps/deploy-01 configured

#查看 deploy、rs 及pod状态(已经由3改为2 并随机删除了一个pod)
[root@k8s-master ~]# kubectl get deploy
NAME        READY   UP-TO-DATE   AVAILABLE   AGE
deploy-01   2/2     2            2           67m
[root@k8s-master ~]# kubectl get rs
NAME                   DESIRED   CURRENT   READY   AGE
deploy-01-59774cd67f   2         2         2       67m
[root@k8s-master ~]# kubectl get pods
NAME                         READY   STATUS    RESTARTS   AGE
deploy-01-59774cd67f-4d95v   1/1     Running   0          67m
deploy-01-59774cd67f-dlkcj   1/1     Running   0          67m

2.5.3 Deployment 实现pod滚动更新

滚动更新是一种自动化程度较高的发布方式,一次滚动发布一般由若干个发布批次组成,每批的数量一般是可以配置的(可以通过发布模板定义),比如10个pod可以按照百分比去分批更新,第一批10%,第二批30%......,每个批次更新之间可以由时间观察状态。


通过该命令查看字段信息。 kubectl explain deploy 如下图 deployment字段可简写成deploy

k8s控制器管理,Replicaset、Deployment进行pod扩容缩容更新及回滚,蓝绿部署及金丝雀发布_控制器_04

#创建yaml资源 (还以上方2.4标题中使用的deploy-pod01.yaml文件为例 副本数改为3)
[root@k8s-master ~]# kubectl apply -f deploy-pod01.yaml 
deployment.apps/deploy-01 created

[root@k8s-master ~]# kubectl get deploy
NAME        READY   UP-TO-DATE   AVAILABLE   AGE
deploy-01   3/3     3            3           102s

#查看deployment默认的更新策略  如下图
[root@k8s-master ~]# kubectl describe deploy deploy-01

#默认都是25%
maxSurge	     25%  #字段含义:更新的过程当中最多允许超出的指定的目标副本数有几个
                     计算方式:pod数量乘以定义的百分比,即 3*25%=0.75 根据字段含义向上取整数,即等于为1个,
                     所以根据字段含义默认为3+1=4,3个pod设置为25% 最多可以更新为4个
maxUnavailable 25%	#字段含义:#最多允许几个不可用,比如假设有5个副本,最多一个不可用,就表示最少有4个可用
                     计算方式:pod数量乘以定义的百分比,即 3*25%=0.75 根据字段含义向下取整数,即等于为0个,
                     所以根据字段含义默认为3-0=3,3个pod设置为25% 最多0个不可用,所以还是等于3,最少更新三个pod。
                     
#总结:如果这个yaml文件没有指定 maxSurge、maxUnavailable的更新策略,
 那么默认就是25%,根据如上计算方式,那么pod数量在3-4个,最少不能低于3个pod。

k8s控制器管理,Replicaset、Deployment进行pod扩容缩容更新及回滚,蓝绿部署及金丝雀发布_linux_05

开始更新

#查看当前pod数量及状态
[root@k8s-master ~]# kubectl get pods 
NAME                         READY   STATUS    RESTARTS   AGE
deploy-01-59774cd67f-gkm7p   1/1     Running   0          2m3s
deploy-01-59774cd67f-kznkt   1/1     Running   0          2m3s
deploy-01-59774cd67f-pkzhk   1/1     Running   0          2m3s

#修改yaml文件中的nginx镜像为tomcat
[root@k8s-master ~]# vim deploy-pod01.yaml  (修改镜像nginx为tomcat 也可以先将探测字段规则删除)

apiVersion: apps/v1
kind: Deployment
metadata:
  name: deploy-01    #定义deployment 的名字
  labels:
    dep01: dep02     #定义deployment 的标签
spec:
  replicas: 3        #定义pod副本数,让deployment管理两个pod
  selector:          #标签选择器,定义管理哪个具有匹配标签的pod    
    matchLabels:     #定义匹配下方模板中定义的标签,这样才能通过匹配的标签找到关联的pod
      app: pod01
      version: v1
  template:          #定义pod模板,无需定义pod的name,因为模板中的pod name是跟据 deployment中定义的name来的
    metadata:
      labels:
        app: pod01
        version: v1
    spec:           #定义pod中容器的信息
      containers:
      - name: mytomcat   #定义容器的名称
        image: tomcat
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 8080

#创建新的pod
[root@k8s-master ~]# kubectl apply -f deploy-pod02.yaml 
deployment.apps/deploy-01 configured

#查看 (新pod名称已经从deploy-01-59774cd67f....更改为deploy-01-8fc846cc9....)
[root@k8s-master ~]# kubectl get pods 
NAME                        READY   STATUS    RESTARTS   AGE
deploy-01-8fc846cc9-b2dth   1/1     Running   0          71s
deploy-01-8fc846cc9-wtjwb   1/1     Running   0          75s
deploy-01-8fc846cc9-xjqgg   1/1     Running   0          73s

#同时也会创建新的replicaset
[root@k8s-master ~]# kubectl get rs 
NAME                   DESIRED   CURRENT   READY   AGE
deploy-01-59774cd67f   0         0         0       4m11s
deploy-01-8fc846cc9    3         3         3       114s

#因为使用过的是同一个deploymen 所以 deploymen不会发生改变
[root@k8s-master ~]# kubectl get deploy  
NAME        READY   UP-TO-DATE   AVAILABLE   AGE
deploy-01   3/3     3            3           4m16s

#下图为更新时的pod实时状态。

k8s控制器管理,Replicaset、Deployment进行pod扩容缩容更新及回滚,蓝绿部署及金丝雀发布_linux_06

2.5.4 Deployment 实现pod更新后的回滚

#使用如下命令查看deployment的历史版本 kubectl rollout history deployment + 指定的deployment的名称
[root@k8s-master ~]# kubectl rollout history deployment deploy-01
deployment.apps/deploy-01        #名称
REVISION  CHANGE-CAUSE           #只更新了一次所以只有两个版本
1         <none>                 #序号1 更新前的版本
2         <none>                 #序号2 更新后的当前版本

#回滚前确认 rs 的状态信息
[root@k8s-master ~]# kubectl get rs  当前是deploy-01-8fc846cc9 管理的pod
NAME                   DESIRED   CURRENT   READY   AGE
deploy-01-59774cd67f   0         0         0       19m
deploy-01-8fc846cc9    3         3         3       17m

#执行序号进行回滚版本
[root@k8s-master ~]# kubectl rollout undo deployment/deploy-01 --to-revision=1
deployment.apps/deploy-01 rolled back

#查看rs 的状态,正在转移更新
[root@k8s-master ~]# kubectl get rs 
NAME                   DESIRED   CURRENT   READY   AGE
deploy-01-59774cd67f   2         2         1       22m
deploy-01-8fc846cc9    2         2         2       20m

#查看pod 状态 目前正在进行创建新的和删除旧的
[root@k8s-master ~]# kubectl get pods 
NAME                         READY   STATUS    RESTARTS   AGE
deploy-01-59774cd67f-8twqb   0/1     Running   0          2s
deploy-01-59774cd67f-bgn9g   1/1     Running   0          48s
deploy-01-59774cd67f-r5jcp   1/1     Running   0          27s
deploy-01-8fc846cc9-xjqgg    1/1     Running   0          20m

#最后完成,已经变更为deploy-01-59774cd67f 管理pod
[root@k8s-master ~]# kubectl get rs 
NAME                   DESIRED   CURRENT   READY   AGE
deploy-01-59774cd67f   3         3         3       24m
deploy-01-8fc846cc9    0         0         0       21m

NAME                         READY   STATUS    RESTARTS   AGE
deploy-01-59774cd67f-8twqb   1/1     Running   0          104s
deploy-01-59774cd67f-bgn9g   1/1     Running   0          2m30s
deploy-01-59774cd67f-r5jcp   1/1     Running   0          2m9s

2.6 自定义滚动更新的策略

maxSurge和maxUnavailable用来控制滚动更新的更新策略

取值范围

数值

1. maxUnavailable: [0, 副本数]

2. maxSurge: [0, 副本数]

注意:两者不能同时为0。

比例

1. maxUnavailable: [0%, 100%] 向下取整,比如10个副本,5%的话==0.5个,但计算按照0个;

2. maxSurge: [0%, 100%] 向上取整,比如10个副本,5%的话==0.5个,但计算按照1个;

建议配置

1. maxUnavailable == 0

2. maxSurge == 1

这是生产环境提供给用户的默认配置。即“一上一下,先上后下”最平滑原则:

1个新版本pod ready(结合readiness)后,才销毁旧版本pod。此配置适用场景是平滑更新、

保证服务平稳,但也有缺点,就是“太慢”了,如果pod较多的话可以增加数值,比如依次更新10个pod。

 

总结:

maxUnavailable:和期望的副本数比,不可用副本数最大比例(或最大值),这个值越小,越能保证服务稳定,更新越平滑;

maxSurge:和期望的副本数比,超过期望副本数最大比例(或最大值),这个值调的越大,副本更新速度越快。

2.6.1 使用rollingUpdate字段自定义更新pod

#创建yaml资源 (删除之前的资源重新创建)
[root@k8s-master ~]# vim deploy-pod01.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: deploy-01    #定义deployment 的名字
  labels:
    dep01: dep02     #定义deployment 的标签
spec:
  replicas: 3        #定义pod副本数,让deployment管理两个pod
  selector:          #标签选择器,定义管理哪个具有匹配标签的pod    
    matchLabels:     #定义匹配下方模板中定义的标签,这样才能通过匹配的标签找到关联的pod
      app: pod01
      version: v1
  template:          #定义pod模板,无需定义pod的name,因为模板中的pod name是跟据 deployment中定义的name来的
    metadata:
      labels:
        app: pod01
        version: v1
    spec:           #定义pod中容器的信息
      containers:
      - name: mynginx    #定义容器的名称
        image: nginx
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 80
        
#创建        
[root@k8s-master ~]# kubectl apply -f deploy-pod01.yaml 
deployment.apps/deploy-01 created

[root@k8s-master ~]# kubectl get rs 
NAME                   DESIRED   CURRENT   READY   AGE
deploy-01-6f84c7b797   3         3         3       41s

[root@k8s-master ~]# kubectl get pods 
NAME                         READY   STATUS    RESTARTS   AGE
deploy-01-6f84c7b797-j9jcb   1/1     Running   0          51s
deploy-01-6f84c7b797-lrvv5   1/1     Running   0          51s
deploy-01-6f84c7b797-t6wd5   1/1     Running   0          51s

#自定义更新yaml资源
 (还以上方使用的deploy-pod01.yaml文件为例 在deployment的spec字段下添加strategy字段并修改镜像为tomcat)
[root@k8s-master ~]# vim deploy-pod01.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: deploy-01    #定义deployment 的名字
  labels:
    dep01: dep02     #定义deployment 的标签
spec:
  strategy:          #定义更新策略  
    rollingUpdate:   #定义更新方式 如下定义表示最多pod的更新在2~4之间
      maxSurge: 1    #定义最多数值,根据pod数量加该数值 即3+1
      maxUnavailable: 1 #定义最少数值,根据pod数量减该数值 即3-1   
  replicas: 3        #定义pod副本数,让deployment管理两个pod
  selector:          #标签选择器,定义管理哪个具有匹配标签的pod    
    matchLabels:     #定义匹配下方模板中定义的标签,这样才能通过匹配的标签找到关联的pod
      app: pod01
      version: v1
  template:          #定义pod模板,无需定义pod的name,因为模板中的pod name是跟据 deployment中定义的name来的
    metadata:
      labels:
        app: pod01
        version: v1
    spec:           #定义pod中容器的信息
      containers:
      - name: mytomcat   #定义容器的名称
        image: tomcat
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 8080

#执行
[root@k8s-master ~]# kubectl apply -f deploy-pod01.yaml 
deployment.apps/deploy-01 configured

[root@k8s-master ~]# kubectl get rs 
NAME                   DESIRED   CURRENT   READY   AGE
deploy-01-6f84c7b797   0         0         0       5m35s
deploy-01-8fc846cc9    3         3         3       10s

[root@k8s-master ~]# kubectl get pods 
NAME                        READY   STATUS    RESTARTS   AGE
deploy-01-8fc846cc9-gg6w5   1/1     Running   0          16s
deploy-01-8fc846cc9-jf49d   1/1     Running   0          16s
deploy-01-8fc846cc9-xfmxk   1/1     Running   0          14s

#自动更新不外乎就是要掌握strategy.rollingUpdate:下的两个字段的定义方式maxSurge、maxUnavailable
如下图片是pod更新过程

k8s控制器管理,Replicaset、Deployment进行pod扩容缩容更新及回滚,蓝绿部署及金丝雀发布_linux_07

2.6.2 使用type.Recreate字段自定义更新pod

Recreate 使用这种表示重建式的更新,会将所有的pod都一起删除然后重建pod

yaml资源文件中 不定义type的话 默认的就是使用rollingUpdate字段进行更新,下面介绍使用Recreate字段进行自定义更新pod

[root@k8s-master ~]# vim deploy-pod01.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: deploy-01    #定义deployment 的名字
  labels:
    dep01: dep02     #定义deployment 的标签
spec:
  strategy:          #定义更新策略  
    type: Recreate   #定义重建式更新pod策略
  replicas: 3        #定义pod副本数,让deployment管理两个pod
  selector:          #标签选择器,定义管理哪个具有匹配标签的pod    
    matchLabels:     #定义匹配下方模板中定义的标签,这样才能通过匹配的标签找到关联的pod
      app: pod01
      version: v1
  template:          #定义pod模板,无需定义pod的name,因为模板中的pod name是跟据 deployment中定义的name来的
    metadata:
      labels:
        app: pod01
        version: v1
    spec:           #定义pod中容器的信息
      containers:
      - name: mynginx   #定义容器的名称
        image: nginx
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 80
        
#执行
[root@k8s-master ~]# kubectl apply -f deploy-pod01.yaml 
deployment.apps/deploy-01 configured

#查看pod状态
[root@k8s-master ~]# kubectl get pods 
NAME                         READY   STATUS    RESTARTS   AGE
deploy-01-6f84c7b797-5gxqv   1/1     Running   0          7s
deploy-01-6f84c7b797-dbh2p   1/1     Running   0          7s
deploy-01-6f84c7b797-q4c4j   1/1     Running   0          7s

#查看pod更新过程(先全部删除旧pod,然后创建新pod,这种风险较大 不建议使用) 如下图所示

k8s控制器管理,Replicaset、Deployment进行pod扩容缩容更新及回滚,蓝绿部署及金丝雀发布_linux_08

2.7 基于k8s实现蓝绿部署

蓝绿部署中,一共有两套系统:一套是正在提供服务系统,标记为“绿色”;另一套是准备发布的系统,标记为“蓝色”。两套系统都是功能完善的、正在运行的系统,只是系统版本和对外服务情况不同。

开发新版本,要用新版本替换线上的旧版本,在线上的系统之外,搭建了一个使用新版本代码的全新系统。 这时候,一共有两套系统在运行,正在对外提供服务的老系统是绿色系统,新部署的系统是蓝色系统。

Kubernetes不支持内置的蓝绿部署。目前最好的方式是创建新的deployment,然后更新应用程序的service以指向新的deployment部署的应用

#创建命名空间
[root@k8s-master ~]# kubectl create ns number-one
namespace/number-one created

#创建部署绿色环境(模拟为第一版旧的镜像运行的pod环境,使用的是nginx镜像端口为80)
[root@k8s-master ~]#  vim old.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: old-01
  labels:
    old01: old02    
  namespace: number-one
spec:
  strategy: 
  replicas: 3  
  selector:   
    matchLabels: 
      app: pod01
      version: v1
  template:     
    metadata:
      labels:
        app: pod01
        version: v1
    spec:        
      containers:
      - name: mynginx  
        image: nginx
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 80

#创建
[root@k8s-master ~]# kubectl apply -f old.yaml 
deployment.apps/old-01 created

#查看number-one空间下的pod 
[root@k8s-master ~]# kubectl get pods -n number-one
NAME                      READY   STATUS    RESTARTS   AGE
old-01-6f84c7b797-6jcrg   1/1     Running   0          16s
old-01-6f84c7b797-b8sxq   1/1     Running   0          16s
old-01-6f84c7b797-xl5nf   1/1     Running   0          16s

#查看pod标签及node节点ip
[root@k8s-master ~]# kubectl get pods -n number-one -owide --show-labels
NAME                      READY   STATUS    RESTARTS   AGE   IP               NODE          NOMINATED NODE   READINESS GATES   LABELS
old-01-6f84c7b797-4jjvm   1/1     Running   0          27s   10.244.126.1     k8s-worker2   <none>           <none>            app=pod01,pod-template-hash=6f84c7b797,version=v1
old-01-6f84c7b797-s6d45   1/1     Running   0          27s   10.244.194.108   k8s-worker1   <none>           <none>            app=pod01,pod-template-hash=6f84c7b797,version=v1
old-01-6f84c7b797-v5fcx   1/1     Running   0          27s   10.244.126.3     k8s-worker2   <none>           <none>            app=pod01,pod-template-hash=6f84c7b797,version=v1


#创建前端service关联pod
[root@k8s-master ~]# vim service.yaml

apiVersion: v1
kind: Service
metadata:
  name: service01
  namespace: number-one
  labels:
    server01: server02
spec:
  type: NodePort
  ports:
  - port: 80
    nodePort: 30502  #绑定物理机的30502映射容器内nginx的80端口
    name: http
  selector:      #定义关联
    app: pod01   #关联pod的标签
    version: v1  #关联pod的标签


#创建
[root@k8s-master ~]# kubectl apply -f service.yaml 
service/service01 created

#查看
[root@k8s-master ~]# kubectl get svc -n number-one
NAME        TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
service01   NodePort   10.99.214.149   <none>        80:30502/TCP   43s

#查看service 关联的pod的信息 如ip
[root@k8s-master ~]# kubectl describe svc service01 -n number-one
Name:                     service01
Namespace:                number-one
Labels:                   server01=server02
Annotations:              <none>
Selector:                 app=pod01,version=v1
Type:                     NodePort
IP Family Policy:         SingleStack
IP Families:              IPv4
IP:                       10.99.214.149
IPs:                      10.99.214.149
Port:                     http  80/TCP
TargetPort:               80/TCP
NodePort:                 http  30502/TCP
Endpoints:                10.244.126.1:80,10.244.126.3:80,10.244.194.108:80 #这里就是关联的三个pod所在的node节点的IP
Session Affinity:         None
External Traffic Policy:  Cluster
Events:                   <none>


#查看当前k8s控制节点的ip 通过IP及映射的端口浏览器访问验证,如下图
[root@k8s-master ~]# ip a | grep ens | grep inet | awk '{print $2}'
192.168.57.131/24

k8s控制器管理,Replicaset、Deployment进行pod扩容缩容更新及回滚,蓝绿部署及金丝雀发布_控制器_09

#创建部署蓝色环境(模拟为第二版新的镜像运行的pod环境,要替代第一版的,使用的是httpd镜像端口为80)
[root@k8s-master ~]# vim new.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: new-01
  labels:
    new01: new02
  namespace: number-one
spec:
  strategy:
  replicas: 3
  selector:
    matchLabels:
      app: pod02
      version: v1
  template:
    metadata:
      labels:
        app: pod02
        version: v1
    spec:
      containers:
      - name: myhttp
        image: httpd
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 80

        
#创建
[root@k8s-master ~]# kubectl apply -f new.yaml 
deployment.apps/new-01 created

#查看 当前有了6个pod,根据名称可分辨为新旧两类,并查看标签
[root@k8s-master ~]# kubectl get pods -n number-one --show-labels
NAME                      READY   STATUS    RESTARTS   AGE   LABELS
new-01-7f88446d6d-6x7hb   1/1     Running   0          3s    app=pod02,pod-template-hash=7f88446d6d,version=v1
new-01-7f88446d6d-v6bxc   1/1     Running   0          3s    app=pod02,pod-template-hash=7f88446d6d,version=v1
new-01-7f88446d6d-xtgc8   1/1     Running   0          3s    app=pod02,pod-template-hash=7f88446d6d,version=v1
old-01-6f84c7b797-4jjvm   1/1     Running   0          28m   app=pod01,pod-template-hash=6f84c7b797,version=v1
old-01-6f84c7b797-s6d45   1/1     Running   0          28m   app=pod01,pod-template-hash=6f84c7b797,version=v1
old-01-6f84c7b797-v5fcx   1/1     Running   0          28m   app=pod01,pod-template-hash=6f84c7b797,version=v1


#修改service.yaml文件 修改关联的pod标签,其它不用修改
[root@k8s-master ~]# cat service.yaml | grep app
    app: pod02    #修改为new.yaml中pod的标签关联它

#重新执行service.yaml文件
[root@k8s-master ~]# kubectl apply -f service.yaml 
service/service01 configured

[root@k8s-master ~]# kubectl get svc -n number-one
NAME        TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
service01   NodePort   10.99.214.149   <none>        80:30502/TCP   23m

#查看当前service关联的pod IP
[root@k8s-master ~]# kubectl describe svc service01 -n number-one
Name:                     service01
Namespace:                number-one
Labels:                   server01=server02
Annotations:              <none>
Selector:                 app=pod02,version=v1
Type:                     NodePort
IP Family Policy:         SingleStack
IP Families:              IPv4
IP:                       10.99.214.149
IPs:                      10.99.214.149
Port:                     http  80/TCP
TargetPort:               80/TCP
NodePort:                 http  30502/TCP
Endpoints:                10.244.126.7:80,10.244.194.113:80,10.244.194.114:80 #已更改
Session Affinity:         None
External Traffic Policy:  Cluster
Events:                   <none>

#然后通过映射的端口重新浏览器刷新访问,就会变成了httpd的网页,这时就已经成功替换。如下图

k8s控制器管理,Replicaset、Deployment进行pod扩容缩容更新及回滚,蓝绿部署及金丝雀发布_控制器_10


2.8 基于k8s实现金丝雀发布

  金丝雀发布(又称灰度发布、灰度更新):金丝雀发布一般先发1台,或者一个小比例,例如2%的服务器,主要做流量验证用,也称为金丝雀 (Canary) 测试 (国内常称灰度测试)。


  比如集群环境内有10个pod,其中一个pod使用新的镜像进行更新,那么就可以控制访问流量有一小部分来到更新后的这个pod,以此来验证是否会有问题。简单来说就是验证更新使用。

#创建一个命名空间 进行测试
[root@k8s-master ~]# kubectl create ns test001
namespace/test001 created


#创建yaml资源文件
[root@k8s-master ~]# vim pod01.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: pod-01
  labels:
    a01: a02
  namespace: test001
spec:
  strategy:
  replicas: 3
  selector:
    matchLabels:
      app: pod01
      version: v1
  template:
    metadata:
      labels:
        app: pod01
        version: v1
    spec:
      containers:
      - name: mynginx
        image: nginx
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 80

#创建
[root@k8s-master ~]# kubectl apply -f pod01.yaml 
deployment.apps/pod-01 created

[root@k8s-master ~]# kubectl get pods -n test001
NAME                      READY   STATUS    RESTARTS   AGE
pod-01-6f84c7b797-d286w   1/1     Running   0          15s
pod-01-6f84c7b797-lq77h   1/1     Running   0          15s
pod-01-6f84c7b797-qvb6j   1/1     Running   0          15s


#创建第四个pod,第四个pod修改镜像为httpd,并创建pod之后进入暂停状态
[root@k8s-master ~]# kubectl set image deployment pod-01 mynginx=httpd -n test001 && kubectl rollout pause deployment pod-01 -n test001

deployment.apps/pod-01 image updated
deployment.apps/pod-01 paused

#当前显示四个pod,前面三个运行8分钟的使用的还是nginix镜像,第四个使用的是httpd镜像
[root@k8s-master ~]# kubectl get pods -n test001 -owide
NAME                      READY   STATUS    RESTARTS   AGE     IP               NODE          NOMINATED NODE   READINESS GATES
pod-01-6f84c7b797-d286w   1/1     Running   0          8m55s   10.244.126.11    k8s-worker2   <none>           <none>
pod-01-6f84c7b797-lq77h   1/1     Running   0          8m55s   10.244.194.115   k8s-worker1   <none>           <none>
pod-01-6f84c7b797-qvb6j   1/1     Running   0          8m55s   10.244.126.10    k8s-worker2   <none>           <none>
pod-01-8696457cc-x9n82    1/1     Running   0          2m57s   10.244.126.13    k8s-worker2   <none>           <none>

#通过node节点ip及端口访问验证,如下图所示

PS:通过暂停的方式,创建第四个pod之后暂停,那么前面三个也不会删除,还会继续提供服务,
    当确认新发布的pod没有问题后解除暂停,之后就会将前面三个nginx的pod进行取代更新为新的httpd的pod

k8s控制器管理,Replicaset、Deployment进行pod扩容缩容更新及回滚,蓝绿部署及金丝雀发布_控制器_11

#解除暂停
[root@k8s-master ~]# kubectl rollout resume deployment pod-01 -n test001
deployment.apps/pod-01 resumed

#解除暂停之后就会继续更新,删除前面三个,创建新的pod,(如下8s、6s新创建的,8m的为刚刚创建暂停时的pod)
[root@k8s-master ~]# kubectl get pods -n test001
NAME                     READY   STATUS    RESTARTS   AGE
pod-01-8696457cc-kbb7f   1/1     Running   0          8s
pod-01-8696457cc-nzzr9   1/1     Running   0          6s
pod-01-8696457cc-x9n82   1/1     Running   0          8m31s

#访问测试验证,如下图所示,即所有的pod都为httpd的服务

k8s控制器管理,Replicaset、Deployment进行pod扩容缩容更新及回滚,蓝绿部署及金丝雀发布_k8s_12

#回滚的方式同上方2.5.4标题的步骤一样

[root@k8s-master ~]# kubectl get rs -n test001
NAME                DESIRED   CURRENT   READY   AGE
pod-01-6f84c7b797   0         0         0       19m  #这里管理的pod运行的就是nginx服务的镜像
pod-01-8696457cc    3         3         3       13m  #这里管理的pod运行的则是httpd服务的镜像