一文吃透 K8s Deployment:资源创建、扩缩容与节点自愈实战
前言
Kubernetes(简称 K8s)作为当前容器编排领域的事实标准,其核心能力之一就是通过多种控制器(Controller)来管理应用的生命周期。在实际生产环境中,我们很少直接操作 Pod —— 因为 Pod 本身不具备自愈、扩缩容、滚动更新等能力。为此,Kubernetes 提供了 Deployment、ReplicaSet、DaemonSet、StatefulSet、Job 等一系列更高层次的对象,其中 Deployment 是最常用、也最基础的工作负载控制器。
无论是部署一个简单的 Web 服务,还是维护一个复杂的微服务集群,Deployment 都能帮助我们轻松实现声明式管理:你只需要告诉 Kubernetes “我想要运行 3 个实例,使用 httpd 镜像”,它就会自动创建所需的 ReplicaSet 和 Pod,并确保实际状态始终与期望状态一致。此外,Deployment 还天然支持滚动更新、版本回滚、副本扩缩容、节点故障自动迁移等高级功能。
本文将从 Deployment 的基本概念出发,结合实际的命令行输出和 YAML 配置文件,逐步分析 Deployment 的执行流程、创建资源的方式、配置文件编写方法、在线扩缩容操作、节点故障时的自动切换,以及如何通过 Label 控制 Pod 的调度位置。文章内容基于 Kubernetes v1.18.6 环境,所有示例均来自真实操作记录。希望通过这篇详解,能帮助读者从原理到实践全面掌握 Deployment 的使用。
一、Deployment介绍
1. Deployment的概念
为了满足不同业务场景,Kubernetes 开发了 Deployment、ReplicaSet、DaemonSet、StatefulSet、Job 等多种 Controller。其中 Deployment 是最常用的一种。
Deployment 为 Pod 和 ReplicaSet 提供了一个声明式定义(declarative)方法,用来替代以前的 Replication Controller,从而更方便地管理应用。
作为最常用的 Kubernetes 对象,Deployment 经常被用来创建 ReplicaSet 和 Pod。我们通常不会直接在集群中使用 ReplicaSet 部署微服务,因为 ReplicaSet 功能不够强大,缺乏更新、扩缩容等常见运维操作。Deployment 的引入正是为了支持这些复杂操作。
2. Deployment执行状态分析
查看 Deployment 的状态,可以使用以下命令:
[root@master k8s]# kubectl get deployment
NAME READY UP-TO-DATE AVAILABLE AGE
http-deployment 3/3 3 3 160m
可以看到,集群中有一个名为 http-deployment 的 Deployment,它有三个副本且全部正常运行。
要查看某个 Deployment 的详细信息,可以执行:
[root@master k8s]# kubectl describe deployment http-deployment
从输出中发现,存在一个 ReplicaSet http-deployment-749876cdf4,这说明 Deployment 是通过 ReplicaSet 来管理 Pod 的。
接着查看 ReplicaSet 的状态:
[root@master k8s]# kubectl get replicaset http-deployment-749876cdf4
使用 kubectl describe replicaset 可以查看更详细的信息:
[root@master ~]# kubectl describe replicaset
Name: http-deployment-749876cdf4
Namespace: default
Selector: app=http_server, pod-template-hash=749876cdf4
Labels: app=http_server
pod-template-hash=749876cdf4
Annotations: deployment.kubernetes.io/desired-replicas: 3
deployment.kubernetes.io/max-replicas: 4
deployment.kubernetes.io/revision: 1
Controlled By: Deployment/http-deployment
Replicas: 3 current / 3 desired
Pods Status: 3 Running / 0 Waiting / 0 Succeeded / 0 Failed
Pod Template:
Labels: app=http_server
pod-template-hash=749876cdf4
Containers:
http-web:
Image: httpd
Port: <none>
Host Port: <none>
Environment: <none>
Mounts: <none>
Volumes: <none>
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal SuccessfulCreate 51m replicaset-controller Created pod: http-deployment-749876cdf4-vlfrp
Normal SuccessfulCreate 51m replicaset-controller Created pod: http-deployment-749876cdf4-k2xSt
Normal SuccessfulCreate 51m replicaset-controller Created pod: http-deployment-749876cdf4-kq9dt
输出中的 Controlled By 指明该 ReplicaSet 是由 Deployment http-deployment 创建的。Events 部分记录了三个副本 Pod 的创建过程。
然后查看 Pod 的状态:
[root@master k8s]# kubectl get pod
NAME READY STATUS RESTARTS AGE
http-deployment-749876cdf4-k2x5t 1/1 Running 0 101s
http-deployment-749876cdf4-kq9dt 1/1 Running 0 101s
http-deployment-749876cdf4-vlfrp 1/1 Running 0 101s
可以看到三个副本 Pod 都处于 Running 状态。
使用 kubectl describe pod 查看更详细的信息:
Controlled By: ReplicaSet/http-deployment-749876cdf4
Containers:
http-web:
Container ID: docker://3043f79fa114...
Image: httpd
Image ID: docker-pullable://httpd@sha256:2a9ae199b5...
State: Running
Started: Fri, 24 Jul 2020 16:53:17 +0800
Ready: True
Restart Count: 0
Environment: <none>
...
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled <unknown> default-scheduler Successfully assigned default/http-deployment-749876cdf4-89c29 to node2
Normal Pulling 67s kubelet, node2 Pulling image "httpd"
Normal Pulled 52s kubelet, node2 Successfully pulled image "httpd"
Normal Created 52s kubelet, node2 Created container http-web
Normal Started 52s kubelet, node2 Started container http-web
输出中 Controlled By 指明此 Pod 是由 ReplicaSet http-deployment-749876cdf4 创建。最后的 Events 记录了 Pod 的启动过程。如果操作失败(比如镜像不存在),也可以从这里查看到失败原因。
3. Deployment执行流程总结
Deployment 的实现过程可以总结为以下几步:
-
用户通过
kubectl创建 Deployment。 -
Deployment 创建 ReplicaSet。
-
ReplicaSet 创建 Pod。
-
Pod 在每个节点上通过 kubelet 调用容器运行时(如 docker)完成容器创建。
对象的命名方式为:子对象的名字 = 父对象名字 + 随机字符串或数字。
二、K8s中创建资源的方式
1. 基于命令的方式
-
优点:简单直观快捷,上手快。
-
适用场景:适合临时测试或实验。
2. 基于配置文件的方式
-
优点:资源的属性写在 YAML 配置文件中,描述了最终要达到的状态。配置文件提供了创建资源的模板,能够重复部署,可以像管理代码一样管理部署。
-
适用场景:适合正式的、跨环境、规模化部署。
-
注意:这种方式要求熟悉配置文件的语法,有一定难度。后续我们主要采用这种方式,需要尽快熟悉和掌握。
3. 用 kubectl 命令直接创建资源(已部分废弃)
[root@master k8s]# kubectl run nginx-deployment --image=nginx --port=80
[root@master k8s]# kubectl get pod
nginx-deployment 1/1 Running 0 31s
从 Kubernetes 1.18 版本开始,已经不支持在命令行中通过参数指定资源的属性(例如 --replicas 参数已弃用),推荐使用 Deployment 配置文件方式创建 Pod。
4. 通过配置文件和 kubectl apply 创建资源
[root@master k8s]# more http.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: http-deployment
spec:
replicas: 3
selector:
matchLabels:
app: http_server
template:
metadata:
labels:
app: http_server
spec:
containers:
- name: http-web
image: httpd
kubectl apply 不仅可以创建 Kubernetes 资源,还能对资源进行更新,非常方便。虽然 Kubernetes 还提供了 kubectl create、kubectl replace、kubectl edit 和 kubectl patch 等命令,但 kubectl apply 已经能够应对超过 90% 的场景。
三、通过 YAML 文件编写 Deployment 配置
Deployment 的配置格式详解
以 http.yml 为例进行说明:
| 字段 | 说明 |
|---|---|
apiVersion |
当前配置格式的版本。可以通过 kubectl api-resources 找到所有资源,再用 kubectl explain deploy 获取版本和类型信息。 |
kind |
要创建的资源类型,这里是 Deployment。 |
metadata |
该资源的元数据,name 是必需的,可任意指定。 |
spec (第一层) |
Deployment 的规格说明。 |
replicas |
副本数量,默认为 1,这里指定为 3。 |
selector |
选择器,matchLabels 用于匹配标签。发布 Service 时,selector 需要与此处对应。 |
template |
定义 Pod 的模板,是配置文件的重点部分。 |
template.metadata |
定义 Pod 的元数据,至少要定义一个 label,key/value 可任意指定。 |
template.spec |
描述 Pod 的规格,定义 Pod 中每个容器的属性,name 和 image 是必需的。 |
注意:containers 后面是一个列表,所以每项前面需要加一个短横线 -。
四、在线增加或减少 Pod 的副本数
1. 增加 Pod 副本数
修改 http.yml 文件,将 replicas 从 3 增加到 5,然后重新应用配置:
[root@master k8s]# kubectl apply -f http.yml
deployment.apps/http-deployment configured
[root@master k8s]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE
http-deployment-749876cd4f-89c29 1/1 Running 0 76m 10.244.2.5 node2
http-deployment-749876cd4f-bj7v9 1/1 Running 0 76m 10.244.1.7 node1
http-deployment-749876cd4f-gv8cw 1/1 Running 0 22s 10.244.1.8 node1
http-deployment-749876cd4f-hxkks 1/1 Running 0 76m 10.244.1.6 node1
http-deployment-749876cd4f-ldq8q 1/1 Running 0 22s 10.244.2.8 node2
可以看到 Pod 数量由 3 个增加到了 5 个。
2. 减少 Pod 副本数
修改 http.yml 文件,将 replicas 从 5 减少到 3(或 2),重新应用即可。Kubernetes 会自动终止多余的 Pod。
五、Node 节点故障时的 Pod 切换
假设当前有 3 个 httpd 副本分别运行在 node1 和 node2 上:
[root@master k8s]# kubectl get nodes
NAME STATUS ROLES AGE VERSION
master Ready master 8h v1.18.6
node1 Ready <none> 8h v1.18.6
node2 Ready <none> 8h v1.18.6
[root@master k8s]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE
http-deployment-749876cdf4-brmt7 1/1 Running 0 16s 10.244.1.12 node1
http-deployment-749876cdf4-jt4bd 1/1 Running 0 16s 10.244.1.11 node1
http-deployment-749876cdf4-p56tb 1/1 Running 0 16s 10.244.2.9 node2
现在模拟 node1 故障,关闭该节点,然后查看状态:
[root@master k8s]# kubectl get nodes
NAME STATUS ROLES AGE VERSION
master Ready master 8h v1.18.6
node1 NotReady <none> 8h v1.18.6
node2 Ready <none> 8h v1.18.6
[root@master k8s]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE
http-deployment-749876cd4-rmt7 1/1 Terminating 0 7m56s 10.244.1.12 node1
http-deployment-749876cd4-jt4bd 1/1 Terminating 0 7m56s 10.244.1.11 node1
http-deployment-749876cd4-17jkd 1/1 Running 0 83s 10.244.2.11 node2
http-deployment-749876cd4-ndb9g 1/1 Running 0 83s 10.244.2.10 node2
http-deployment-749876cd4-p56tb 1/1 Running 0 7m56s 10.244.2.9 node2
可以看到,node1 状态变为 NotReady。等待一段时间,Kubernetes 会检测到 node1 不可用,将 node1 上的 Pod 标记为 Terminating 状态,并在 node2 上新建两个 Pod,使总副本数维持在 3 个。
当 node1 恢复后,Terminating 的 Pod 会被删除,但已经在 node2 上运行的 Pod 不会重新调度回 node1。
六、通过 Label 控制 Pod 的位置
默认配置下,Scheduler 会将 Pod 调度到所有可用的 Node。但有时我们希望将 Pod 部署到指定的 Node(例如将大量磁盘 I/O 的 Pod 部署到配置了 SSD 的节点,或需要 GPU 的 Pod 部署到 GPU 节点)。
Kubernetes 通过 Label 实现这个功能。Label 是 key-value 对,各种资源都可以设置 Label,灵活添加自定义属性。
1. 给 Node 添加 Label
执行如下命令,标注 node1 是配置了 SSD 磁盘的节点:
[root@master k8s]# kubectl label node node1 disk=ssd
[root@master k8s]# kubectl get node --show-labels
注意:disk=ssd 中 disk 是 key,ssd 是 value,都是自定义的。除了自定义 label,Node 上还有几个 Kubernetes 自己维护的 label。
2. 编写带 nodeSelector 的 Deployment
编写一个 nginx.yml 文件,内容如下:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 3
selector:
matchLabels:
app: nginx_server
template:
metadata:
labels:
app: nginx_server
spec:
containers:
- name: nginx-web
image: nginx
nodeSelector:
disk: ssd
在 Pod 模板的 spec 中通过 nodeSelector 指定将此 Pod 部署到具有 label disk=ssd 的 Node 上。
注意:nodeSelector 需要与 containers 保持同级,且其中的 S 必须大写。
3. 删除 Label
要删除 label,执行:
[root@master k8s]# kubectl label node node1 disk-
删除之后,已存在的 Pod 并不会重新部署,依然会在原节点上运行。要改变 Pod 运行的节点,需要修改 nodeSelector 设置,然后通过 kubectl apply 重新部署。
结语
通过本文的详细介绍,我们系统性地学习了 Kubernetes Deployment 的方方面面:从它作为 ReplicaSet 和 Pod 上层控制器的基本定位,到实际的创建、查看、更新操作;从 YAML 配置文件的逐字段解析,到在线扩缩容、节点故障自愈等强大特性;最后还掌握了如何通过 Label 和 nodeSelector 精准控制 Pod 的调度位置。
Deployment 的设计思想体现了 Kubernetes 声明式 API 的精髓 —— 用户只需要描述“想要什么”,系统会持续不断地将实际状态调整为期望状态。这种模式极大地降低了运维复杂度,也为自动化运维和 GitOps 实践奠定了坚实基础。
在实际生产环境中,Deployment 通常还会结合 Service、Ingress、ConfigMap、Secret 等对象共同工作,形成一个完整的应用部署方案。作为 Kubernetes 学习的起点,深入理解 Deployment 的使用方法和原理,将帮助你更轻松地掌握 StatefulSet(有状态应用)、DaemonSet(守护进程)、Job/CronJob(任务型应用)等其它控制器,从而从容应对各种复杂业务场景。
希望本文能成为你 Kubernetes 学习之路上的一块坚实垫脚石。如果你有任何疑问或建议,欢迎在评论区留言交流。
更多推荐
所有评论(0)