内容更新于 2026-09-29。保留原发布日期,正文与示例已按更新时的官方文档修订。
把应用打成镜像以后,单机运行通常已经不难。真正的复杂度出现在多台机器和多个团队之间:新实例应该放在哪里?节点损坏后谁来补齐副本?发布期间怎样保留可用容量?客户端如何找到不断变化的实例?
Kubernetes 用声明式 API 和控制器管理这些变化。用户提交期望状态,系统持续观察实际状态,再通过一系列操作缩小两者之间的差距。理解这套机制,比先记住大量 YAML 字段更重要。
一、从一次部署请求理解集群分工
假设我们希望订单服务运行 3 个副本。向 API Server 提交 Deployment 后,并不是 API Server 自己启动了 3 个容器,而是多个组件协作完成:
- API Server 处理身份认证、授权、准入和资源请求,并把集群状态持久化到 etcd。
- Deployment 控制器管理 ReplicaSet,ReplicaSet 控制器创建所需的 Pod 对象。
- Scheduler 为尚未绑定节点的 Pod 选择符合条件的节点。
- 节点上的 kubelet 观察分配给自己的 Pod,通过 CRI 调用容器运行时。
- 运行时配合网络、存储等组件准备环境并启动容器,kubelet 持续报告状态。
- Service 相关控制机制维护后端端点,网络数据面按规则转发流量。
这是一条异步链路。kubectl apply 成功说明资源请求被接受,并不说明镜像已经拉取、应用已经启动或流量已经打通。
etcd 保存的是 Kubernetes 对象等控制面状态,不是业务数据库内容。恢复集群元数据与恢复订单数据属于两套不同的备份恢复工作。
二、Pod 是一组共享生命周期的进程
Pod 是调度的基本单位,包含一个或多个容器。这些容器共享网络空间,能够通过 localhost 通信,也可以显式挂载同一个卷;但它们不会因为属于同一 Pod 就自动共享各自的根文件系统。
常见情况下,一个 Pod 承载一个主应用。确实需要贴近主应用、共享网络或本地文件的辅助进程,可以作为 Sidecar,例如本地代理或配置同步组件。不能仅因为两个业务服务会互相调用,就把它们塞进同一个 Pod,否则扩缩容和发布也会被绑定。
2.1 重启容器和替换 Pod 的区别
应用进程退出后,kubelet 可以根据策略在同一 Pod 内重启容器。节点失效或 Pod 被删除时,控制器则可能创建一个新的 Pod。新 Pod 有新的身份,并不等于把原 Pod 原封不动迁移到了另一台机器。
这一区别会影响数据。容器可写层不能作为可靠存储;emptyDir 可以供同一 Pod 内的容器使用,并跨越容器重启,但 Pod 删除后数据也随之失去。需要跨 Pod 生命周期保存的数据,应通过持久卷或外部服务管理。
因此应用不能依赖某个 Pod IP 永远不变,也不能用本地磁盘上的任务标记保证跨实例一致性。临时计算结果可以重建,业务事实则要有稳定的持久化来源。
三、Deployment 如何管理发布
Deployment 适合管理可替换的无状态副本。它通过 ReplicaSet 维持数量,并在 Pod 模板变化时推动新旧副本集之间的切换。修改镜像属于模板变化;只修改外部配置文件,不一定会触发 Deployment 自动创建新 Pod。
滚动发布需要两个重要预算:maxSurge 控制发布时可以额外增加多少 Pod,maxUnavailable 控制期望副本中允许多少个不可用。它们会影响发布速度、可用容量和临时资源需求。
例如 3 个副本,配置 maxSurge: 1、maxUnavailable: 0,意味着更新策略允许创建额外副本,并要求在减少旧副本前保留足够的可用实例。集群没有空闲资源时,新 Pod 可能一直 Pending;为了保证可用性而设置的策略,也可能因此让发布停住。
3.1 控制器不会自动理解业务成功
Pod Ready 不代表订单写入一定正确。发布时除了探针,还需要观察错误率、延迟、订单成功率等业务指标。Deployment 检测到进展超时会报告相应状态,并不会替业务团队自动判断回滚时机和数据兼容性。
配置了多副本也不一定具备节点容灾。如果所有副本都落在同一台节点或同一可用区,底层故障仍会同时影响它们。拓扑分布约束、反亲和性与足够的集群容量,需要一起规划。
3.2 其他工作负载何时使用
| 对象 | 主要用途 | 容易误解的地方 |
|---|---|---|
| Deployment | 可替换的服务副本 | 不管理业务事务和数据库一致性 |
| StatefulSet | 稳定身份、存储关联和有序管理 | 不自动实现数据库复制或备份 |
| DaemonSet | 在符合条件的节点运行代理 | 适合节点职责,不是普通服务扩容工具 |
| Job / CronJob | 一次性或周期性任务 | 失败重试、调度等可能导致重复执行,业务应幂等 |
选对象时应先明确实例身份、状态存储和完成条件,而不是把所有进程都包装成长期运行的 Deployment。
四、Service 如何找到不断变化的 Pod
普通 ClusterIP Service 提供稳定的集群内访问入口,通过标签选择器关联后端 Pod。EndpointSlice 等对象记录后端端点,节点的数据面组件依据相关信息实现转发。常见实现使用 kube-proxy,也有采用其他数据面方案的集群。
Service 中的 port 是客户端访问端口,targetPort 是后端应用端口,二者不必一致。containerPort 则描述容器端口信息,并不会替应用启动监听程序。
Service 负责提供访问抽象,默认不等于把每个 HTTP 请求均匀轮转到所有 Pod。转发常常具有连接级行为,长连接和连接池可能造成负载不均,需要结合客户端连接策略分析。
4.1 从集群外进入应用
LoadBalancer 类型的 Service 需要云平台或其他负载均衡实现支持。Ingress 通过配套控制器处理常见 HTTP 路由;Gateway API 则提供 GatewayClass、Gateway、HTTPRoute 等资源,让基础设施与路由职责可以更清楚地划分。
创建 Gateway API 对象并不会凭空产生可用网关。集群需要安装对应 API 资源和兼容实现,具体协议、扩展和跨命名空间行为还要看实现支持情况。Kubernetes 将 Ingress API 视为功能冻结的 API,并建议新增能力考虑 Gateway;这不表示现有 Ingress 资源无法继续工作。
公开入口只是访问路径的一部分。TLS 证书、身份认证、限流、网络访问控制和后端超时,同样需要明确由哪一层负责。
五、requests 和 limits 应该怎么理解
调度器主要依据 requests 以及节点可分配资源等条件,判断某个 Pod 是否能够放入节点;它不会只看“这台机器现在 CPU 很空”。因此实际负载低,不代表调度器一定允许继续放入更多 Pod。
cpu: 250m 表示 0.25 CPU 的资源量,memory: 256Mi 表示 256 MiB。调度请求描述的是资源需求,不是应用一定会消耗这么多,也不是给普通 Pod 独占绑定一颗 CPU。
在节点有余量且配置允许时,容器可以超过 request 使用资源。CPU limit 通常通过节流约束 CPU 时间,内存 limit 则可能在无法回收内存时导致 OOM 处理。二者都叫 limit,但失败表现很不相同。
5.1 资源配置不合理会发生什么
- requests 太低:调度器可能放入过多工作负载,负载上来后产生争抢。
- requests 太高:即使实际用量低,也可能导致新 Pod 无法调度。
- CPU limit 太紧:应用被节流,请求延迟上升,即使节点整体仍有余量。
- 内存 limit 太低:进程可能被 OOM 杀死,反复启动又增加故障压力。
limit 高并不直接等于调度层预留了同样高的资源。不过,只设置 limit 而不设置 request,且没有准入机制给出其他默认值时,Kubernetes 可能把 limit 用作 request。因此应检查最终进入集群的资源对象,而不只看手里的模板。
资源参数需要基于实际压测和运行指标调整,尤其要为 JVM 的非堆内存、线程栈和启动峰值留空间。本文后面的示例数值只用于小型 Nginx 实验,不能照搬到 Java 服务。
六、三种探针分别决定什么
| 探针 | 要回答的问题 | 失败后的主要影响 |
|---|---|---|
| startupProbe | 启动是否完成 | 达到失败阈值后重启相应容器 |
| readinessProbe | 当前能否接收流量 | Pod 就绪状态变更,普通 Service 的可用后端随之调整 |
| livenessProbe | 进程是否陷入无法自行恢复的状态 | 达到阈值后重启相应容器 |
配置 startupProbe 后,在它成功之前,不执行对应容器的 liveness 和 readiness 检查。这可以避免慢启动应用被存活探针过早重启。
探针端点应该快速、明确、成本低。liveness 不宜把所有下游依赖都纳入判断,否则数据库一抖动,应用副本可能一起重启,形成更大的恢复压力。readiness 是否依赖数据库,则需要根据应用是否还有可服务能力决定,不能机械套用统一模板。
探针参数也有预算。例如每 5 秒检查一次,失败阈值为 30,大致给启动留出了约 150 秒的失败容忍窗口;真实时间还受首次检查、超时和执行调度影响。这个窗口需要覆盖正常慢启动,同时不能让真正坏掉的实例长期占用容量。
七、一个可以在实验集群执行的部署
下面用 Nginx 演示 Deployment、Service、资源和探针之间的关系。保存为 web-demo.yaml,在已有的实验集群执行;它只提供集群内 Service,不会申请公网负载均衡器。
nginx:stable-alpine 是便于实验的可变标签,生产部署应使用经过验证的固定版本或摘要。默认页面仅用来观察部署链路,不代表业务健康接口的完整设计。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | |
应用并观察状态:
1 2 3 4 5 6 | |
另开一个终端请求 http://127.0.0.1:8080/,应该能看到页面。注意,port-forward 会选择后端 Pod 建立转发,用于验证应用访问很方便,但它绕过了普通 Service 虚拟 IP 的数据路径,不能据此认定集群网络和负载均衡已全面正常。
可以再把副本扩到 3 个,观察新增 Pod 从 Pending 到 Running、Ready 的过程:
1 2 | |
命令行扩容会改变集群状态,但原文件仍声明 2 个副本;后续重新应用文件时需要理解这种差异。日常管理应明确配置的权威来源,避免手工操作与自动化系统相互覆盖。实验结束后执行 kubectl delete -f web-demo.yaml 清理专用示例资源。
八、配置、存储和权限需要独立设计
ConfigMap 适合普通配置,Secret 用于敏感数据对象,但 Secret 中的 base64 编码不是加密。仍需配置访问控制、审计,并根据环境启用静态加密或对接外部密钥服务。
配置作为环境变量传入时,已有进程不会因对象变化自动获得新值;通过卷投射的文件通常可以更新,但存在传播时间和挂载方式限制,应用还需要能够重新加载。变更配置以后是否滚动重启,应作为发布策略明确下来。
PVC 表达持久存储需求,StorageClass 等机制帮助供应相应卷。跨节点访问方式、可用区约束、卷回收策略和备份能力取决于存储系统。StatefulSet 提供身份与卷关联,不会自动解决数据库主从复制或数据一致性。
Namespace 可以组织资源并配合 RBAC、配额和网络策略使用,但本身不是完整的安全隔离边界。NetworkPolicy 需要网络实现支持并执行,RBAC 则控制 API 操作权限,两者不能相互替代。
九、按状态排查,不要先重启
| 现象 | 优先检查 | 常见原因 |
|---|---|---|
| Pending | Pod Events、requests、节点条件、PVC | 资源不足、亲和性约束、卷无法绑定 |
| ImagePullBackOff | 镜像名、仓库访问、拉取凭证 | 标签不存在、权限错误、网络故障 |
| CrashLoopBackOff | 当前与上次容器日志、退出原因 | 启动配置错误、OOM、探针失败 |
| Running 但不 Ready | readiness 结果、启动进度 | 依赖未就绪、监听地址错误、检查端点错误 |
| Service 无法访问 | selector、EndpointSlice、端口、网络策略 | 没有可用后端或流量路径被阻断 |
常用命令包括 kubectl describe pod、kubectl logs 和 kubectl logs --previous。其中 --previous 用于读取上一轮已终止容器实例的日志,对反复重启尤其有用;日志是否仍可取得还受容器清理和保留情况影响。
发布卡住时,应沿“对象被接受 → Pod 创建 → 调度 → 镜像拉取 → 进程启动 → 探针通过 → 流量到达”的顺序检查。一次重启可能暂时隐藏症状,却会丢掉定位所需的现场。
十、平台负责恢复实例,应用负责业务正确
HPA 可以调整副本数,但需要有效的指标管道;增加 Pod 不代表节点容量也会自动增加。节点扩容、应用预热与外部依赖容量,需要分别考虑。
PodDisruptionBudget 可以限制某些自愿中断操作对可用副本的影响,却不能阻止节点突然宕机,也不能替代 Deployment 的更新策略。多副本、跨故障域部署、数据备份和恢复演练解决的是不同问题。
对订单服务而言,平台可以重新启动进程,却无法判断某次扣款是否已经成功、某条消息是否需要重试。幂等键、事务边界、超时和补偿仍属于业务设计。只有把平台机制和应用语义一起考虑,自动恢复才不会变成自动重复错误。
上一篇:用 Docker 建立可重复交付 · 系列起点:从物理机到云原生