侧边栏壁纸
  • 累计撰写 51 篇文章
  • 累计创建 23 个标签
  • 累计收到 0 条评论

目 录CONTENT

文章目录

K8s Pod 和 Service 6

zhanjie.me
2020-11-12 / 0 评论 / 0 点赞 / 1 阅读 / 0 字

6.1 Deployment 简介

Deployment 资源对象为 Pod 和 ReplicaSet(ReplicationController 的升级版)提供了声明式定义,在 Deployment YAML 文件中描述期望达到的目标状态,Deployment Controller 会创建符合目标状态的 ReplicaSet 和 Pod,如果更新 Deployment,对应的 ReplicaSet 和 Pod 的状态也会改变以符合新的目标状态。

Deployment 的典型应用场景包括:

  1. 定义 Deployment 来创建 ReplicaSet 和 Pod
    使用 Deployment 来创建 ReplicaSet,ReplicaSet 又会在后台创建 Pod。可以检查 Pod 的启动状态,观察是成功还是失败。
    也可以根据 Deployment 的状态判断上线是否 hang 住了。
  2. 滚动升级和回滚应用

通过更新 Deployment 的 PodTemplateSpec 字段来声明 Pod 的新状态,更新 Deployment 后会创建一个新的 ReplicaSet,Deployment 会按照控制的速率删除由旧的 ReplicaSet 创建的 Pod、并使用新的 ReplicaSet 创建新的 Pod,当新生成的 Pod 达到要求的目标状态后,会清除旧的 ReplicaSet。

如果当前状态不稳定,可以回滚到之前的 Deployment revision,每次回滚都会更新 Deployment 的 revision。

  1. 扩容和缩容
    根据系统负载进行 Deployment 的扩容和缩容。
  2. 暂停和继续 Deployment
    暂停 Deployment 并修改 PodTemplateSpec 字段,然后重新恢复上线。

运行示例

定义一个 Deployment YAML 文件,它可以创建一个 Replica Set 来启动 3 个 nginx Pod,新建 nginx-deployment.yaml 文件,并向其中写入如下内容:

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

执行创建:

$ kubectl create -f nginx-deployment.yaml
deployment.apps/nginx-deployment created

查看 Deployment 的状态、RS 的状态、以及运行的 Pod 副本数量:

# 可以看到已经创建了 3 个符合要求的 Pod,这 3 个 Pod 都是最新的、都处于可用状态
$ kubectl get deployments
NAME               READY   UP-TO-DATE   AVAILABLE   AGE
nginx-deployment   3/3     3            3           34s

# 该 RS 需要 3 个 Pod,当前符合要求的有 3 个 Pod 并且已经创建好,RS 名字的组成:<Deployment 的名字>-<Pod template 的 hash 值>
$ kubectl get rs
NAME                          DESIRED   CURRENT   READY   AGE
nginx-deployment-56f8998dbc   3         3         3       92s

# 使用 nginx-deployment-56f8998dbc RS 创建的 3 个 Pod
$ kubectl get pods
NAME                                READY   STATUS    RESTARTS   AGE
nginx-deployment-56f8998dbc-6w9ll   1/1     Running   0          2m14s
nginx-deployment-56f8998dbc-nwv2w   1/1     Running   0          2m14s
nginx-deployment-56f8998dbc-spc6s   1/1     Running   0          2m14s

查看 nginx-deployment 的详细信息:

$ kubectl describe deployment nginx-deployment
Name:                   nginx-deployment
Namespace:              user-test
CreationTimestamp:      Thu, 12 Nov 2020 21:21:39 +0800
Labels:                 <none>
Annotations:            deployment.kubernetes.io/revision: 1
Selector:               app=nginx
Replicas:               3 desired | 3 updated | 3 total | 3 available | 0 unavailable
StrategyType:           RollingUpdate
MinReadySeconds:        0
RollingUpdateStrategy:  25% max unavailable, 25% max surge
Pod Template:
  Labels:  app=nginx
  Containers:
   nginx:
    Image:        nginx:1.9.1
    Port:         80/TCP
    Host Port:    0/TCP
    Environment:  <none>
    Mounts:       <none>
  Volumes:        <none>
Conditions:
  Type           Status  Reason
  ----           ------  ------
  Available      True    MinimumReplicasAvailable
  Progressing    True    NewReplicaSetAvailable
