开局先啰嗦两句。这一系列写到现在,环境初始化、控制平面高可用、工作节点接入、网络与存储就绪都过完了,Kubernetes 1.32 高可用集群部署系列需要开始回答一个更实际的问题:集群搭完了,然后呢?很多团队卡在“集群能跑”和“业务能稳”之间,差的就是从搭建到生产就绪的这最后一段路。这一篇我打算换个节奏,重点讲三件事:先做一轮完整的高可用验证,再落地两个典型负载——Nginx 和 Doris,最后把资源治理与多租户隔离收尾。适合刚把集群搭完、准备把业务往上迁的团队参考。
1. 高可用不是“配完就完”:先做一轮生产就绪验证
我见过太多集群,配置上看着完美:三个控制平面节点、etcd 集群、HAProxy 前置,但真到出故障那天发现根本没验证过。Kubernetes 1.32 的高可用部署,不是说把组件装起来就完事了,而是要证明“挂了某台机器,业务不受影响”这件事是真实存在的。所以我建议,任何集群在接入真实业务之前,先做一轮生产就绪验证。
这里的核心思路是:高可用配置解决的是“故障发生后系统能否自愈”,而不是“故障不发生”。要用实际操作把故障注入进去,看系统怎么应对。常见的验证维度有四个:控制平面故障转移、etcd 选举与恢复、数据备份恢复、组件版本一致性。下面一个一个说。
1.1 控制平面与 etcd 的“拔网线”演练
这一步是整个验证里最刺激的,也是最有价值的。做法很简单:在业务低峰期,直接对一台控制平面节点执行关机,或者更激进一点,断开它的网络连接,模拟真实故障场景。然后观察几件事。
第一,剩余的两台 API Server 是否正常响应。你可以不停执行kubectl get nodes,确认命令不超时、不报连接错误。第二,etcd 集群是否完成了选举切换。etcd 是 Raft 协议,三节点中挂掉一个,只要剩余两个能凑够多数,就能继续对外服务。第三,已有业务 Pod 是否无感。正常情况下,Pod 不会因为某个 etcd 或 API Server 故障而重启,流量也不应中断。第四,故障节点恢复后,kubelet 会自动向集群重新注册,etcd 也能重新加入集群完成数据同步。
注意:演练之前必须确认监控告警是完好的,否则故障期间的日志和指标全丢了,演练就失去意义。另外,三节点 etcd 中挂掉两个会直接失去多数派,集群表现为只读或频繁抖动,这个就是设计底线,不要在演练里挑战它。
实操上,我建议用shutdown而不是直接拔电源,前者能保证有优雅终止的过程,但故障恢复验证不充分。更好的做法是直接执行systemctl stop kubelet或者用ip link set <网卡> down模拟网络分区。恢复时依次启动服务,观察节点状态从NotReady回到Ready,etcd 成员从unstarted回到started。
1.2 验证 etcd 备份与恢复,别让数据成为唯一软肋
Kubernetes 集群的所有状态都存放在 etcd 里,包括 Namespace、Deployment、Service、ConfigMap、Secret 等。控制平面节点可以销毁重建,但 etcd 数据没了,整个集群就废了。所以,备份和恢复是生产就绪验证的硬指标。
备份层面,我推荐两条路线:一是直接用etcdctl snapshot save做定时快照;二是用 Velero 这类工具做集群级备份。快照方式更底层、更可靠,但要自己写脚本轮转和管理。Velero 除了 etcd 还会备份资源对象,但需要额外部署和配置对象存储。对于高可用集群,我的建议是两者结合:etcd 快照保证数据底线,Velero 保证资源级别可恢复。
恢复验证这一步,很多人会跳过,但恰恰是最不该跳过的。完整的恢复演练流程大概是:
- 停掉 kube-apiserver,让 API Server 不再连接 etcd,防止写入造成数据不一致。
- 用
etcdctl snapshot restore把快照恢复到临时数据目录,并指定新的--initial-cluster配置。 - 替换 etcd 数据目录后启动 etcd,确认成员状态正常。
- 启动 kube-apiserver、controller-manager、scheduler,观察集群是否恢复对外服务。
这里有两个容易踩的坑。第一个,snapshot restore恢复出来的 etcd 默认是单节点集群,必须设置正确的initial-cluster参数,否则其他成员无法加入。第二个,恢复操作的时间点选择很重要,快照时间点到故障时间点之间的数据变更会丢失,也就是 RPO 由备份频率决定,这个要在演练前跟业务方对齐。
1.3 组件版本一致性与滚动升级路径确认
既然系列标题是 Kubernetes 1.32,这里必须确认一件事:集群内所有组件的版本是否处于一致状态。kubeadm upgrade plan是检查升级路径的好工具,它会列出当前版本、可升级版本以及 API 的弃用变更。对于已经上线的集群,我建议用kubeadm upgrade diff先看差异,再决定是否升级。
升级本身遵循“一次一个次要版本”的原则。比如从 1.31 升到 1.32,应该先升控制平面,再升工作节点。控制平面的升级顺序是 kubeadm、kubelet、kube-apiserver、controller-manager、scheduler、etcd。工作节点升级前要先把节点标记为不可调度并驱逐 Pod,升级完成后再恢复调度。这个过程同样需要验证:升级后kubectl get nodes全部 Ready,核心工作负载正常运行,etcd 健康检查通过。
升级验证的核心结论是:高可用集群的价值在于可以滚动升级而不中断业务。如果升级过程中出现服务不可用,说明高可用设计本身有漏洞,需要回头排查负载均衡、健康检查、Pod 调度策略等问题。
2. 第一个生产负载:Nginx 部署的完整落地
验证完集群底座,接下来要在上面跑第一个生产负载。我选 Nginx,不是因为它复杂,而是因为它足够简单,能快速验证整个应用调度链路:镜像拉取、容器调度、网络连通、服务发现、负载均衡、健康检查、自动扩缩容。只要 Nginx 能稳定跑起来,这套集群的“业务链路”就被验证通了。
很多人会觉得部署 Nginx 太简单,不值得单独写一篇文章。但实际在做生产部署时,细节远比kubectl run nginx --image=nginx要多。我见过的生产事故里,不少就是栽在“基础资源没写好”上的。
2.1 资源请求与限制:写错这里,早晚出事故
资源 requests 和 limits 是生产部署的第一步。requests 是调度依据,告诉调度器这个 Pod 至少要占用多少 CPU 和内存;limits 是运行约束,限制 Pod 最多能用多少。Kubernetes 调度器只会看 requests,不会看 limits,所以如果你只写了 limits 不写 requests,调度器会把 Pod 当成“零资源占用”来调度,很容易把某个节点塞爆。
Nginx 的常规建议值:CPU requests 100m,内存 requests 128Mi,CPU limits 500m,内存 limits 256Mi,这个配置适合纯反向代理场景。如果你的 Nginx 还承担了静态文件服务或者网关职责,需要按实际压测数据调整。另外,limits 不要设置得太接近节点容量,否则系统预留资源被挤占,kubelet 和系统进程可能 OOM。
经验之谈:requests 是长期常态值,limits 是短期峰值上限。生产环境里 CPU limits 可以留 3-5 倍余量,内存 limits 尽量贴近 requests,因为内存不可压缩,一旦超过 limits 就会触发 OOMKilled,而不是像 CPU 那样只是限流。
2.2 Deployment、Service、Ingress 的完整配置
先给一份可以直接用的配置,再逐段解释为什么这么写。这份配置我按生产标准来,包含资源限制、存活探针、就绪探针、滚动更新策略。
apiVersion: apps/v1 kind: Deployment metadata: name: nginx-demo namespace: web spec: replicas: 3 selector: matchLabels: app: nginx-demo strategy: type: RollingUpdate rollingUpdate: maxSurge: 1 maxUnavailable: 0 template: metadata: labels: app: nginx-demo spec: containers: - name: nginx image: nginx:1.27 ports: - containerPort: 80 resources: requests: cpu: 100m memory: 128Mi limits: cpu: 500m memory: 256Mi readinessProbe: httpGet: path: /healthz port: 80 initialDelaySeconds: 3 periodSeconds: 5 livenessProbe: httpGet: path: /healthz port: 80 initialDelaySeconds: 10 periodSeconds: 15探针这一块要重点说。readinessProbe 决定 Pod 是否进入 Service 的 Endpoints 列表,如果就绪探针失败,Pod 不会被分配流量,但也不会被重启。livenessProbe 决定 Pod 是否需要重启,如果存活探针失败,kubelet 会杀掉容器重新拉起。生产上建议两个探针都配置,用不同的路径区分:就绪探针可以查依赖的配置是否加载完成,存活探针只查进程本身是否还活着。
滚动更新策略maxSurge: 1, maxUnavailable: 0的意思是,更新过程中最多额外创建一个新 Pod,但绝对不允许出现可用副本数小于期望值。这在发布场景里保证了零中断,代价是更新期间会短暂占用额外资源。如果你的集群资源比较紧张,可以把maxUnavailable调整为 1,交换发布速度与资源占用。
Service 和 Ingress 的配置相对简单:
apiVersion: v1 kind: Service metadata: name: nginx-demo namespace: web spec: selector: app: nginx-demo ports: - port: 80 targetPort: 80 type: ClusterIP apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: nginx-demo namespace: web spec: ingressClassName: nginx rules: - host: nginx.demo.local http: paths: - path: / pathType: Prefix backend: service: name: nginx-demo port: number: 80Service 的 selector 必须精确匹配 Pod 标签,这是最容易出错的地方。Ingress 的ingressClassName必须和集群里安装的 Ingress Controller 一致,否则规则不会生效。如果你用的是 ingress-nginx,还需要确认它的 IngressClass 资源存在。
2.3 压测验证与 HPA 自动扩缩容
Nginx 部署稳定后,加上 HPA 验证弹性能力。HPA 需要集群里先装好 metrics-server,否则拿不到 Pod 的 CPU 指标,HPA 会一直显示<unknown>状态,这是最常见的坑之一。
HPA 配置看起来很简单:
apiVersion: autoscaling/v2 kind: HorizontalPodAutoscaler metadata: name: nginx-demo-hpa namespace: web spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: nginx-demo minReplicas: 3 maxReplicas: 10 metrics: - type: Resource resource: name: cpu target: type: Utilization averageUtilization: 60这里的目标利用率 60% 表示,当所有副本的平均 CPU 使用率超过 60% 时开始扩容。HPA 的计算方式是:期望副本数 = 当前副本数 × 当前利用率 / 目标利用率。假设当前 3 个副本平均 CPU 利用率是 90%,那期望副本数就是 3 × 90 / 60 = 4.5,向上取整就是 5 个副本。
验证扩缩容需要实际压测。我常用hey或者wrk做压测,比如执行hey -n 200000 -c 100 http://<nginx-svc>,然后另开一个终端观察kubectl get hpa -w。你会看到副本数随着 CPU 压力逐步上升,压测停止后,经过一段冷却时间副本数会逐步回落。
这里有两个行为要提前解释清楚,免得压测时慌。第一,HPA 默认的扩容冷却时间是 3 分钟,也就是说指标连续超过阈值 3 分钟后才触发扩容,不会一超就扩。第二,缩容冷却时间默认 5 分钟,而且每次缩容的幅度有限制,不会从 10 个副本直接缩回 3 个。这些策略可以在 HPA 的behavior字段里覆盖,但默认值在生产上其实是合理的,至少能防止震荡。
3. 大数据组件落地:Doris 部署的集群策略拆解
Nginx 这类无状态服务验证了集群的基本调度能力,但很多团队最终要在这套 Kubernetes 1.32 集群上跑大数据业务。我把 Doris 单独拿出来讲,是因为它的架构在数据类组件里很有代表性:既有无状态角色,也有有状态角色;既吃内存,也吃磁盘;既要求调度灵活,又要求数据不丢。跑通 Doris 之后,类似的 ClickHouse、StarRocks、Elasticsearch 等组件在部署思路上都是相通的。
3.1 FE 与 BE 的角色划分和部署形态
Doris 有两个核心角色。FE(Frontend)负责元数据管理、查询解析和计划生成,对内存敏感,可以通过多副本部署实现自身高可用,元数据在 FE 之间通过类似 Raft 的协议同步。BE(Backend)负责数据存储和查询执行,是真正落数据的地方,必须用持久化存储,磁盘容量和 IOPS 是硬指标。
在 Kubernetes 上,FE 可以用 StatefulSet 部署 2-3 个副本,因为 FE 有固定标识和元数据同步需求;BE 则必须用 StatefulSet 加 PVC,存储通过volumeClaimTemplates动态创建。这里不建议用 Deployment 跑 BE,因为 Deployment 的 Pod 是无名的,重建后标识变化,Doris 集群内部无法正确识别节点身份。
一个关键的配置点是podManagementPolicy。StatefulSet 默认是OrderedReady,会按顺序逐个启动 Pod。大数据组件希望并行启动,所以通常要改成Parallel,让所有副本同时拉起,减少整体启动时间。
3.2 PersistentVolumeClaim 与存储类选择:本地盘优先还是云盘兜底
BE 的存储选型直接决定 Doris 性能。Doris BE 的数据写入和读取都是高吞吐,对磁盘随机 IOPS 和顺序吞吐都有要求。我的经验是,优先考虑本地 NVMe 盘或者高性能云盘,避免使用普通的网络存储。
如果自建机房里有多块本地 NVMe 盘,可以用 Local PersistentVolume 或者 OpenEBS 这类本地存储方案。Local PV 的好处是性能直通,没有网络存储开销;坏处是数据绑定节点,节点坏了数据要依赖 Doris 自身的副本机制来恢复。用 Local PV 时必须配合节点亲和性,让 BE 的 Pod 固定调度到有对应磁盘的节点上。
如果用的是云盘,关注两类参数:类型和扩容能力。SSD 云盘的 IOPS 上限一般跟容量成正比,容量越大 IOPS 越高,所以 BE 的 PVC 不要一味贪小。另一个是云盘必须支持在线扩容,PVC 的 StorageClass 里要设置allowVolumeExpansion: true。扩容操作本身不复杂,改 PVC 容量、等云盘层扩展完成、再在节点上执行文件系统扩容,但踩过的坑不少,后面故障排查部分会单独说。
3.3 节点亲和、拓扑分布与资源预留
Doris 这样的重负载组件,不能让它“随便调度到任何节点”。我建议在集群里规划一个专门的大数据节点池,给节点打上专用标签,然后用 nodeAffinity 把 BE 绑定过去。这样可以避免大数据组件和在线业务互相争抢 CPU 和内存。
nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: node-role operator: In values: - bigdata同时,要控制同一个角色不要集中在一台物理机器上。用 podAntiAffinity 让 BE 副本尽量打散到不同节点,这样一台机器宕机只损失一个副本的数据分片,Doris 可以快速补副本恢复。
资源预留方面,大数据组件通常配置大内存,比如 BE 的 limits 可能是 32Gi、64Gi 起步。如果不对节点做系统预留,Pod 很可能会把宿主机内存吃满,触发系统 OOM 甚至 kubelet 不稳定。建议在 kubelet 启动参数里设置system-reserved为memory=4Gi左右,或者至少保证节点内存总量减去所有 Pod limits 还有 5%-10% 的余量。
重要提示:BE 这类重状态服务的 QoS 等级一定要设置为 Guaranteed,也就是 requests 和 limits 完全相等。Burstable 的 Pod 在节点内存紧张时可能被驱逐,对 BE 来说触发驱逐等于强制杀掉数据节点,后果远比 CPU 限流严重。
3.4 大数据集群部署策略里的三个典型教训
第一个教训是,不要在 Kubernetes 层面用多副本的方式给 Doris 做数据冗余。BE 的数据副本策略由 Doris 自己管理,你在 K8s 里多拉几个 BE 副本并不会增加数据副本数,反而可能导致 Doris 集群识别异常。
第二个教训是节点维护之前要做优雅下线。自建机房经常有硬件维护,如果直接kubectl drainBE 所在节点,BE 进程被强杀,Doris 集群会立即开始大量补副本,瞬时压力可能把集群拖垮。正确做法是先在 Doris 层执行 BE 的 decommission 操作,让 Doris 自己把数据迁移走,再执行 drain。
第三个教训是存储扩容之后文件系统也要扩容。云盘在线扩容后,PVC 容量变了,但节点上的文件系统不会自动变大。需要进入 Pod 或节点执行resize2fs或xfs_growfs,很多团队在扩容后以为完成了,结果 BE 写满磁盘才发现文件系统还是旧容量。这条我放进后面的故障排查速查表里,避免遗忘。
4. 资源治理、多租户隔离与弹性伸缩的取舍
集群到了这个阶段,不再只是“能跑业务”,而是要考虑怎么稳定地跑很多业务。现实情况是:一个团队搭建的 Kubernetes 1.32 高可用集群,往往要服务多个项目组、多个环境。如果所有人都挤在default命名空间,没有配额限制,很容易出现某个业务突然把集群资源占满、其他业务全部受影响的情况。所以,资源治理和多租户隔离是生产集群的必修课。
4.1 Namespace、ResourceQuota 与 LimitRange 的配合使用
多租户的最佳实践是:每个团队或每个业务线一个独立的 Namespace,然后在 Namespace 上挂 ResourceQuota 和 LimitRange。
ResourceQuota 是总限额,告诉这个 Namespace 最多能用多少 CPU、内存、Pod 数量、PVC 数量。LimitRange 是单 Pod 的默认值和上下限,防止用户在 Namespace 里创建一个没有资源请求或者资源请求过大的 Pod。两者配合的逻辑是:ResourceQuota 管总量,LimitRange 管单量。
一个生产级的配置示例:
apiVersion: v1 kind: ResourceQuota metadata: name: quota namespace: team-bigdata spec: hard: requests.cpu: "32" requests.memory: 128Gi limits.cpu: "64" limits.memory: 256Gi pods: "200" persistentvolumeclaims: "50"apiVersion: v1 kind: LimitRange metadata: name: default-limit namespace: team-bigdata spec: limits: - default: cpu: 500m memory: 512Mi defaultRequest: cpu: 100m memory: 128Mi max: cpu: "8" memory: 32Gi min: cpu: 50m memory: 64Mi type: Container我特别建议把 LimitRange 里的defaultRequest配置上。很多开发者在使用集群时不会认真编写 resources 块,如果没有默认值,调度器会认为 Pod 不占资源,把它们全堆到同一台节点上。加上默认请求值之后,即使开发者什么都不写,系统也会替你兜底。这个机制是 Kubernetes 里很实用但又经常被忽略的。
4.2 PriorityClass 与抢占恢复策略
集群资源紧张时,怎么保证核心业务不被边缘业务挤占?答案是 PriorityClass。Kubernetes 调度器会根据 Pod 的优先级排序,高优先级的 Pod 可以先调度,甚至在必要的时候抢占低优先级 Pod 的资源。
配置 PriorityClass 本身很简单:
apiVersion: scheduling.k8s.io/v1 kind: PriorityClass metadata: name: high-priority value: 1000000 globalDefault: false description: "核心业务使用" apiVersion: scheduling.k8s.io/v1 kind: PriorityClass metadata: name: low-priority value: 1000 globalDefault: false然后 Pod 在spec.priorityClassName里指定。这里的优先级有讲究:系统默认的优先级是 0,你设置的数值越大越优先。Kubernetes 内置了两个系统级 PriorityClass:system-cluster-critical是 2000000000,system-node-critical是 2000001000,不要把自己的业务优先级设置得接近甚至超过它,否则你可能会抢占到 kube-system 里的核心组件。
抢占行为的理解也很重要。调度器发现高优先级 Pod 无法调度时,会尝试驱逐低优先级 Pod 腾出资源。这个驱逐不是立刻杀掉的,会按优雅终止期限来,默认 30 秒,但实际情况中低优先级 Pod 的容器被终止后会重启。所以,不要什么都设成高优先级,否则抢占机制就没有意义了。
4.3 节点级弹性伸缩:Cluster Autoscaler 与 Karpenter 的取舍
前面讨论的 HPA 解决的是 Pod 副本数的问题,但集群节点资源不够时,Pod 调度不上去,HPA 扩到上限也白搭。这时需要节点级的弹性伸缩。
在云环境里,常见方案是 Cluster Autoscaler(CA)和 Karpenter。CA 依赖云厂商的节点组 API,扩容时需要等新的云主机创建并加入集群,通常要 5-10 分钟,对突发流量来说偏慢。Karpenter 的优势在于它可以基于调度需求直接创建最合适的实例,并在一分钟内完成节点加入,速度快、粒度细,适合大规模弹性场景。
自建机房的场景就完全不同了。没有云 API 可以调用,物理机的交付周期通常以天计,节点自动伸缩并不现实。这种场景下,我更推荐把精力放在 HPA、VPA 和资源配额治理上,配合少量预留的 buffe 节点池来应对突发流量。
具体到 Kubernetes 1.32 这个版本,节点弹性伸缩和 HPA、VPA 的配合已经比较成熟。只是要注意:Cluster Autoscaler 需要配置合理的scale-down-utilization-threshold,避免节点利用率一降就缩容导致 Pod 频繁搬迁;Karpenter 则需要设置好consolidationPolicy防止碎片化实例被不断替换,反而浪费成本。
5. 现场实录:高可用集群故障排查与避坑清单
最后这一部分,我整理一些在真实集群里反复踩过的坑,每条都对应一套排查思路。这些内容不会写在官方文档里,但往往是最影响线上稳定性的细节。
5.1 API Server 连接抖动与负载均衡健康检查
现象:kubectl命令偶尔超时或报错connection refused,但集群整体看起来又没挂。排查时先看负载均衡器的健康检查配置。很多人在 HAProxy 或云负载均衡里把健康检查路径写成了/,而 API Server 的/会返回 404,健康检查自然失败。正确路径一般是/healthz或/livez,Kubernetes 1.32 里livez是更细粒度的存活检查。
另外注意,如果健康检查返回 403,通常是匿名访问被禁用,需要在 APIServer 配置的system:public-info-viewer角色里放行 healthz 路径,或者通过认证方式访问。这个坑在启用 RBAC 严格模式后容易出现。
5.2 PVC 一直 Pending 的排查链路
现象:kubectl get pvc显示Pending,对应 Pod 调度不上去。排查顺序应该是:先查 StorageClass 是否存在,再查 provisioner 是否正常运行,再查 PVC 的事件。kubectl describe pvc <name>里通常会给出具体原因。
有一种很隐蔽的情况:集群里用了多个 StorageClass,但 PVC 没指定storageClassName,结果它用了默认存储类,而默认存储类的 provisioner 没安装,PVC 就一直 Pending。解决办法要么装好默认存储类对应的 provisioner,要么在 PVC 里显式指定storageClassName。
Local PV 场景还有另一种坑:PVC 成功创建了,但 Pod 调度不上去,因为 Local PV 有nodeAffinity,只能调度到数据所在节点,而那个节点可能被打了NoSchedule污点。这时查 Pod 事件会看到0/3 nodes available,原因是节点亲和性和污点同时生效。
5.3 Ingress 流量倾斜,转发不均匀
现象:业务 Pod 有 5 个副本,但通过 Ingress 访问时,某个 Pod 的流量特别高,其他 Pod 几乎为空。首先看 Service 的externalTrafficPolicy,如果它被设置为Local,流量只会转发到本节点上的 Pod,跨节点副本自然分不到请求。Cluster模式才具备全量转发能力。
其次看 ingress-nginx 的上游 keepalive 配置。Nginx 默认会复用后端连接,长时间运行的连接可能一直停留在同一个 Pod 上,尤其当整体流量不大、连接数少时,表现就是流量倾斜。这不是故障,而是长连接特性,但如果你希望更均衡,可以把upstream-keepalive-connections调低,或者在应用层通过 cookie 等方法做会话保持。
5.4 HPA 扩缩容震荡,副本数反复横跳
现象:Pod 数量在几分钟内不断增减,业务没有明显波动,但副本数在上下跳动。这个问题的核心原因通常是单指标尖刺,或者多指标叠加导致期望副本数频繁变化。建议在 HPA 的behavior里配置缩容稳定窗口:
behavior: scaleDown: stabilizationWindowSeconds: 300 policies: - type: Percent value: 20 periodSeconds: 60stabilizationWindowSeconds: 300的意思是,缩容决策会参考过去 5 分钟的指标趋势,避免因为一次短暂的 CPU 下降就立刻缩容。另一种情况是 HPA 同时配置了 CPU 和内存两个指标,只要其中一个超过目标就扩容,但缩容时又要求两个都低于目标,这时系统很可能在扩容后快速缩容。我个人的建议是,一个 HPA 尽量只用一个主导指标,不要贪多。
5.5 故障排查速查表
| 现象 | 可能原因 | 处理动作 |
|---|---|---|
| API Server 健康检查失败 | 健康检查路径不对,或 RBAC 未放行 | 修改为 /healthz,检查 system:public-info-viewer |
| PVC Pending | StorageClass 不存在或 provisioner 未安装 | describe PVC 查事件,核对 storageClassName |
| Pod 调度不上 | 节点资源不足、亲和性不满足、污点未容忍 | describe Pod 查事件,逐项检查调度约束 |
| Ingress 流量倾斜 | externalTrafficPolicy=Local 或长连接复用 | 改 Cluster 模式,调整 keepalive 配置 |
| HPA 副本反复横跳 | 指标尖刺、多 HPA 指标冲突 | 配置稳定窗口,收敛指标数量 |
| 云盘扩容后磁盘没变大 | PVC 扩容后未执行文件系统扩容 | 进入节点执行 resize2fs 或 xfs_growfs |
| 节点维护导致 Doris 大量补副本 | BE 未做优雅下线 | 先在 Doris 层 decommission BE 再 drain |
最后再补一条自己踩过的教训:所有的高可用验证和故障演练,一定要写成文档、留好操作记录,并且至少每季度做一次。集群搭起来并不难,难的是让它在各种意外中依然稳定。建议把这一篇第 1 部分的演练内容做成“例行应急演练清单”,配合 etcd 备份脚本和恢复手册,变成团队沉淀下来的资产。下一期我会接着聊安全加固与证书管理,包括 RBAC 权限模型、Pod Security Standards 以及证书轮换的自动化思路,这些都是高可用集群上线之后躲不开的功课。