Pod 滚动升级(Deployment)

参考链接

使用kubernetes 进行升级的时候并不需要停止业务,kubectl 支持滚动升级的方式,每次更新一个pod,而不是同时删除整个服务。
目前的kubernetes 版本只支持Replication Controllers的方式实现滚动升级。然而,官方推荐的方式是使用Deployments. Deployments是一个更高级别的控制器,它以声明方式自动执行应用程序的滚动更新,因此推荐使用。
这里将重点介绍使用Deployment的方式。

  1. 创建一个nginx应用的deployment:
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.7.9
        ports:
        - containerPort: 80

可以看到,创建了3个Pod副本:

# kubectl  get pods
NAME                                READY     STATUS    RESTARTS   AGE
nginx-deployment-75675f5897-jhr26   1/1       Running   0          36m
nginx-deployment-75675f5897-n77ds   1/1       Running   0          36m
nginx-deployment-75675f5897-ns6pn   1/1       Running   0          36m

更新镜像为nginx 1.10.3:

# kubectl  set image deployment nginx-deployment nginx=nginx:1.10.3

# kubectl  get pods
NAME                                READY     STATUS        RESTARTS   AGE
nginx-deployment-75675f5897-n77ds   0/1       Terminating   0          47m
nginx-deployment-75d56bb955-54686   1/1       Running       0          7s
nginx-deployment-75d56bb955-5zxqz   1/1       Running       0          10s
nginx-deployment-75d56bb955-bxqd9   1/1       Running       0          8s

# kubectl  get pods -o wide
NAME                                READY     STATUS    RESTARTS   AGE       IP           NODE
nginx-deployment-75d56bb955-54686   1/1       Running   0          2m        10.2.74.9    10.0.0.3
nginx-deployment-75d56bb955-5zxqz   1/1       Running   0          2m        10.2.74.8    10.0.0.3
nginx-deployment-75d56bb955-bxqd9   1/1       Running   0          2m        10.2.62.16   10.0.0.2

# curl --head 10.2.62.16
HTTP/1.1 200 OK
Server: nginx/1.10.3
Date: Wed, 20 Jun 2018 10:52:10 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Tue, 31 Jan 2017 15:01:11 GMT
Connection: keep-alive
ETag: "5890a6b7-264"
Accept-Ranges: bytes

我们也可以直接使用编辑配置文件的方式,直接修改nginx镜像版本为1.12.2:

# kubectl edit deployment nginx-deployment

# kubectl  get pods -o wide
NAME                                READY     STATUS    RESTARTS   AGE       IP           NODE
nginx-deployment-7498dc98f8-756tq   1/1       Running   0          11s       10.2.62.17   10.0.0.2
nginx-deployment-7498dc98f8-g265v   1/1       Running   0          13s       10.2.74.10   10.0.0.3
nginx-deployment-7498dc98f8-hh6wv   1/1       Running   0          10s       10.2.74.11   10.0.0.3

curl  --head 10.2.62.17
HTTP/1.1 200 OK
Server: nginx/1.12.2
...

在进行滚动升级的过程中,Deployment 进行初始化时,创建了一个新的ReplicaSet,新的ReplicaSet 逐渐创建新的Pod 副本,旧的ReplicaSet 逐渐销毁旧的副本,并始终保持副本数量恒定,逐步滚动替换。
可以查看ReplicaSet的状态:

# kubectl  get rs -o  wide
NAME                          DESIRED   CURRENT   READY     AGE       CONTAINERS   IMAGES         SELECTOR
nginx-deployment-7498dc98f8   3         3         3         44m       nginx        nginx:1.12.2   app=nginx,pod-template-hash=3054875494
nginx-deployment-75675f5897   0         0         0         1h        nginx        nginx:1.7.9    app=nginx,pod-template-hash=3123191453
nginx-deployment-75d56bb955   0         0         0         59m       nginx        nginx:1.10.3   app=nginx,pod-template-hash=3181266511

查看更新的状态:

kubectl rollout status deployment/nginx-deployment

在Deployment的定义中,可以通过spec.strategy指定的Pod更新策略,支持两种策略:

  • Recreate(重建):设置spec.strategy.type=Recreate, 表示Deployment在更新Pod的时候,会先杀掉所有正在运行的Pod,然后创建新的Pod。
  • RollingUpdate(滚动更新): 设置 spec.strategy.type=RollingUpdate,表示Deployment会以滚动更新的方式来逐个更新Pod。可以指定

