在 Kubernetes 中,Deployment 是一种控制器(Controller),用于管理一组 Pod 的创建和扩展。它提供了一种声明性的方式来描述应用的期望状态,并确保这些状态被维护。Deployment 控制器会监视你的应用副本数量、健康状态等,并根据需要调整 Pod 的数量。

一个 Deployment 为 Pod 和 ReplicaSet 提供声明式的更新能力。

一、Deployment 对象详解

一个 Deployment 对象包含以下主要字段:

  1. apiVersion‌: 指定 API 的版本,通常是 apps/v1

  2. kind‌: 指定 Kubernetes 对象的类型,这里是 Deployment

  3. metadata‌: 包含对象的元数据,如名称、命名空间等。

  4. spec‌: 描述 Deployment 的期望状态,包括:

    • replicas‌: 期望的 Pod 副本数量。
    • selector‌: 用于选择 Pod 的标签选择器。
    • template‌: 定义 Pod 的模板,包括容器定义、卷、环境变量等。
    • strategy‌: 定义更新策略,如滚动更新(RollingUpdate)或重新创建(Recreate)。
    • minReadySeconds‌: Pod 准备就绪前的秒数。
    • revisionHistoryLimit‌: 保留的历史版本数。

示例

下面是一个简单的 Deployment 示例,它创建了一个运行 Nginx 的 Pod:

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.14.2
        ports:
        - containerPort: 80

在该例中:

  • 创建名为 nginx-deployment(由 .metadata.name 字段标明)的 Deployment。 该名称将成为后续创建 ReplicaSet 和 Pod 的命名基础。  

  • 该 Deployment 创建一个 ReplicaSet,它创建三个(由 .spec.replicas 字段标明)Pod 副本。

  • .spec.selector 字段定义所创建的 ReplicaSet 如何查找要管理的 Pod。 在这里,你选择在 Pod 模板中定义的标签(app: nginx)。 不过,更复杂的选择规则是也可能的,只要 Pod 模板本身满足所给规则即可。

    说明:

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

  • .spec.template 字段包含以下子字段:
    • Pod 被使用 .metadata.labels 字段打上 app: nginx 标签。
    • Pod 模板规约(即 .spec 字段)指示 Pod 运行一个 nginx 容器, 该容器运行版本为 1.14.2 的 nginx Docker Hub 镜像。
    • 创建一个容器并使用 .spec.containers[0].name 字段将其命名为 nginx

开始之前,请确保的 Kubernetes 集群已启动并运行。 按照以下步骤创建上述 Deployment:

  1. 通过运行以下命令创建 Deployment:

    kubectl apply -f https://k8s.io/examples/controllers/nginx-deployment.yaml
    
  1. 运行 kubectl get deployments 检查 Deployment 是否已创建。 如果仍在创建 Deployment,则输出类似于:

    NAME               READY   UP-TO-DATE   AVAILABLE   AGE
    nginx-deployment   0/3     0            0           1s
    

    在检查集群中的 Deployment 时,所显示的字段有:

    • NAME 列出了名字空间中 Deployment 的名称。
    • READY 显示应用程序的可用的“副本”数。显示的模式是“就绪个数/期望个数”。
    • UP-TO-DATE 显示为了达到期望状态已经更新的副本数。
    • AVAILABLE 显示应用可供用户使用的副本数。
    • AGE 显示应用程序运行的时间。

    请注意期望副本数是根据 .spec.replicas 字段设置 3。

  1. 要查看 Deployment 上线状态,运行 kubectl rollout status deployment/nginx-deployment

    输出类似于:

    Waiting for rollout to finish: 2 out of 3 new replicas have been updated...
    deployment "nginx-deployment" successfully rolled out
    
  1. 几秒钟后再次运行 kubectl get deployments。输出类似于:

    NAME               READY   UP-TO-DATE   AVAILABLE   AGE
    nginx-deployment   3/3     3            3           18s
    

    注意 Deployment 已创建全部三个副本,并且所有副本都是最新的(它们包含最新的 Pod 模板) 并且可用。

  1. 要查看 Deployment 创建的 ReplicaSet(rs),运行 kubectl get rs。 输出类似于:

    NAME                          DESIRED   CURRENT   READY   AGE
    nginx-deployment-75675f5897   3         3         3       18s
    

    ReplicaSet 输出中包含以下字段:

    • NAME 列出名字空间中 ReplicaSet 的名称。
    • DESIRED 显示应用的期望副本个数,即在创建 Deployment 时所定义的值。 此为期望状态
    • CURRENT 显示当前运行状态中的副本个数。
    • READY 显示应用中有多少副本可以为用户提供服务。
    • AGE 显示应用已经运行的时间长度。

    注意 ReplicaSet 的名称格式始终为 [Deployment 名称]-[哈希]。 该名称将成为所创建的 Pod 的命名基础。 其中的哈希字符串与 ReplicaSet 上的 pod-template-hash 标签一致。

  1. 要查看每个 Pod 自动生成的标签,运行 kubectl get pods --show-labels。 输出类似于:

    NAME                                READY     STATUS    RESTARTS   AGE       LABELS
    nginx-deployment-75675f5897-7ci7o   1/1       Running   0          18s       app=nginx,pod-template-hash=75675f5897
    nginx-deployment-75675f5897-kzszj   1/1       Running   0          18s       app=nginx,pod-template-hash=75675f5897
    nginx-deployment-75675f5897-qqcnn   1/1       Running   0          18s       app=nginx,pod-template-hash=75675f5897
    

    所创建的 ReplicaSet 确保总是存在三个 nginx Pod。

