在现代应用的交付与运维体系中,Kubernetes 已成为容器编排领域的事实标准。然而,直接在 Kubernetes 中管理 Pod 面临诸多挑战——单点故障、扩缩容繁琐、版本升级过程易出错、缺乏高可用保证等。 为了解决这些工程实际问题,Kubernetes 引入了功能强大的控制器资源对象——Deployment。
Deployment 提供声明式(Declarative)管理应用生命周期的能力。用户无需手动操作每一个 Pod,仅需描述期望的系统状态,包括副本数量、镜像版本等,Deployment 控制器便会自动确保集群中实际状态与期望状态保持一致,实现自动化、自愈、弹性伸缩及平滑滚动升级等功能。

典型应用场景包括:
凭借 Deployment,开发与运维团队能够专注于描述“期望状态”,而将 Pod 的具体管理和异常恢复交由 Kubernetes 自动完成。这是提升系统稳定性与运维效率的关键所在,亦是现代云原生架构不可或缺的重要能力。
在 Kubernetes 架构中,Deployment 并不直接管理 Pod,而是通过中间层 ReplicaSet 实现对 Pod 的间接控制。这三者形成了清晰的管理层级结构。
因此,Deployment 管理 ReplicaSet,ReplicaSet 再负责管理 Pod。运维与开发人员通常直接使用 Deployment 编排应用,实现复杂的生命周期管理,而 ReplicaSet 作为支撑组件,在系统中承担自动化、副本管理等核心工作角色。
Kubernetes 的工作哲学是“声明式”的,这与我们通常习惯的“命令式”有很大不同。
Deployment 正是基于这种声明式模型工作的。你通过一个 YAML 文件来描述你的“期望状态”(Desired State),比如:“我希望有10个运行着 my-app:1.0 镜像的 Pod”。然后,你把这个文件交给 Kubernetes,它内部的控制器(Controller)就会像一个孜孜不倦的管家,不停地检查“当前状态”(Current State)是否与你的“期望状态”一致。
如果不一致,比如某个 Pod 挂了,导致当前只有9个 Pod,控制器就会立刻行动起来,创建一个新的 Pod,让当前状态向期望状态靠拢。这个过程被称为“调谐循环”(Reconciliation Loop)。
声明式模型的最大好处在于它的容错性和自愈能力。你不需要关心过程中可能发生的任何意外,Kubernetes 会持续不断地努力,确保最终结果符合你的声明。
理解了背后的理念,我们再来看看 Deployment 提供的几个核心能力。
这是由 ReplicaSet 直接提供的能力。当你定义一个 Deployment,并指定需要3个副本时,对应的 ReplicaSet 就会时刻确保有3个健康的 Pod 在运行。
replicas 字段从 3 改成 10,然后再次应用这个文件。Deployment 收到新指令后,会命令 ReplicaSet 将 Pod 数量扩展到10个。整个过程非常简单。这是 Deployment 最强大的功能之一,它能让你在不中断服务的情况下更新应用。
当你更新了 Deployment 中的容器镜像版本(比如从 v1.0 更新到 v2.0),Deployment 不会粗暴地一次性杀掉所有旧的 Pod,然后启动新的。它会进行一个非常平滑的“滚动更新”(Rolling Update)。
过程大致如下:
Deployment 会创建一个新的 ReplicaSet,这个新的 ReplicaSet 负责管理 v2.0 版本的新 Pod。
Deployment 会先启动一个 v2.0 的新 Pod。
当新的 Pod 成功启动并准备好接收流量后,Deployment 会杀掉一个 v1.0 的旧 Pod。
它会重复这个过程,“滚动地”用新 Pod 替换旧 Pod,直到所有的 Pod 都更新为 v2.0 版本。
整个过程中,始终有可用的 Pod 在对外提供服务,从而实现了零停机更新。
万一新版本有问题怎么办?回滚(Rollback)也非常简单。Deployment 会保留旧的 ReplicaSet(虽然它的副本数是0)。你只需要一条命令,就可以让 Deployment 重新“激活”旧的 ReplicaSet,用同样滚动的方式,把应用恢复到之前的稳定状态。
首先,我们创建一个名为 hello-deploy.yml 的文件。这个文件就是我们向 Kubernetes 描述“期望状态”的蓝图。
|# hello-deploy.yml apiVersion: apps/v1 kind: Deployment metadata: name: hello-deploy spec: replicas: 3 selector: matchLabels: app: hello-world template
假设我们要把应用更新到一个新的版本,镜像为 nigelpoulton/k8sbook:edge。我们只需要修改 hello-deploy.yml 文件中的 image 字段。
|# ... 省略其他部分 ... spec: containers: - name: hello-pod image: nigelpoulton/k8sbook:edge # <-- 仅仅修改这里 ports: - containerPort: 8080 # ... 省略其他部分 ...
然后,再次使用 kubectl apply 命令。
|$ kubectl apply -f hello-deploy.yml deployment.apps/hello-deploy configured
Kubernetes 会智能地发现只有镜像版本发生了变化,然后自动开始执行滚动更新。你可以使用 kubectl rollout status 命令来观察更新过程。
当我们在更新应用到新版本后,发现这个版本存在问题时,不用担心,我们可以迅速地将应用恢复到之前的版本。首先,我们需要查看应用的历史版本记录,以便确定要回滚到哪个版本:
|$ kubectl rollout history deployment hello-deploy REVISION CHANGE-CAUSE 1 <none> 2 kubectl apply -f hello-deploy.yml
在查看历史版本记录后,我们发现当前应用有两个版本。假设我们在更新到第二个版本后,遇到了某些问题,导致应用无法正常运行。 此时,我们可以通过执行回滚命令,将应用恢复到第一个版本。
|$ kubectl rollout undo deployment hello-deploy --to-revision=1 deployment.apps/hello-deploy rolled back
Deployment 会再次执行滚动操作,将应用平滑地恢复到之前的稳定状态。
Deployment 是 Kubernetes 中管理无状态应用最常用、也是最重要的对象之一。 它通过与 ReplicaSet 和 Pod 的协作,为我们提供了一个强大而简单的应用生命周期管理工具。
我们来解读一下这个文件的关键部分:
kind: Deployment:声明这是一个 Deployment 对象。spec.replicas: 3:这是我们的核心期望,我们想要3个 Pod 副本。spec.selector.matchLabels:选择器,它告诉 Deployment 应该管理哪些 Pod。这里是所有带有 app: hello-world 标签的 Pod。spec.template:这是 Pod 的模板。Deployment 会根据这个模板来创建 Pod。
metadata.labels:为 Pod 设置标签,这个标签必须与上面的选择器匹配。spec.containers:定义 Pod 中包含的容器,这里我们使用了一个公开的镜像 nigelpoulton/k8sbook:latest。现在,使用 kubectl 命令来将这个期望状态应用到你的 Kubernetes 集群中。
|$ kubectl apply -f hello-deploy.yml deployment.apps/hello-deploy created
等一小会儿,让 Deployment 完成它的工作。然后我们可以用 kubectl get 来查看状态。
|$ kubectl get deployment hello-deploy NAME READY UP-TO-DATE AVAILABLE AGE hello-deploy 3/3 3 3 24s $ kubectl get pods NAME READY STATUS RESTARTS AGE hello-deploy-6b7f9f4d5b-abcde 1/1 Running 0 30s hello-deploy-6b7f9f4d5b-fghij 1/1 Running 0 30s hello-deploy-6b7f9f4d5b-klmno 1/1 Running 0 30s
你可以看到,hello-deploy 这个 Deployment 已经成功创建了3个 READY 的 Pod,完全符合我们的预期。
现在 Pod 正在运行,但我们还无法从外部访问它。我们需要创建一个 Service 对象来为这组 Pod 提供一个稳定的访问入口。我们创建一个 hello-svc.yml 文件。
|# hello-svc.yml apiVersion: v1 kind: Service metadata: name: hello-svc spec: type: NodePort selector: app: hello-world ports: - protocol: TCP port: 8080 targetPort: 8080 nodePort: 30001
这个 Service 会将集群节点上的 30001 端口的流量,转发到所有带有 app: hello-world 标签的 Pod 的 8080 端口上。
现在我们应用它:
|$ kubectl apply -f hello-svc.yml service/hello-svc created
现在,你就可以通过访问 http://<你的节点IP>:30001 来看到你的应用了。