OldReplicaSets:  <none>
NewReplicaSet:   nginx-deployment-56f8998dbc (3/3 replicas created)
Events:
  Type    Reason             Age    From                   Message
  ----    ------             ----   ----                   -------
  Normal  ScalingReplicaSet  2m57s  deployment-controller  Scaled up replica set nginx-deployment-56f8998dbc to 3

在 Annotations 记录了版本 revision: 1

默认更新策略使用的是 RollingUpdate

max unavailable 和 max surge 的默认值都为 25%

ReplicaSet 为 nginx-deployment-56f8998dbc


6.2 Deployment 的升级

设想一个场景,服务需要升级,传统的做法是:暂停与该服务相关的所有 Pod,下载新镜像并创建新的 Pod,这种方式不好的地方是升级的过程中,会导致服务不可用,进而影响整体的产品体验。因此 Kubernetes 提供了滚动升级功能来解决这个问题。

通常使用 Deployment 来创建 Pod 资源对象,当 Pod 在运行中,可以修改 Deployment 的 Pod 定义或是镜像名称,并应用到 Deployment 对象上,这样就完成了 Deployment 的自动更新操作。在更新过程中发生了错误,可以通过回滚操作恢复 Pod 的版本。

这里我们将 Pod 的镜像更新为 nginx:1.19:

$ kubectl set image deployment/nginx-deployment nginx=nginx:1.19
deployment.apps/nginx-deployment image updated

也可以使用 kubectl edit 命令进行更新,把 image 字段下的 nginx:1.9.1 更改为 nginx:1.19

$ kubectl edit deployment/nginx-deployment
deployment.extensions/nginx-deployment edited

上面修改了镜像名,就会触发系统完成 Deployment 所有运行 Pod 的滚动升级操作,查看 rollout 的状态:

$ kubectl rollout status deployment/nginx-deployment
deployment "nginx-deployment" successfully rolled out

需要注意的是:当且仅当 Deployment 的 .spec.template 字段下的 labels 或是 image 更新时才会触发 rollout,其它的更新并不会触发 rollout。

查看更新后的 Deployment、RS、Pods:

# 可以看到 UP-TO-DATE 的数量已经变成了 3,说明已经全部更新完成
$ kubectl get deployment
NAME               READY   UP-TO-DATE   AVAILABLE   AGE
nginx-deployment   3/3     3            3           43m

# 查看两个 RS 的最终状态,可以看到旧的 RS 已经没有 Pod 在运行了,新的 RS 创建好了 3 个新的 Pod
$ kubectl get rs
NAME                          DESIRED   CURRENT   READY   AGE
nginx-deployment-56f8998dbc   0         0         0       43m
nginx-deployment-687548bb8c   3         3         3       4m58s

# 由新 nginx-deployment-687548bb8c RS 创建出来的 3 个 Pod
$ kubectl get pods
NAME                                READY   STATUS    RESTARTS   AGE
nginx-deployment-687548bb8c-89268   1/1     Running   0          5m22s
nginx-deployment-687548bb8c-fff9j   1/1     Running   0          5m29s
nginx-deployment-687548bb8c-vzxbp   1/1     Running   0          5m37s

查看现在 nginx-deployment 的详细信息:

$ kubectl describe deployments/nginx-deployment
...
NewReplicaSet:   nginx-deployment-687548bb8c (3/3 replicas created)
Events:
  Type    Reason             Age    From                   Message
  ----    ------             ----   ----                   -------
  Normal  ScalingReplicaSet  45m    deployment-controller  Scaled up replica set nginx-deployment-56f8998dbc to 3
  Normal  ScalingReplicaSet  6m48s  deployment-controller  Scaled up replica set nginx-deployment-687548bb8c to 1
  Normal  ScalingReplicaSet  6m40s  deployment-controller  Scaled down replica set nginx-deployment-56f8998dbc to 2
  Normal  ScalingReplicaSet  6m40s  deployment-controller  Scaled up replica set nginx-deployment-687548bb8c to 2
  Normal  ScalingReplicaSet  6m33s  deployment-controller  Scaled down replica set nginx-deployment-56f8998dbc to 1
  Normal  ScalingReplicaSet  6m33s  deployment-controller  Scaled up replica set nginx-deployment-687548bb8c to 3
  Normal  ScalingReplicaSet  6m32s  deployment-controller  Scaled down replica set nginx-deployment-56f8998dbc to 0

