Deployments
官方文档:https://kubernetes.io/zh-cn/docs/concepts/workloads/controllers/deployment/
API:https://kubernetes.io/zh-cn/docs/reference/kubernetes-api/workload-resources/deployment-v1/#Deployment
一个 Deployment 为 Pod 和 ReplicaSet 提供声明式的更新能力。
你负责描述 Deployment 中的目标状态,而 Deployment 控制器(Controller) 以受控速率更改实际状态, 使其变为期望状态。你可以定义 Deployment 以创建新的 ReplicaSet,或删除现有 Deployment, 并通过新的 Deployment 收养其资源。
用例
以下是 Deployments 的典型用例(作用):
- 创建 Deployment 以将 ReplicaSet 上线。ReplicaSet 在后台创建 Pod。 检查 ReplicaSet 的上线状态,查看其是否成功。
- 通过更新 Deployment 的 PodTemplateSpec,声明 Pod 的新状态 。 新的 ReplicaSet 会被创建,Deployment 以受控速率将 Pod 从旧 ReplicaSet 迁移到新 ReplicaSet。 每个新的 ReplicaSet 都会更新 Deployment 的修订版本。
- 如果 Deployment 的当前状态不稳定,回滚到较早的 Deployment 版本。 每次回滚都会更新 Deployment 的修订版本。
- 扩大 Deployment 规模以承担更多负载。
- 暂停 Deployment 的上线 以应用对 PodTemplateSpec 所作的多项修改, 然后恢复其执行以启动新的上线版本。
- 使用 Deployment 状态来判定上线过程是否出现停滞。
- 清理较旧的不再需要的 ReplicaSet 。
下面是一个 Deployment 示例。其中创建了一个 ReplicaSet,负责启动三个 nginx Pod:controllers/nginx-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:name: nginx-deploymentlabels:app: nginx
spec:replicas: 3selector:matchLabels:app: nginxtemplate:metadata:labels:app: nginxspec:containers:- name: nginximage: nginx:1.14.2ports:- containerPort: 80
在该例中:
- 创建名为
nginx-deployment
(由.metadata.name
字段标明)的 Deployment。 该名称将成为后续创建 ReplicaSet 和 Pod 的命名基础。 - 该 Deployment 创建一个 ReplicaSet,它创建三个(由
.spec.replicas
字段标明)Pod 副本。 .spec.selector
字段定义所创建的 ReplicaSet 如何查找要管理的 Pod。 在这里,你选择spec.selector.matchLabels
在 Pod 模板中定义的标签(app: nginx
)。 不过,更复杂的选择规则是也可能的,只要 Pod 模板本身满足所给规则即可。
说明:
.spec.selector.matchLabels
字段是{key,value}
键值对映射。 在matchLabels
映射中的每个{key,value}
映射等效于matchExpressions
中的一个元素, 即其key
字段是 “key”,operator
为 “In”,values
数组仅包含 “value”。 在matchLabels
和matchExpressions
中给出的所有条件都必须满足才能匹配。
template
字段包含以下子字段:- Pod 被使用
.metadata.labels
字段打上app: nginx
标签。 - Pod 模板规约(即
.template.spec
字段)指示 Pod 运行一个nginx
容器, 该容器运行版本为 1.14.2 的nginx
Docker Hub 镜像。 - 创建一个容器并使用
.spec.template.spec.containers[0].name
字段将其命名为nginx
。
- Pod 被使用
总结:共有三个
app: nginx
,分别作用是,定义Deployment
的 labels;第二个,给Deployment
选择app: nginx
标签的pod模板;给这个pod模板打上app: nginx
标签。
按照以下步骤创建上述 Deployment :
- 通过运行以下命令创建 Deployment :
kubectl apply -f https://k8s.io/examples/controllers/nginx-deployment.yaml
- 运行
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。
- 要查看 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
- 几秒钟后再次运行
kubectl get deployments
。输出类似于:
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deployment 3/3 3 3 18s
注意 Deployment 已创建全部三个副本,并且所有副本都是最新的(它们包含最新的 Pod 模板) 并且可用。
- 要查看 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
标签一致。
- 要查看每个 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 中指定适当的选择算符和 Pod 模板标签(在本例中为app: nginx
)。 标签或者选择算符不要与其他控制器(包括其他 Deployment 和 StatefulSet)重叠。 Kubernetes 不会阻止你这样做,但是如果多个控制器具有重叠的选择算符, 它们可能会发生冲突执行难以预料的操作。
Pod-template-hash 标签
注意:
不要更改此标签。
Deployment 控制器将pod-template-hash
标签添加到 Deployment 所创建或收留的每个 ReplicaSet 。
此标签可确保 Deployment 的子 ReplicaSet 不重叠。 标签是通过对 ReplicaSet 的PodTemplate
进行哈希处理。 所生成的哈希值被添加到 ReplicaSet 选择算符、Pod 模板标签,并存在于在 ReplicaSet 可能拥有的任何现有 Pod 中。
更新 Deployment
说明:
仅当 Deployment Pod 模板(即.spec.template
)发生改变时,例如模板的标签或容器镜像被更新, 才会触发 Deployment 上线。其他更新(如对 Deployment 执行扩缩容的操作)不会触发上线动作。
- 先来更新 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 执行
edit
操作并将.spec.template.spec.containers[0].image
从nginx:1.14.2
更改至nginx:1.16.1
。
kubectl edit deployment/nginx-deployment
- 要查看上线状态
kubectl rollout status deployment/nginx-deployment
获取 Deployment 的更多信息:
- 在上线成功后,可以通过运行
kubectl get deployments
来查看 Deployment。 - 运行
kubectl get rs
以查看 Deployment 通过创建新的 ReplicaSet 并将其扩容到 3 个副本并将旧 ReplicaSet 缩容到 0 个副本完成了 Pod 的更新操作。 - 现在运行
kubectl get pods
应仅显示新的 Pod。 kubectl describe deployments
回滚 Deployment
有时,你可能想要回滚 Deployment;例如,当 Deployment 不稳定时(例如进入反复崩溃状态)。 默认情况下,Deployment 的所有上线记录都保留在系统中,以便可以随时回滚 (你可以通过修改修订历史记录限制来更改这一约束)。
检查 Deployment 上线历史
首先,检查 Deployment 修订历史:kubectl rollout history deployment/nginx-deployment
要查看修订历史的详细信息,运行:kubectl rollout history deployment/nginx-deployment --revision=2
回滚到之前的修订版本
按照下面给出的步骤将 Deployment 从当前版本回滚到以前的版本(即版本 2)。
假定现在你已决定撤消当前上线并回滚到以前的修订版本:kubectl rollout undo deployment/nginx-deployment
或者,你也可以通过使用 --to-revision 来回滚到特定修订版本:kubectl rollout undo deployment/nginx-deployment --to-revision=2
检查回滚是否成功以及 Deployment 是否正在运行,运行:kubectl get deployment nginx-deployment
获取 Deployment 描述信息:kubectl describe deployment nginx-deployment
缩放 Deployment
你可以使用如下指令缩放 Deployment:kubectl scale deployment/nginx-deployment --replicas=10
假设集群启用了Pod 的水平自动缩放, 你可以为 Deployment 设置自动缩放器,并基于现有 Pod 的 CPU 利用率选择要运行的 Pod 个数下限和上限。kubectl autoscale deployment/nginx-deployment --min=10 --max=15 --cpu-percent=80
比例缩放
RollingUpdate 的 Deployment 支持同时运行应用程序的多个版本。 当自动缩放器缩放处于上线进程(仍在进行中或暂停)中的 RollingUpdate Deployment 时, Deployment 控制器会平衡现有的活跃状态的 ReplicaSet(含 Pod 的 ReplicaSet)中的额外副本, 以降低风险。这称为 比例缩放(Proportional Scaling)。
例如,你运行一个 10 个副本的 Deployment,其 maxSurge=3,maxUnavailable=2。
暂停、恢复 Deployment 的上线过程
在你更新一个 Deployment 的时候,或者计划更新它的时候, 你可以在触发一个或多个更新之前暂停 Deployment 的上线过程。 当你准备应用这些变更时,你可以重新恢复 Deployment 上线过程。 这样做使得你能够在暂停和恢复执行之间应用多个修补程序,而不会触发不必要的上线操作。
使用如下指令暂停上线:kubectl rollout pause deployment/nginx-deployment
接下来更新 Deployment 镜像:kubectl set image deployment/nginx-deployment nginx=nginx:1.16.1
注意没有新的上线被触发:kubectl rollout history deployment/nginx-deployment
获取上线状态验证现有的 ReplicaSet 没有被更改:kubectl get rs
你可以根据需要执行很多更新操作,例如,可以要使用的资源:kubectl set resources deployment/nginx-deployment -c=nginx --limits=cpu=200m,memory=512Mi
最终,恢复 Deployment 上线并观察新的 ReplicaSet 的创建过程,其中包含了所应用的所有更新:kubectl rollout resume deployment/nginx-deployment
观察上线的状态,直到完成。kubectl get rs -w
编写 Deployment 规约
同其他 Kubernetes 配置一样, Deployment 需要 .apiVersion
,.kind
和 .metadata
字段。 有关配置文件的其他信息,请参考部署 Deployment、 配置容器和使用 kubectl 管理资源等相关文档。
当控制面为 Deployment 创建新的 Pod 时,Deployment 的 .metadata.name
是命名这些 Pod 的部分基础。 Deployment 的名称必须是一个合法的 DNS 子域值, 但这会对 Pod 的主机名产生意外的结果。为获得最佳兼容性,名称应遵循更严格的 DNS 标签规则。
Deployment 还需要 .spec
部分。
Pod 模板
.spec
中只有 .spec.template
和 .spec.selector
是必需的字段。
.spec.template
是一个 Pod 模板。 它和 Pod 的语法规则完全相同。 只是这里它是嵌套的,因此不需要 apiVersion
或 kind
。
除了 Pod 的必填字段外,Deployment 中的 Pod 模板必须指定适当的标签和适当的重新启动策略。 对于标签,请确保不要与其他控制器重叠。请参考选择算符。
只有 .spec.template.spec.restartPolicy
等于 Always
才是被允许的,这也是在没有指定时的默认设置。
副本
.spec.replicas
是指定所需 Pod 的可选字段。它的默认值是1。
如果你对某个 Deployment 执行了手动扩缩操作(例如,通过 kubectl scale deployment deployment --replicas=X
), 之后基于清单对 Deployment 执行了更新操作(例如通过运行 kubectl apply -f deployment.yaml
),那么通过应用清单而完成的更新会覆盖之前手动扩缩所作的变更。
如果一个 HorizontalPodAutoscaler (或者其他执行水平扩缩操作的类似 API)在管理 Deployment 的扩缩, 则不要设置 .spec.replicas
。
恰恰相反,应该允许 Kubernetes 控制面来自动管理 .spec.replicas
字段。
选择算符
.spec.selector
是指定本 Deployment 的 Pod 标签选择算符的必需字段。
.spec.selector
必须匹配 .spec.template.metadata.labels
,否则请求会被 API 拒绝。
在 API apps/v1
版本中,.spec.selector
和 .metadata.labels
如果没有设置的话, 不会被默认设置为 .spec.template.metadata.labels
,所以需要明确进行设置。 同时在 apps/v1
版本中,Deployment 创建后 .spec.selector
是不可变的。
当 Pod 的标签和选择算符匹配,但其模板和 .spec.template
不同时,或者此类 Pod 的总数超过 .spec.replicas
的设置时,Deployment 会终结之。 如果 Pod 总数未达到期望值,Deployment 会基于 .spec.template
创建新的 Pod。
你不应直接创建与此选择算符匹配的 Pod,也不应通过创建另一个 Deployment 或者类似于 ReplicaSet 或 ReplicationController 这类控制器来创建标签与此选择算符匹配的 Pod。 如果这样做,第一个 Deployment 会认为它创建了这些 Pod。 Kubernetes 不会阻止你这么做。
如果有多个控制器的选择算符发生重叠,则控制器之间会因冲突而无法正常工作。
策略
.spec.strategy
策略指定用于用新 Pod 替换旧 Pod 的策略。 .spec.strategy.type
可以是 “Recreate” 或 “RollingUpdate”。“RollingUpdate” 是默认值
重新创建 Deployment
如果 .spec.strategy.type==Recreate
,在创建新 Pod 之前,所有现有的 Pod 会被杀死。
说明:
这只会确保为了升级而创建新 Pod 之前其他 Pod 都已终止。如果你升级一个 Deployment, 所有旧版本的 Pod 都会立即被终止。控制器等待这些 Pod 被成功移除之后, 才会创建新版本的 Pod。如果你手动删除一个 Pod,其生命周期是由 ReplicaSet 来控制的, 后者会立即创建一个替换 Pod(即使旧的 Pod 仍然处于 Terminating 状态)。 如果你需要一种“最多 n 个”的 Pod 个数保证,你需要考虑使用 StatefulSet。
滚动更新 Deployment
Deployment 会在 .spec.strategy.type==RollingUpdate
时,采取 滚动更新的方式更新 Pod。你可以指定 maxUnavailable
和 maxSurge
来控制滚动更新过程。
最大不可用
.spec.strategy.rollingUpdate.maxUnavailable
是一个可选字段, 用来指定更新过程中不可用的 Pod 的个数上限。该值可以是绝对数字(例如,5),也可以是所需 Pod 的百分比(例如,10%)。百分比值会转换成绝对数并去除小数部分。 如果 .spec.strategy.rollingUpdate.maxSurge
为 0,则此值不能为 0。 默认值为 25%。
例如,当此值设置为 30% 时,滚动更新开始时会立即将旧 ReplicaSet 缩容到期望 Pod 个数的70%。 新 Pod 准备就绪后,可以继续缩容旧有的 ReplicaSet,然后对新的 ReplicaSet 扩容, 确保在更新期间可用的 Pod 总数在任何时候都至少为所需的 Pod 个数的 70%。
最大峰值
.spec.strategy.rollingUpdate.maxSurge
是一个可选字段,用来指定可以创建的超出期望 Pod 个数的 Pod 数量。此值可以是绝对数(例如,5)或所需 Pod 的百分比(例如,10%)。 如果 MaxUnavailable
为 0,则此值不能为 0。百分比值会通过向上取整转换为绝对数。 此字段的默认值为 25%。
例如,当此值为 30% 时,启动滚动更新后,会立即对新的 ReplicaSet 扩容,同时保证新旧 Pod 的总数不超过所需 Pod 总数的 130%。一旦旧 Pod 被杀死,新的 ReplicaSet 可以进一步扩容, 同时确保更新期间的任何时候运行中的 Pod 总数最多为所需 Pod 总数的 130%。
以下是一些使用 maxUnavailable 和 maxSurge 的滚动更新 Deployment 的示例:
apiVersion: apps/v1
kind: Deployment
metadata:name: nginx-deploymentlabels:app: nginx
spec:replicas: 3selector:matchLabels:app: nginxtemplate:metadata:labels:app: nginxspec:containers:- name: nginximage: nginx:1.14.2ports:- containerPort: 80strategy:type: RollingUpdaterollingUpdate:maxSurge: 1maxUnavailable: 1