主要操作命令

  • 创建 Deployment‌:

    kubectl apply -f deployment.yaml
  • 查看 Deployment 状态‌:

    kubectl get deployments
  • 查看 Deployment 的详细信息‌:

    kubectl describe deployment <deployment-name>
  • 更新 Deployment‌ (例如,更改镜像版本):

    kubectl set image deployment/<deployment-name> nginx=nginx:1.18.0

    或者使用 kubectl edit deployment <deployment-name> 直接编辑文件。

  • 缩放 Deployment‌ (例如,增加副本数):

    kubectl scale deployment <deployment-name> --replicas=5
  • 删除 Deployment‌:

    kubectl delete deployment <deployment-name>

进阶使用和最佳实践

  1. 使用 ConfigMap 和 Secrets‌: 可以将配置信息和敏感信息从 Deployment 中分离出来,使用 ConfigMap 和 Secrets 管理。
  2. 滚动更新和回滚‌: 使用 Deployment 可以轻松地实现应用的零停机更新,并通过回滚到旧版本快速恢复服务。
  3. 健康检查‌: 在 Pod 模板中配置 readinessProbe 和 livenessProbe,确保只有健康的 Pod 被服务流量访问。
  4. 资源限制‌: 通过设置容器的资源请求(requests)和限制(limits),确保应用不会消耗过多资源,影响集群稳定性。
  5. 标签和选择器‌: 合理使用标签和选择器可以更灵活地管理资源和服务。

二、更新 Deployment

说明:

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

按照以下步骤更新 Deployment:

  1. 先来更新 nginx Pod 以使用 nginx:1.16.1 镜像,而不是 nginx:1.14.2 镜像。

    kubectl set image deployment.v1.apps/nginx-deployment nginx=nginx:1.16.1
    

    或者使用下面的命令:

    kubectl set image deployment/nginx-deployment nginx=nginx:1.16.1
    

    在这里,deployment/nginx-deployment 表明 Deployment 的名称,nginx 表明需要进行更新的容器, 而 nginx:1.16.1 则表示镜像的新版本以及它的标签。

    输出类似于:

    deployment.apps/nginx-deployment image updated
    

    或者,可以对 Deployment 执行 edit 操作并将 .spec.template.spec.containers[0].image 从 nginx:1.14.2 更改至 nginx:1.16.1

    kubectl edit deployment/nginx-deployment
    

    输出类似于:

    deployment.apps/nginx-deployment edited
    
  1. 要查看上线状态,运行:

    kubectl rollout status deployment/nginx-deployment
    

    输出类似于:

    Waiting for rollout to finish: 2 out of 3 new replicas have been updated...
    

    或者

    deployment "nginx-deployment" successfully rolled out
    