从 Events 事件中我们可以看到 Pod 的更新过程:

  • 系统创建了一个新的 RS(nginx-deployment-687548bb8c),将其副本数量扩展到 1;将旧的 RS(nginx-deployment-56f8998dbc)副本数量缩减为 2
  • 新的 RS 副本数量扩展到了 2,旧的 RS 副本数量缩减为 1
  • 新的 RS 副本数量扩展到了 3,旧的 RS 副本数量缩减为 0

就是通过这样逐步替换的过程完成了整个 Pod 的更新,这个过程中保证了整体服务不中断,并且副本数量始终维持为用户指定的数量。

Deployment 通过字段 spec.strategy 设置 Pod 更新策略,上面创建的 Deployment 的相关默认设置如下:

spec:
  strategy:
    rollingUpdate:
      maxSurge: 25%
      maxUnavailable: 25%
    type: RollingUpdate

Deployment 的更新策略有两种:

  • Recreat(重建): 先 kill 掉所有正在运行的 Pod,然后创建新的 Pod。
  • RollingUpdate(滚动更新): 逐个更新 Pod。可以在字段 spec.strategy.rollingUpdate 下设置两个参数 maxSurge 和 maxUnavailable 来控制滚动更新的过程。

关于两个参数的详细说明:

  • maxUnavailable:指定更新过程中不可用状态的 Pod 数量上限。默认值 25% 指的是:Pod 期望副本数的 25%,然后系统会以向下取整的方式计算出绝对值(整数)。对于这里而言,当开始滚动更新时,旧的 RS 立即将副本数缩小到所需副本总数的 75%(3 * 75% = 2.25,然后向下取整,绝对值为 2),一旦新的 Pod 创建并准备好,旧的 RS 会进一步缩容,新的 RS 会进一步扩容,整个过程中系统在任意时刻都可以确保可用状态的 Pod 总数至少占 Pod 期望副本总数的 75%。
  • maxSurge:指定更新过程中 Pod 总数超过 Pod 期望副本数部分的最大值。默认值 25% 指的是:Pod 期望副本数的 25%,然后系统会以向上取整的方式计算出绝对值(整数)。对于这里而言,新的 RS 可以在滚动更新开始时立即进行副本数扩容,只要保证新旧 RS 的 Pod 副本总数之和不超过期望副本数的 125% 即可。一旦旧的 Pod 被 kill 掉,新的 RS 会进一步扩容。在整个过程中系统在任意时刻都能确保新旧 RS 的 Pod 副本总数之和不超过所需副本数的 125%。

6.3 Deployment 的回滚

有的时候由于升级后的 Deployment 不稳定,我们需要将 Deployment 回滚到旧的版本。默认情况下,kubernetes 会在系统中保存所有 Deployment 的 rollout 历史记录,方便随时回退。

这里需要注意的是,只有更新 Deployment template 中的 label 和 image,才会创建一个新的 revision,而扩缩容不会创建 revision,所以回退历史 revision 时,只有 Deployment 中的 template 部分才会回退。

比如先进行一次升级,要修改容器的镜像,但是不小心手误写成了 nginx:1.91,这是一个不存在的版本镜像,所以 Deployment 不会更新成功:

$ kubectl set image deployment/nginx-deployment nginx=nginx:1.91
deployment.apps/nginx-deployment image updated

查看 Deployment 的部署过程以及 RS 的状态:

# 可以看到部署过程卡住了,按 Ctrl+C 终止查看
$ kubectl rollout status deployments nginx-deployment
Waiting for deployment "nginx-deployment" rollout to finish: 1 out of 3 new replicas have been updated...
^C

# 新创建的 nginx-deployment-8456d5d8c5 RS 也卡在了第一个 Pod 的创建过程中,主要是镜像拉取不成功
$ kubectl get rs
NAME                          DESIRED   CURRENT   READY   AGE
nginx-deployment-546bbd4947   3         3         3       96s
nginx-deployment-8456d5d8c5   1         1         0       71s

使用 kubectl rollout history 命令查看部署的历史记录,由于我们在创建 Deployment 的时候没有使用 --record 参数,CHANGE-CAUSE 中没有记录下更新每个版本使用的命令,在创建的时候可以把这个参数加上:

$ kubectl rollout history deployment nginx-deployment
deployment.apps/nginx-deployment
REVISION  CHANGE-CAUSE
1         <none>
2         <none>

使用 --revision=<N> 参数可以查看特定版本的详细信息:

