Kubernetes Deployment 整理

2018/09/11 Kubernetes

简介

Deployment 提供了声明式的方法,对 Pod 和 ReplicaSet 进行更新,我们只需要在 Deployment 对象中设置好预期的状态,然后Deployment 就能够控制将实际的状态保持与预期状态一致。使用 Deployment 的典型场景,有如下几个:

  • 创建ReplicaSet,进而通过ReplicaSet启动Pod,Deployment会检查启动状态是否成功

  • 滚动升级或回滚应用

  • 应用扩容或缩容

  • 暂停(比如修改Pod模板)及恢复Deployment的运行

  • 根据Deployment的运行状态,可以判断对应的应用是否hang住

  • 清除掉不再使用的ReplicaSet

创建 Deployment

在工作中我一般是直接创建资源配置清单 yaml 文件来进行创建。Deployment 定义和 Pod 定义区别不大。下面定义一个 replicas=3 来启动三个 nginx Pod。

$ vim nginx-deploy.yaml

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: nginx-deploy
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.8.1
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 80

你可以使用 kubectl create 或 kubectl apply 去建立 nginx deployment

$ kubectl create -f nginx-deploy.yaml --record
deployment "nginx-deploy" created

将kubectl的 --record 的flag设置为 true可以在annotation中记录当前命令创建或者升级了该资源。这在未来会很有用,例如,查看在每个Deployment revision中执行了哪些命令。

通过 get可以看到目前 nginx deployment 的部署情況

$ kubectl get deployment nginx-deploy
NAME           DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
nginx-deploy   3         3         3            3           7m

以下为上面各字段输出内容器解释:

  • DESIRED:Pod 副本数量的期望值,即 Deployment 里定义的 replicas。

  • CURRENT:当前 replicas 的值,实际上是 Replica Set 里的 replica 的值,这个值不断增加,直到达到 DESIRED 为止,表明部署完成。

  • UP-TO-DATE:最新版本的 Pod 副本数量,用于只是在滚动升级过程中,有多少个Pod副本已经成功升级。

  • AVAILABEL:当前集群中可用的Pod副本数量,即集群中存活的Pod数量。

查看自动产生的 Replica Set

$ kubectl get rs|grep nginx-deploy
nginx-deploy-775fdcb79b      3         3         3         10s

查看 Pod

$ kubectl get pods|grep nginx-deploy
nginx-deploy-775fdcb79b-4jjhv      1/1       Running   0          2m
nginx-deploy-775fdcb79b-jjrwk      1/1       Running   0          2m
nginx-deploy-775fdcb79b-vgdpp      1/1       Running   0          2m

imagePullPolicy

支持三种ImagePullPolicy

  • Always:不管镜像是否存在都会进行一次拉取。
  • Never:不管镜像是否存在都不会进行拉取
  • IfNotPresent:只有镜像不存在时,才会进行镜像拉取。

注意:

  • 默认为IfNotPresent,但:latest标签的镜像默认为Always。
  • 拉取镜像时docker会进行校验,如果镜像中的MD5码没有变,则不会拉取镜像数据。
  • 生产环境中应该尽量避免使用:latest标签,而开发环境中可以借助:latest标签自动拉取最新的镜像。

滚动升级 (Rolling Update)

为了让 Kubernetes 能够按照我们所想的方式来进行滚动升级,首先我们必须在刚刚的 yaml 文件内的 spec 加入相关升级策略设定。

