主题
企业级 K8s 核心特性
一句话:企业级特性解决的不是「能不能跑」,而是「更新时能不能少动 Pod、维护时能不能少停服务、故障时能不能只影响一个单元」;换来的是更细的控制,代价是更多组件和更复杂的约束。
适用版本:Kubernetes 1.29+,OpenKruise 1.6+(CloneSet),Calico 3.27+ / Whereabouts。能力与默认值以官方文档为准。
为什么需要
原生 Deployment 的更新单位是 Pod:改镜像、改环境变量、改资源,都是删旧 Pod 建新 Pod。对无状态服务没问题;但对启动要几分钟、持有本地缓存、或者对端按 IP 做白名单的服务,重建一次就是一次风险。
节点维护也一样:kubectl drain 会驱逐 Pod,如果没有约束,一个节点上的所有副本可能同时消失。企业级特性就是围绕「减少重建」和「限制同时中断」做补充。
核心机制
滚动发布:用两个参数控制节奏
yaml
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 0
maxSurge: 1maxSurge 是发布期间最多多出多少 Pod,maxUnavailable 是最多允许多少 Pod 不可用。两者不能同时为 0,否则发布永远无法推进。maxUnavailable: 0 + maxSurge: 1 表示先起一个新 Pod,Ready 后再停一个旧的,容量不下降;前提是集群还有 1 个 Pod 的资源余量。
删除 Pod 的完整顺序是:从 Endpoint 摘除 → 执行 preStop → 发送 SIGTERM → 等 terminationGracePeriodSeconds(默认 30s)→ SIGKILL。优雅关闭的关键是让摘流量发生在进程退出之前,preStop 里做注册中心下线或短暂 sleep 都行,但不能超过 grace period。
原地升级:只换镜像,不换 Pod
OpenKruise 的 CloneSet 和 Advanced StatefulSet 支持原地升级(in-place update):只更新容器镜像,Pod 对象、IP、挂载的 PVC 都保留。适合启动慢、需要保留本地状态、或者下游按 Pod 身份做路由的服务。
代价是原地升级只覆盖镜像这一类变更。改环境变量、改资源、改挂载,仍然要重建 Pod;原地升级期间新旧进程短暂共存,要求应用能处理滚动替换。
固定 IP:CloneSet 不负责这件事
一个常见误解是「CloneSet 提供固定 IP」。实际上 CloneSet 的价值在原地升级、PVC 保留和更细的批量发布策略,它本身不分配也不保留 Pod IP;Pod 重建后 IP 仍然由 CNI 决定。
真正提供固定 IP 的是网络层:
| 方案 | 固定的是什么 | 适用 |
|---|---|---|
| StatefulSet + Headless Service | 稳定的 DNS 名,不是 IP | 有状态服务、客户端按域名发现 |
| Calico IPPool + IP annotation | 指定 IP,重建后可复用 | 已有 Calico、白名单场景 |
| Whereabouts CNI | 集群级 IP 分配与保留 | 不想绑定 Calico |
| 云厂商 ENI / Terway | 网卡级固定 IP | 云上、需要和 VPC 网络打通 |
选型顺序应该是:能用稳定 DNS 解决就不要固定 IP;必须固定 IP 时,先看现有 CNI 是否支持 IPAM,再考虑换 CNI 或引入 OpenKruise 做原地升级来减少 IP 变化。
PDB、QoS 与污点:把「同时坏多少」管起来
| 机制 | 管什么 | 边界 |
|---|---|---|
| PodDisruptionBudget | 自愿中断时保留多少可用副本 | 只管 Eviction API,管不了节点失联 |
| QoS | 节点资源紧张时谁先被驱逐 | Guaranteed 最后,BestEffort 最先 |
| Taint / Toleration | 哪些 Pod 能进哪些节点 | 只约束调度,不保证运行中不超卖 |
| TopologySpreadConstraints | 副本打散到不同节点/可用区 | 需要节点有对应拓扑标签 |
PDB 的典型配置:
yaml
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: order
namespace: default
spec:
minAvailable: 50%
selector:
matchLabels: {app: order}它只在 kubectl drain、集群升级、descheduler 这类自愿中断时生效。节点 NotReady 属于非自愿中断,kubelet 失联后 Pod 会被标记删除并由控制器在别处重建,PDB 不参与决策;真正需要的是反亲和/拓扑打散和足够的冗余容量。
CRD 与 Operator:把运维知识代码化
CRD 让平台团队定义新的资源类型,比如 MySQLCluster;Operator 是监听这个类型的控制器,它根据 CR 创建 StatefulSet、Service、Secret,并处理备份、主从切换、版本升级。价值是把 DBA 的手工步骤变成可复用的调谐循环,代价是 Operator 本身也是一个需要高可用、权限和升级计划的控制面。
单元化在 K8s 里怎么落
单元化(Unitization)是把「按客户/租户分片、单元内闭环」落到部署形态。K8s 本身不提供单元路由,它提供的是隔离原语:
- 单元 = 独立集群或独立 namespace + 专用节点池:用 taint 把节点划给某个单元,避免不同单元争抢资源。
- 入口按单元分流:GSLB/Ingress 按客户号或地域把请求送到对应单元的入口,路由规则在 K8s 之外维护。
- 单元内自包含:每个单元有自己的 Deployment、Service、数据库和缓存;跨单元调用走 API 网关或 Mesh,不共享数据库连接。
- 发布与故障隔离:单元可以独立发布、独立扩容、独立切流;一个单元故障不影响其他单元。
代价是集群数量、镜像分发、配置管理和监控都按单元数放大。规模不够时,用 namespace + 资源配额 + 拓扑打散就能获得大部分隔离收益。完整的单元化设计(DLS、GNS、跨单元事务)见 13-单元化架构。
最小上手
bash
# 1) 滚动更新并观察状态
kubectl create deployment rolling-demo --image=nginx:1.27 --replicas=3
kubectl set image deployment/rolling-demo nginx=nginx:1.27-alpine
kubectl rollout status deployment/rolling-demo
kubectl rollout history deployment/rolling-demo
kubectl rollout undo deployment/rolling-demo --to-revision=1
# 2) 验证 PDB 的 ALLOWED DISRUPTIONS
kubectl apply -f - <<'EOF'
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: rolling-demo
spec:
minAvailable: 2
selector:
matchLabels: {app: rolling-demo}
EOF
kubectl get pdb rolling-demo
# → ALLOWED DISRUPTIONS: 1(3 副本减 2 最小可用)
kubectl delete deployment rolling-demo
kubectl delete pdb rolling-demo原地升级需要先安装 OpenKruise,且 CRD 就绪后才能提交 CloneSet;没有装 Operator 时,kubectl apply 会报 no matches for kind "CloneSet"。
生产动作
- 发布参数:
maxUnavailable: 0需要集群余量;容量紧张时先扩容,否则新 Pod 会 Pending,发布卡住。 - 优雅关闭:
terminationGracePeriodSeconds默认 30s(以官方文档为准),必须大于preStop等待加业务收尾时间;否则请求被 SIGKILL 打断。 - 回滚历史:
revisionHistoryLimit默认 10(以官方文档为准),保留足够版本;镜像用固定 tag 或 digest。 - PDB 验收:
kubectl get pdb的 ALLOWED DISRUPTIONS 应大于 0,否则 drain 和升级会卡住;但不要把 PDB 当成节点故障的保护。 - 固定 IP 验收:重建 Pod 后对比
kubectl get pod -o wide的 IP,确认 CNI 的 IPAM 真的保留了地址;只配 annotation 不验证,等于没配。
边界
- 原地升级只换镜像:环境变量、资源、挂载变更仍会重建 Pod;不要把原地升级当成「永不重建」。
- CloneSet 不提供固定 IP:IP 由 CNI 分配;要固定地址必须在网络层解决。
- PDB 管不了节点失联:非自愿中断下 Pod 会被直接重建;靠拓扑打散和冗余容量,不靠 PDB。
- 单元化成本随单元数线性增长:集群、镜像、监控、发布流水线都要复制;规模不够时用 namespace 和节点池更划算。
- OpenKruise 是额外的控制面:Operator 本身需要高可用和升级计划,引入前先评估运维能力。
讲清楚
企业级 K8s 特性可以归成两类:一类减少重建,一类限制同时中断。滚动参数控制发布节奏,原地升级只换镜像保留 Pod 和 IP,PDB 控制自愿中断时最少留多少副本。
固定 IP 是最容易讲错的地方:CloneSet 不分配也不保留 Pod IP,它的价值是原地升级和 PVC 保留;固定 IP 要靠 Calico IPPool、Whereabouts 或云厂商 ENI,或者用 StatefulSet 加 Headless Service 拿稳定 DNS。
单元化在 K8s 里不是某个资源,而是「独立集群/命名空间 + 专用节点池 + 入口按单元分流」的组合。K8s 提供隔离原语,路由和跨单元一致性要在它之外设计。