$ kubectl rollout history deployment nginx-deployment --revision=2
deployment.apps/nginx-deployment with revision #2
Pod Template:
  Labels:   app=nginx
    k8s=nginx-pod
    pod-template-hash=8456d5d8c5
  Containers:
   nginx:
    Image:  nginx:1.91
    Port:   80/TCP
    Host Port:  0/TCP
    Environment:    <none>
    Mounts: <none>
  Volumes:  <none>

撤销本次发布并回滚到上一个部署版本:

$ kubectl rollout undo deployment/nginx-deployment
deployment.extensions/nginx-deployment rolled back

# 也可以使用参数 --to-revision 指定回滚到的部署版本
$ kubectl rollout undo deployment/nginx-deployment --to-revision=1

现在检查 Deployment 是否回滚到了上一个版本:

$ kubectl describe deployments.apps nginx-deployment
...
NewReplicaSet:   nginx-deployment-546bbd4947 (3/3 replicas created)
Events:
  Type    Reason             Age    From                   Message
  ----    ------             ----   ----                   -------
  Normal  ScalingReplicaSet  5m52s  deployment-controller  Scaled up replica set nginx-deployment-546bbd4947 to 3
  Normal  ScalingReplicaSet  5m27s  deployment-controller  Scaled up replica set nginx-deployment-8456d5d8c5 to 1
  Normal  ScalingReplicaSet  25s    deployment-controller  Scaled down replica set nginx-deployment-8456d5d8c5 to 0

从 Events 事件中可以看到 Deployment 回滚的过程是:先创建一个新 RS(nginx-deployment-546bbd4947)扩容到 3 个 Pod,然后旧的 RS(nginx-deployment-8456d5d8c5)的 Pod 从 1 缩减为 0。


6.4 Deployment 的暂停与恢复

有的时候需要频繁的对 Deployment 的配置进行修改,如果每修改一次就触发一次更新的话会显得比较麻烦,这个时候可以暂停 Deployment 的更新操作,多次修改配置,然后再恢复 Deployment,一次性触发完整的更新操作。

这里先删除掉前面创建的 nginx-deployment,然后重新使用文件进行创建(注意创建的时候可以加上 --record 参数):

$ kubectl create -f nginx-deployment.yaml --record
deployment.apps/nginx-deployment created
$ kubectl get deployments
NAME               READY   UP-TO-DATE   AVAILABLE   AGE
nginx-deployment   3/3     3            3           22s
$ kubectl get rs
NAME                          DESIRED   CURRENT   READY   AGE
nginx-deployment-546bbd4947   3         3         3       32s

使用命令 kubectl rollout pause 暂停 Deployment 的更新操作:

$ kubectl rollout pause deployment nginx-deployment
deployment.apps/nginx-deployment paused

修改 Deployment 的镜像信息为 nginx:1.9.1:

$ kubectl set image deployment/nginx-deployment nginx=nginx:1.9.1
deployment.apps/nginx-deployment image updated

查看更新历史记录,可以看到并没有触发对应的更新操作:

$ kubectl rollout history deployment/nginx-deployment
deployment.apps/nginx-deployment
REVISION  CHANGE-CAUSE
1         kubectl create --namespace=user-test --filename=nginx-deployment.yaml --record=true

这里再一次更新 Deployment 配置,限制容器的资源使用:

$ kubectl set resources deployment nginx-deployment -c=nginx --limits=cpu=200m,memory=512Mi
deployment.apps/nginx-deployment resource requirements updated

恢复 Deployment 的部署操作:

$ kubectl rollout resume deploy nginx-deployment
deployment.apps/nginx-deployment resumed

查看 RS 资源和 Deployment 的详细信息:

# 可以看到新创建的 RS(nginx-deployment-5bd45c7d95)
$ kubectl get rs
NAME                          DESIRED   CURRENT   READY   AGE
nginx-deployment-546bbd4947   0         0         0       5m55s
nginx-deployment-5bd45c7d95   3         3         3       46s

# 观察 nginx-deployment 的配置信息是否修改
$ kubectl describe deployment nginx-deployment
...
Annotations:            deployment.kubernetes.io/revision: 2
                        kubernetes.io/change-cause: kubectl create --namespace=user-test --filename=nginx-deployment.yaml --record=true
...
Pod Template:
  Labels:  app=nginx
           k8s=nginx-pod
  Containers:
   nginx:
    Image:      nginx:1.9.1
    Port:       80/TCP
    Host Port:  0/TCP
    Limits:
      cpu:        200m
      memory:     512Mi
...
0

评论区