获取关于已更新的 Deployment 的更多信息:

  • 在上线成功后,可以通过运行 kubectl get deployments 来查看 Deployment。 输出类似于:

    NAME               READY   UP-TO-DATE   AVAILABLE   AGE
    nginx-deployment   3/3     3            3           36s
    
  • 运行 kubectl get rs 以查看 Deployment 通过创建新的 ReplicaSet 并将其扩容到 3 个副本并将旧 ReplicaSet 缩容到 0 个副本完成了 Pod 的更新操作:

    kubectl get rs
    

    输出类似于:

    NAME                          DESIRED   CURRENT   READY   AGE
    nginx-deployment-1564180365   3         3         3       6s
    nginx-deployment-2035384211   0         0         0       36s
    
  • 现在运行 get pods 应仅显示新的 Pod:

    kubectl get pods
    

    输出类似于:

    NAME                                READY     STATUS    RESTARTS   AGE
    nginx-deployment-1564180365-khku8   1/1       Running   0          14s
    nginx-deployment-1564180365-nacti   1/1       Running   0          14s
    nginx-deployment-1564180365-z9gth   1/1       Running   0          14s
    

    下次要更新这些 Pod 时,只需再次更新 Deployment Pod 模板即可。

    Deployment 可确保在更新时仅关闭一定数量的 Pod。默认情况下,它确保至少所需 Pod 的 75% 处于运行状态(最大不可用比例为 25%)。

    Deployment 还确保仅所创建 Pod 数量只可能比期望 Pod 数高一点点。 默认情况下,它可确保启动的 Pod 个数比期望个数最多多出 125%(最大峰值 25%)。

    例如,如果仔细查看上述 Deployment ,将看到它首先创建了一个新的 Pod,然后删除旧的 Pod, 并创建了新的 Pod。它不会杀死旧 Pod,直到有足够数量的新 Pod 已经出现。 在足够数量的旧 Pod 被杀死前并没有创建新 Pod。它确保至少 3 个 Pod 可用, 同时最多总共 4 个 Pod 可用。 当 Deployment 设置为 4 个副本时,Pod 的个数会介于 3 和 5 之间。

  • 获取 Deployment 的更多信息

    kubectl describe deployments
    

    输出类似于:

    Name:                   nginx-deployment
    Namespace:              default
    CreationTimestamp:      Thu, 30 Nov 2017 10:56:25 +0000
    Labels:                 app=nginx
    Annotations:            deployment.kubernetes.io/revision=2
    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.16.1
          Port:         80/TCP
          Environment:  <none>
          Mounts:       <none>
        Volumes:        <none>
      Conditions:
        Type           Status  Reason
        ----           ------  ------
        Available      True    MinimumReplicasAvailable
        Progressing    True    NewReplicaSetAvailable
      OldReplicaSets:  <none>
      NewReplicaSet:   nginx-deployment-1564180365 (3/3 replicas created)
      Events:
        Type    Reason             Age   From                   Message
        ----    ------             ----  ----                   -------
        Normal  ScalingReplicaSet  2m    deployment-controller  Scaled up replica set nginx-deployment-2035384211 to 3
        Normal  ScalingReplicaSet  24s   deployment-controller  Scaled up replica set nginx-deployment-1564180365 to 1
        Normal  ScalingReplicaSet  22s   deployment-controller  Scaled down replica set nginx-deployment-2035384211 to 2
        Normal  ScalingReplicaSet  22s   deployment-controller  Scaled up replica set nginx-deployment-1564180365 to 2
        Normal  ScalingReplicaSet  19s   deployment-controller  Scaled down replica set nginx-deployment-2035384211 to 1
        Normal  ScalingReplicaSet  19s   deployment-controller  Scaled up replica set nginx-deployment-1564180365 to 3
        Normal  ScalingReplicaSet  14s   deployment-controller  Scaled down replica set nginx-deployment-2035384211 to 0
    

    你可以看到,当第一次创建 Deployment 时,它创建了一个 ReplicaSet(nginx-deployment-2035384211) 并将其直接扩容至 3 个副本。更新 Deployment 时,它创建了一个新的 ReplicaSet (nginx-deployment-1564180365),并将其扩容为 1,等待其就绪;然后将旧 ReplicaSet 缩容到 2, 将新的 ReplicaSet 扩容到 2 以便至少有 3 个 Pod 可用且最多创建 4 个 Pod。 然后,它使用相同的滚动更新策略继续对新的 ReplicaSet 扩容并对旧的 ReplicaSet 缩容。 最后,你将有 3 个可用的副本在新的 ReplicaSet 中,旧 ReplicaSet 将缩容到 0。