minReadySeconds: 5
strategy:
  type: RollingUpdate
  rollingUpdate:
    maxSurge: 1
    maxUnavailable: 1
  • minReadySeconds

  • 容器内应用程序的启动时间,kubernetes 会等待设定的时间后才继续进行升级流程;

  • 如果没有此指令的话,kubernetes 会认为该容器一启动就可以提供服务;

  • 若未设定此指令,在某些极端情况下可能会造成服务无法正常运作(新诞生的pod尚未进入可服务阶段

  • maxSurge

    • 升级过程中最多可以比原先设定所多出的 Pod 数量;

    • 该值可以是固定值或是比例(例如10%);

    • maxSurge: 1 、replicas: 5 ,代表 Kubernetes 会先开好1个新 Pod 后才删掉一个旧的 Pod ,整个升级过程中最多会有 5 + 1 个 Pod;

  • maxUnavailable

    • 最多允许有几个 Pod 处于无法提供服务的状态;

    • 当 maxSurge 不为0时,该值亦不可为0;

    • maxUnavailable:1,代表 Kubernetes 整个升级过程中最多会有 1 个 Pod 处于无法服务的状态;

添加滚动升级配置后的 nginx-deploy.yaml 如下:

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: nginx-deploy
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 1
  minReadySeconds: 5
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.8.1
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 80

apply 新的 nginx-deploy.yaml

$ kubectl apply -f nginx-deploy.yaml  --record
deployment "nginx-deploy" configured

接下来介绍三种方式进行滚动升级(以升级 docker image 为例)

  • set image
# 语法格式
$ kubectl set image deployment <deployment> <container>=<image> --record

# 示例
# 上面 nginx-deploy.yaml 中 nginx 的版本是 1.8.1 我们升级到 1.11.5
$ kubectl set image deployment nginx-deploy nginx=1.11.5 --record
deployment "nginx-deploy" image updated

检查 nginx 镜像是否更新了

$ kubectl describe deployment nginx-deploy

  • replace

修改 nginx-deploy.yaml 中的 iamge 版本。上面我们用set iamge的方式修改版本到 1.11.5,为了演示出效果,这次我们在修改镜像版本为 1.10.3;

spec:
  containers:
  - name: nginx
    image: nginx:1.10.3
    imagePullPolicy: IfNotPresent
    ports:
    - containerPort: 80

利用 replace 来进行升级而不是 apply

# 语法格式
$ kubectl replace -f <yaml> --record

# 示例
$ kubectl replace -f nginx-deploy.yaml --record

检查 nginx 镜像是否更新了

$ kubectl describe deployment nginx-deploy

  • edit
# 语法格式
$ kubectl edit deployment <deployment> --record

# 语法格式
$ kubectl edit deployment nginx-deploy --record

edit指令会直接打开编辑器的窗口,让我们来修改 Deployment 中设定的值

# 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
# reopened with the relevant failures.
#
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  annotations:
    deployment.kubernetes.io/revision: "4"
    kubernetes.io/change-cause: kubectl replace --filename=nginx-deploy.yaml --record=true
    
...

    spec:
      containers:
      - image: nginx:1.8.1
        imagePullPolicy: IfNotPresent
        name: nginx
...

这次我们修改为 1.13.2 然后保存退出

检查 nginx 镜像是否更新

查询升级状态

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

暂停滚动升级

$ kubectl rollout pause deployment <deployment>

继续滚动升级

$ kubectl rollout resume deployment <deployment>

回滚

当升级完成后,如果其他同事发现此次升级造成了服务不稳定的情况,但他们不清除之前我们是在哪个版本。在这种情况下,我们可以利用 rollback 回退到之前的版本。

在之前的操作中,我们在每条指令后面加了一个--record的参数,这个参数主要告诉 kubernetes 记录我们此次执行的命令,如此一来我们就能更加清楚不同版本之间我们做了哪些操作。

$ kubectl create -f nginx-deploy.yaml --record
deployment "nginx-deploy" created

# 更新镜像
$ kubectl set image deployment nginx-deploy nginx=1.11.5 --record
deployment "nginx-deploy" image updated

# 查看升级记录
$ kubectl rollout history deployment nginx-deploy
deployments "nginx-deploy"
REVISION  CHANGE-CAUSE
1         kubectl create --filename=nginx-deploy.yaml --record=true
2         kubectl set image deployment nginx-deploy nginx=1.11.5 --record=true

假设我们现在要回滚到 revision 1 这个版本

# 回滚到上一个版本
$ kubectl rollout undo deployment <deployment>

# 回滚到指定的版本
$ kubectl rollout undo deployment <deployment> --to-revision=<revision>

# 示例回滚到指定的版本
$ kubectl rollout undo deployment nginx-deploy --to-revision=1
deployment "nginx-deploy"

检查 nginx 是否回滚到之前的版本

由于每次修改的指令都会存储在 replica set 中,因此我们可以利用 .spec.revisionHistoryLimit 来决定我们要保留多久以前的记录(此参数需要在第一次建立 Deployment 时就设定好)。

添加 revisionHistoryLimit 参数后的 nginx-deploy.yaml 如下:

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: nginx-deploy
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 1
  minReadySeconds: 5
  revisionHistoryLimit: 10
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.8.1
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 80

删除 Deployment

删除操作比较简单如下:

# 语法格式
$ kubectl delete -f <yaml>
或者
$ kubectl delete <deployment> deployment_name

# 示例
$ kubectl delete -f nginx-deploy.yaml 
deployment "nginx-deploy" deleted 

或者

$ kubectl delete deployment nginx-deploy

参考资料

http://shiyanjun.cn/archives/1671.html#comments https://www.kubernetes.org.cn/deployment

Search

    Table of Contents