RollingUpdate(滚动更新)有两个主要参数,来控制更新的Pod副本数量:

  • .spec.strategy.rollingUpdate.maxUnavailable : 用于指定Deployment在更新过程中不可用状态的Pod数量上限。该maxUnavailable的数值可以是绝对值正整数,也可以是Pod期望的副本数的百分比(例如10%)。如果设置为百分比,那么系统会先以向下取整的方式计算出绝对值整数,但是当.spec.strategy.rollingUpdate.maxSurge值为0时,其值不能为0。 默认情况下为25%。
  • .spec.strategy.rollingUpdate.maxSurge: 用于指定Deployment更新Pod过程中Pod总数超过Pod期望副本部分的最大值。该maxSurge的数值可以是绝对值(例如5)或Pod期望副本数的百分比(例如10%)。如果设置为百分比,那么系统会先按照向上取整的方式计算出绝对数值。如果MaxUnavailable的值为0,则这个值不能为0,默认值是25%。

需要注意更新Deployment的标签选择器(Label selector)的情况。通常不鼓励更新Deployment 的标签选择器,这样会导致Deployment选择的Pod列表发生变化,也可能与其它控制器产生的冲突。
如果要更新Deployment标签选择器,有以下注意事项:

  • 添加标签选择器时,必须同步修改Deployment配置的Pod标签,为Pod添加新的标签,否则Deployment的更新会报验证错误而失败。更改标签之后,旧的rs将会依旧存在,deployment将无法管理旧的RS。直接执行kubectl delete rs <rs-name>即可删除。
  • 更新标签选择器,即更新选择器中标签的键或值,也会产生与添加选择器标签类似的效果。
  • 删除标签选择器,即从Deployment的标签选择器中删除一个或者多个标签,该Deployment的ReplicaSet 和Pod不会受到任何影响,但需要注意的是,被删除的标签仍然会存在于现有的Pod和ReplicaSet上。

Deployment的回滚

1、查看Deployment部署的历史记录:

kubectl  rollout history deployment/nginx-deployment

如果查看到的结果为None,则需要在创建和更新deployment时加上 --record参数.

2、查看特定的版本信息:

# kubectl  rollout history deployment/nginx-deployment --revision=3

3、撤销本次发布,回滚到上一个版本:

# kubectl rollout undo deployment/nginx-deployment

4、可以指定版本回滚:

# kubectl rollout undo deployment/nginx-deployment --to-revision=2

5、查看回滚状态:

# kubectl rollout status deployments nginx-deployment

Waiting for rollout to finish: 2 out of 3 new replicas have been updated...
Waiting for rollout to finish: 2 out of 3 new replicas have been updated...
Waiting for rollout to finish: 2 out of 3 new replicas have been updated...
Waiting for rollout to finish: 1 old replicas are pending termination...
Waiting for rollout to finish: 1 old replicas are pending termination...
deployment "nginx-deployment" successfully rolled out

暂停和恢复Deployment的部署操作

对于一次复杂的Deplyment配置修改,为了避免频繁触发Deployment的更新操作,可以先暂停Deployment的更新操作,然后进行配置修改,等所有的修改完成后,再恢复Deployment,一次性触发完整的更新操作。这样就可以避免不必要的Deployment的更新操作。

1、 暂停Deployment的操作

# kubectl  rollout pause deployment/nginx-deployment

2、修改deployment的镜像信息:

# kubectl set image deploy/nginx-deployment nginx=nginx:1.12.2

# 查看更新记录,没有变化
# kubectl  rollout history deploy/nginx-deployment
deployments "nginx-deployment"
REVISION  CHANGE-CAUSE
1         <none>
4         <none>
5         <none>

3、再次更新容器资源限制:

# kubectl set resources deployment nginx-deployment -c=nginx --limits=cpu=200m,memory=512Mi

4、恢复Deployment的部署操作

kubectl rollout resume deploy/nginx-deployment

5、历史记录以及更新:

# kubectl  rollout history deploy/nginx-deployment
deployments "nginx-deployment"
REVISION  CHANGE-CAUSE
1         <none>
4         <none>
5         <none>
6         <none>

k8s还提供了针对RC进行滚动升级的方式,使用 kubectl rolling-update 命令来执行。由于RC升级过程无法查看记录,无法进行版本数量的精细化控制,将逐渐被RS取代,所以建议优先使用Deployment的方式完成Pod的部署升级,这里不做讨论。

其他对象的更新策略

DaemonSet的更新策略

  • OnDelete:这是用于向后兼容的默认更新策略。 使用OnDelete更新策略,在更新DaemonSet模板之后,只有在手动删除旧的DaemonSet窗格时才会创建新的DaemonSet Pod。 这与Kubernetes版本1.5或更早版本中的DaemonSet是一致的。
  • RollingUpdate:通过RollingUpdate更新策略,在更新DaemonSet模板后,旧的DaemonSet窗格将被终止,并且将以受控的方式自动创建新的DaemonSet。不过不支持DaemonSet的更新历史记录,并且回滚并不能如Deployment直接通过kubectl rollback 命令来实现。