说明:

Kubernetes 在计算 availableReplicas 数值时不考虑终止过程中的 Pod, availableReplicas 的值一定介于 replicas - maxUnavailable 和 replicas + maxSurge 之间。 因此,你可能在上线期间看到 Pod 个数比预期的多,Deployment 所消耗的总的资源也大于 replicas + maxSurge 个 Pod 所用的资源,直到被终止的 Pod 所设置的 terminationGracePeriodSeconds 到期为止。

翻转(多 Deployment 动态更新)

Deployment 控制器每次注意到新的 Deployment 时,都会创建一个 ReplicaSet 以启动所需的 Pod。 如果更新了 Deployment,则控制标签匹配 .spec.selector 但模板不匹配 .spec.template 的 Pod 的现有 ReplicaSet 被缩容。 最终,新的 ReplicaSet 缩放为 .spec.replicas 个副本, 所有旧 ReplicaSet 缩放为 0 个副本。

当 Deployment 正在上线时被更新,Deployment 会针对更新创建一个新的 ReplicaSet 并开始对其扩容,之前正在被扩容的 ReplicaSet 会被翻转,添加到旧 ReplicaSet 列表并开始缩容。

例如,假定你在创建一个 Deployment 以生成 nginx:1.14.2 的 5 个副本,但接下来更新 Deployment 以创建 5 个 nginx:1.16.1 的副本,而此时只有 3 个 nginx:1.14.2 副本已创建。在这种情况下,Deployment 会立即开始杀死 3 个 nginx:1.14.2 Pod, 并开始创建 nginx:1.16.1 Pod。它不会等待 nginx:1.14.2 的 5 个副本都创建完成后才开始执行变更动作。

更改标签选择算符

Deployment 的标签选择算符在创建后不可更改; 它无法通过 kubectl patchkubectl editkubectl apply 或 helm upgrade 等工具进行更新。

如果必须更改选择算符,则必须删除 Deployment 并重新创建。 你务必要谨慎操作,并确保自己理解以下潜在影响:

  • 新增内容: 当你使用条件更苛刻的选择算符创建新的 Deployment 时,新 Deployment 必须拥有合适的 Pod 模板。 如果你已有清单文件,并对其进行编辑以缩小选择算符的范围,则需要编辑该 Deployment 中 Pod 模板的元数据,添加新的标签以与之匹配,否则 API 服务器将返回验证错误。 将被执行的变更是一个非覆盖性质的变更:新的 Deployment 将无法“看到”旧的 Pod(缺少新标签),导致旧的 ReplicaSet 被孤立,与此同时一个全新的 ReplicaSet 会被创建。
  • 值更新: 更改选择算符中某些键的现有值(例如,从 v1 到 v2)会导致与添加相同的行为(孤立加上重新创建)。
  • 移除操作: 从 Deployment 选择算符中移除已有的键时不需要更改 Pod 模板标签。 这类变更是覆盖性质的:新的、范围更广的选择算符将匹配旧的 Pod。 现有的 ReplicaSet 不会被孤立,也不会创建新的 ReplicaSet, 但请注意,已移除的标签仍然存在于任何现有的 Pod 和 ReplicaSet 中。 你可以通过触发 Deployment 的滚动更新来清理这些标签。

更多推荐