k8s-deployment

2021-12-15

1. 简介

一个 DeploymentPodsReplicaSets 提供声明式的更新能力。

用户负责描述 Deployment 中的 目标状态,而 Deployment 控制器(Controller)以受控速率更改实际状态, 使其变为期望状态。你可以定义 Deployment 以创建新的 ReplicaSet,或删除现有 Deployment, 并通过新的 Deployment 收养其资源。

ReplicaSet 的目的是维护一组在任何时候都处于运行状态的 Pod 副本的稳定集合。 因此,它通常用来保证给定数量的、完全相同的 Pod 的可用性。

也就是 Deployment 通过管理 ReplicaSet 来确保任何时间都有指定数量的 Pod 副本在运行。

2. quick start

2.1 创建deploy

如果没有现成的模板,可以使用 --dry-run 快速生成一个deploy资源模板

$ kubectl create deploy nginx-test --image=nginx --dry-run=client --replicas=3  -oyaml -n test1

# 输出内容如下
apiVersion: apps/v1
kind: Deployment
metadata:
  creationTimestamp: null
  labels:
    app: nginx-test
  name: nginx-test
  namespace: test1
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx-test
  strategy: {}
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: nginx-test
    spec:
      containers:
      - image: nginx
        name: nginx
        resources: {}
status: {}

新建一个deploy模板 deploy-nginx.yaml,内容如下:

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    # 自定义标签
    app: nginx-deploy-test
  # 资源名称
  name: nginx-test-1
  namespace: test1
spec:
  # pod 副本数量
  replicas: 3
  # 模板选择器
  selector:
    matchLabels:
      # 选择下方声明的 template
      app: nginx-test
  template:
    metadata:
      labels:
        app: nginx-test
    spec:
      containers:
      - image: nginx
        name: nginx

创建deploy

$ kubectl create -f deploy-nginx.yaml

在该例中:

  • 创建名为nginx-test-1(由 .metadata.name 字段标明)的 deployment
  • 该deployment创建三个(由 replicas 字段标明)Pod副本
  • selector 字段定义 Deployment 如何查找要管理的 Pods。 在这里,选择在 Pod 模板中定义的标签(app: nginx-test)。 不过,更复杂的选择规则是也可能的,只要 Pod 模板本身满足所给规则即可。
  • template字段包含以下子字段:
    • Pod 被使用 labels 字段打上 app: nginx-test 标签。
    • Pod 模板约定(即 .template.spec 字段) Pods nginx 容器。
    • 创建一个容器并使用 name 字段将其命名为 nginx

说明:

spec.selector.matchLabels 字段是 {key,value} 键值对映射。 在 matchLabels 映射中的每个 {key,value} 映射等效于 matchExpressions 中的一个元素, 即其 key 字段是 “key”,operator 为 “In”,values 数组仅包含 “value”。 在 matchLabelsmatchExpressions 中给出的所有条件都必须满足才能匹配。

2.2 查看deploy

查看deploy 基本信息

# kubectl get -f deploy-nginx.yaml
$ kubectl get deploy -n test1

NAME           READY   UP-TO-DATE   AVAILABLE   AGE
nginx-test-1   3/3     3            3           4m20s

查看deploy 详细信息

# kubectl get -f deploy-nginx.yaml -o wide
$ kubectl get deploy -n test1 -o wide

NAME           READY   UP-TO-DATE   AVAILABLE   AGE     CONTAINERS   IMAGES   SELECTOR
nginx-test-1   3/3     3            3           4m54s   nginx        nginx    app=nginx-test

查看deploy 详情信息

# kubectl describe deploy/nginx-test-1 -n test1
$ kubectl describe -f deploy-nginx.yaml

Name:                   nginx-test-1
Namespace:              test1
CreationTimestamp:      Sun, 12 Dec 2021 22:38:12 +0800
Labels:                 app=nginx-deploy-test
Annotations:            deployment.kubernetes.io/revision: 1
Selector:               app=nginx-test
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-test
  Containers:
   nginx:
    Image:        nginx
    Port:         <none>
    Host Port:    <none>
    Environment:  <none>
    Mounts:       <none>
  Volumes:        <none>
Conditions:
  Type           Status  Reason
  ----           ------  ------
  Available      True    MinimumReplicasAvailable
  Progressing    True    NewReplicaSetAvailable
OldReplicaSets:  <none>
NewReplicaSet:   nginx-test-1-795d659f45 (3/3 replicas created)
Events:
  Type    Reason             Age    From                   Message
  ----    ------             ----   ----                   -------
  Normal  ScalingReplicaSet  6m58s  deployment-controller  Scaled up replica set nginx-test-1-795d659f45 to 3

查看pod情况

$ kubectl get po -n test1

NAME                            READY   STATUS    RESTARTS   AGE
nginx-test-1-795d659f45-7rlq7   1/1     Running   0          15m
nginx-test-1-795d659f45-dfjfb   1/1     Running   0          15m
nginx-test-1-795d659f45-m45qn   1/1     Running   0          15m

查看deploy上线状态

$ kubectl rollout status deploy/nginx-test-1 -n test1

deployment "nginx-test-1" successfully rolled out

2.3 修改deploy

说明: 仅当 Deployment Pod 模板(即 .spec.template)发生改变时,例如模板的标签或容器镜像被更新, 才会触发 Deployment 上线。 其他更新(如对 Deployment 执行扩缩容的操作)不会触发上线动作。

  1. 直接修改资源模板,修改完直接apply即可

    $ kubectl apply -f deploy-nginx.yaml
    
  2. 使用命令修改,修改完保存即可

    $ kubectl edit deploy/nginx-test-1 -n test1
    
  3. 修改镜像版本

    • --record=true 记录当前操作,后续会用到
    $ kubectl set image deploy/nginx-test-1 nginx=nginx:1.16.1 -n test1 --record=true
    

2.4 删除deploy

  1. 使用命令删除

    $ kubectl delete deploy/nginx-test-1 -n test1
    
  2. 使用资源文件

    $ kubectl delete -f deploy-nginx.yaml
    

3. 更新服务版本

3.1 创建deploy

deploy-nginx.yaml deploy 模板信息如下:

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: nginx-deploy-test
  name: nginx-test-1
  namespace: test1
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx-test
  template:
    metadata:
      labels:
        app: nginx-test
    spec:
      containers:
      - image: nginx:1.16.1
        name: nginx

3.2 修改deploy文件更新

# 修改模板文件中的镜像版本号
$ sed -i 's/nginx:1.16.1/nginx:latest/g' deploy-nginx.yaml
# 应用修改后的模板文件
# --record的作用是将当前命令记录到 revision 记录中,这样就可以知道每个 revison 对应的是哪个配置文件。
$ kubectl apply -f deploy-nginx.yaml --record

我们从图中可以看到pod执行过程是等待新的pod启动完成,在进行销毁旧的pod,这样就完成了集群的滚动更新工作

更新完成后我们也可以查看一下迭代信息和修订历史详细信息

3.2 使用edit命令更新

$ kubectl edit deploy/nginx-test-1 -n test1

deployment.apps/nginx-test-1 edited

一般临时修改一下部署信息会使用一下edit。

一般不太推荐使用edit进行编辑,推出即保存。虽然版本更新成功了,history也有保留,但是最终的修改记录没有持久化到模板文件中。

3.3 使用set image 命令更新

# nginx=nginx:1.16.1 <container-name>=<image-name>:<version>
$ kubectl set image deploy/nginx-test-1 -n test1 nginx=nginx:1.16.1 --record

能比edit更新强点,至少可以很清楚的在history中查看版本更新的情况

4. 回滚服务版本

我们使用上面的更新应用时k8s都会记录一个revision(版本),这样我们就可以通过这个版本记录回滚到特定的版本中

  1. 回滚到上一个版本

    $ kubectl rollout undo deploy/nginx-test-1  -n test1
    
  2. 回滚到指定版本

    $ kubectl rollout undo deploy/nginx-test-1 --to-revision=3 -n test1
    

rollout命令参数如下

$ kubectl rollout -h
Manage the rollout of a resource.

 Valid resource types include:

  *  deployments
  *  daemonsets
  *  statefulsets

Examples:
  # Rollback to the previous deployment
  kubectl rollout undo deployment/abc

  # Check the rollout status of a daemonset
  kubectl rollout status daemonset/foo

Available Commands:
  history     显示 rollout 历史
  pause       标记提供的 resource 为中止状态
  restart     Restart a resource
  resume      继续一个停止的 resource
  status      显示 rollout 的状态
  undo        撤销上一次的 rollout

Usage:
  kubectl rollout SUBCOMMAND [options]

默认配置下,k8s 只会保留最近的几个 revision,可以在 Deployment 配置文件中通过 revisionHistoryLimit 属性增加 revision 数量。(同时rs和我们rollout中记录的版本号相同,可以理解为rollout中显示的REVISION版本号实际上就是rs中的版本)

revisionHistoryLimit(历史版本记录):Deployment revision history存储在它控制的ReplicaSets中。默认保存记录10个     .spec.revisionHistoryLimit 是一个可选配置项,用来指定可以保留的旧的ReplicaSet数量。
    该理想值取决于心Deployment的频率和稳定性。如果该值没有设置的话,默认所有旧的Replicaset或会被保留,将资源存储在etcd中,是用kubectl get rs查看输出。
    每个Deployment的该配置都保存在ReplicaSet中,然而,一旦删除的旧的RepelicaSet,Deployment就无法再回退到那个revison了。   
    如果将该值设置为0,所有具有0个replica的ReplicaSet都会被删除。在这种情况下,新的Deployment rollout无法撤销,因为revision history都被清理掉了。 PS:为了保存版本升级的历史,需要再创建Deployment对象时,在命令中使用"record"选项

一般配合revisionHistoryLimit使用的strategy (更新策略)

strategy(更新策略):  
    .spec.strategy 指定新的Pod替换旧的Pod的策略。 .spec.strategy.type 可以是"Recreate"或者是 "RollingUpdate"。"RollingUpdate"是默认值。  
    Recreate: 重建式更新,就是删一个建一个。类似于ReplicaSet的更新方式,即首先删除现有的Pod对象,然后由控制器基于新模板重新创建新版本资源对象。   
    rollingUpdate:滚动更新,简单定义 更新期间pod最多有几个等。可以指定maxUnavailable 和 maxSurge 来控制 rolling update 进程。   
    maxSurge:.spec.strategy.rollingUpdate.maxSurge 是可选配置项,用来指定可以超过期望的Pod数量的最大个数。该值可以是一个绝对值(例如5)或者是期望的Pod数量的百分比(例如10%)。当MaxUnavailable为0时该值不可以为0。通过百分比计算的绝对值向上取整。默认值是1。   
    例如,该值设置成30%,启动rolling update后新的ReplicatSet将会立即扩容,新老Pod的总数不能超过期望的Pod数量的130%。旧的Pod被杀掉后,新的ReplicaSet将继续扩容,旧的ReplicaSet会进一步缩容,确保在升级的所有时刻所有的Pod数量和不会超过期望Pod数量的130%。   
    maxUnavailable:.spec.strategy.rollingUpdate.maxUnavailable 是可选配置项,用来指定在升级过程中不可用Pod的最大数量。该值可以是一个绝对值(例如5),也可以是期望Pod数量的百分比(例如10%)。通过计算百分比的绝对值向下取整。  如果.spec.strategy.rollingUpdate.maxSurge 为0时,这个值不可以为0。默认值是1。   
    例如,该值设置成30%,启动rolling update后旧的ReplicatSet将会立即缩容到期望的Pod数量的70%。新的Pod ready后,随着新的ReplicaSet的扩容,旧的ReplicaSet会进一步缩容确保在升级的所有时刻可以用的Pod数量至少是期望Pod数量的70%。 PS:maxSurge和maxUnavailable的属性值不可同时为0,否则Pod对象的副本数量在符合用户期望的数量后无法做出合理变动以进行更新操作。   
    在配置时,用户还可以使用Deployment控制器的spec.minReadySeconds属性来控制应用升级的速度。新旧更替过程中,新创建的Pod对象一旦成功响应就绪探测即被认为是可用状态,然后进行下一轮的替换。而spec.minReadySeconds能够定义在新的Pod对象创建后至少需要等待多长的时间才能会被认为其就绪,在该段时间内,更新操作会被阻塞。

完整的revisionHistoryLimit配置如下:

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: nginx-deploy-test
  name: nginx-test-1
  namespace: test1
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx-test
  strategy:
    rollingUpdate:
      maxSurge: 25%
      maxUnavailable: 25%
    type: RollingUpdate
  template:
    metadata:
      labels:
        app: nginx-test
    spec:
      containers:
      - image: nginx:latest
        name: nginx

4. 服务副本缩放

  1. 使用scale命令修改

    $ kubectl scale deploy/nginx-test-1 --replicas=2 -n test1
    

  1. 使用edit命令修改

    直接使用edit命令修改 .spec.replicas 属性值即可

    $ kubectl edit deploy/nginx-test-1 -n test1
    
  2. 直接修改模板中的 .spec.replicas属性值即可

当然我们也可以设置自动缩放功能,这里先简单提及一下,完了专门写一篇说这个事情。

基于现有 Pods 的 CPU 利用率选择 要运行的 Pods 个数下限和上限。

$ kubectl autoscale deploy/nginx-test-1 --min=10 --max=15 --cpu-percent=80