华为云容器引擎 CCE:Kubernetes 生产集群搭建与运维
托管 K8s 把控制平面变成"别人的服务",代价是把看得见的复杂度换成了看不见的耦合。这篇的重点是分清:哪些故障你还能自己查,哪些只能等。
从自建 K8s 换到托管集群,第一周的感觉通常是"轻松":装集群、修 etcd、换证书这些活全没了。第二周开始会冒出一个新的不安——kubectl 还能用,但你不太确定它在跟谁说话,出了事也不知道能查到哪一层。
这个不安是对的。托管没有消灭复杂度,它做的是把复杂度从一个地方挪到另一个地方:把"看得见的运维负担"换成了"看不见的耦合边界"。这篇想讲清楚这条边界在哪。
#一、托管的分界线
托管的准确含义不是"K8s 由厂商运维",而是:
| 层次 | 自建集群 | 托管集群(CCE 这类) |
|---|---|---|
| 控制平面(apiserver/etcd/scheduler) | 你装、你修、你能看日志 | 厂商维护;你能看指标,通常看不到主机 |
| 数据面节点 | 你装 kubelet、你修 | 你管节点池,节点上的问题你能进 |
| 网络插件 | 你选、你调 | 通常平台集成,可调项是子集 |
| 版本生命周期 | 你自己决定 | 由平台的受支持版本决定 |
| 故障时能查的深度 | 全栈 | 到控制平面入口为止 |
看最后一行:这是托管最本质的代价。你能查的东西变少了,而且减少的部分恰好是最难自建的那部分。
这不是说托管不好——对绝大多数团队来说,自己维护 etcd 的风险远大于"少看到一层日志"的不便。但要接受它,并且在架构上为"查不到"留出余量(例如:客户端侧要有足够的可观测性,不能把全部诊断希望寄托在 apiserver 日志上)。
#二、节点池:把机器变成可丢弃的单位
节点池是托管集群里最重要的一个抽象。它的价值不在"批量管理",而在于它把节点从"资产"变成了"规格"。
用起来的关键是:按负载特征分池,而不是按机器型号分池。
| 池的划分依据 | 例子 | 好处 |
|---|---|---|
| 工作负载类型 | 通用 / GPU / 内存密集 | 调度约束清晰,扩缩容互不干扰 |
| 稳定性等级 | 在线服务 / 批处理 / 抢占式 | 故障与回收的影响面被隔离 |
| 生命周期 | 长期 / 临时 | 升级时可以整池替换 |
第三行值得单独说:"整池替换"是滚动升级真正能落地的前提。 如果一个池里混着不同年代、不同配置的节点,升级就变成了逐个(且各不相同)的维护动作;如果池是同类节点,升级可以做成"新池建好、流量切过去、旧池销毁"——从"修机器"变成"换机器"。
这也是云上最该被用起来的特性:把机器当成可以随时丢弃的东西,前提是任何一台机器上都没有不可重建的状态。
#三、可用性预算:你允许自己同时弄坏几台
K8s 里有一组机制专门用来表达"现在可以坏几台",理解它们之间的关系比记住名字有用:
| 机制 | 表达什么 | 用错时会发生什么 |
|---|---|---|
| 副本数 | 需要几个实例 | 单副本服务在节点维护时直接中断 |
| 反亲和/拓扑分布 | 这些实例别挤在一起 | 三副本全在一台机器上 |
| PodDisruptionBudget (PDB) | 自愿中断时最多坏几个 | 配得太严,节点永远驱逐不干净 |
| 就绪探针 | 什么时候算能接流量 | 探针太松,把坏实例也接进流量 |
第二行和第三行是一对:反亲和解决"物理上会不会一起坏",PDB 解决"运维动作会不会一次坏太多"。 两者缺一,高可用就是靠运气。
PDB 最容易配错的方向是"太严":
# 三副本、PDB 要求至少 2 个可用 → 一次只能坏 1 个
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: web
spec:
minAvailable: 2
selector:
matchLabels: { app: web }看起来保守,实际会出现一个很具体的现象:节点排空(drain)卡住不动,因为驱逐会被 PDB 拦住。这时候人容易做两件事——加大 --timeout(没用),或者直接把 PDB 删掉(危险)。正确的做法是理解"排空是自愿中断",然后按业务窗口安排它。
#四、托管集群的网络,边界在哪
网络是托管集群里最容易出现"我觉得是这样"的地方。三条常见边界:
- Pod 网段与节点网段的关系:不同网络模式(overlay 与 underlay 思路)决定了 Pod IP 能不能被集群外直接访问、SNAT 发生在哪里。这直接决定你排查"包到底有没有到"的路径。
- 服务端负载均衡的实现:
LoadBalancer类型的 Service 背后是厂商的负载均衡实例,这个实例有它自己的健康检查与会话保持策略——两个健康检查不一致,会出现"K8s 认为健康、LB 认为不健康"的经典错配。 - 网络策略的默认行为:NetworkPolicy 是白名单式的,未匹配的流量默认怎么走,各实现略有差异(有的默认允许,有的默认拒绝),上线前必须验证一次,而不是按理解假设。
第二条特别值得记住:任何"两层健康检查"的系统,错配是迟早的事。 排查时先确认"谁在判死",再去看被判定的一方。
#五、能自己查的 与 只能等的
这是这篇最实用的一节。把故障分一下类,心里会踏实很多:
| 现象 | 你能不能自己往下查 |
|---|---|
| Pod 起不来、反复重启 | 能。kubectl describe、容器日志、事件 |
| 节点 NotReady | 部分能。节点本身能进,kubelet 日志能看到一部分 |
| Service 访问不通 | 能查到网络策略与端点,但云负载均衡那一层可能看不到 |
| apiserver 报 5xx / 限流 | 基本只能等。能看到的是客户端侧的错误率与延迟 |
| 调度不上去 | 能。看事件里的调度失败原因,通常是资源或污点 |
| 存储挂载失败 | 部分能。CSI 侧日志可见性取决于平台 |
最后一列那两条,正确的应对方式不是"想办法看到",而是在设计阶段就不依赖它:
- 给 apiserver 的调用方(controller、operator、CI)加退避与降级。
- 关键路径不要每次都实时查询 apiserver(比如用缓存/影子配置),避免把控制平面当成数据面用。
#六、成本:节点池的浪费长什么样
托管集群的账单浪费通常不是"节点太大",而是三种结构性的:
- 池的碎片:多个小池,每个都有闲置余量。池越多,余量被重复预留的次数越多。
- requests 与 limit 的差距:调度按
requests,实际用 limit 附近的量很少。requests 虚高是云上最普遍的隐性浪费。 - 缩容不下来的负载:没有用
HPA,或者用了但伸缩指标选错了(例如按 CPU 伸缩一个 IO 密集的服务,永远不触发)。
第一条和第三条都能靠"先把池合并、再按负载分池"解决;第二条需要的是基于实际用量的 requests 校准,而不是一次调完就完事——它需要一个定期校准的机制。
#七、这篇没写什么
- 没写集群创建的具体步骤与控制台参数。 界面与选项随版本变化,请以官方文档为准。
- 没写 CSI/CNI 各实现的对比。 差异大且演进快,结论很容易过期。
- 没写 Service Mesh 与 Ingress 细节。 那是构建在集群之上的另一层,独立成篇更清楚。
- 没给集群规模数字。 "多大的集群该用托管"取决于团队的自维护能力,不是节点数。
一句话收束:托管把控制平面变成了服务,代价是你的诊断能力在某个深度上被截断。承认这条边界、并围绕它设计客户端侧的可观测性,比假装它不存在要安全得多。
写于 2026 年 6 月 12 日
- 栏目
- 技术文章
- 约
- 6.1 分钟
- 字数
- 3.1K
- 阅读
- 1
本文为原创记录,转载请注明出处。如果这篇替你省了时间,欢迎留言说说你踩到的坑。
同题 · related
- 把博客从 docker-compose 搬到 k3s:单机迁移与上线全过程在 4C3.6G 的云主机上把博客从 docker-compose 迁到单机 k3s。附完整 YAML 清单(Deployment、Service、PVC、Ingress、Certificate 等)与全部配置命令,记录部署、数据迁移与切换上线的踩坑过程。
- 5 台服务器,从二进制装 K8s 到 Spring Cloud 上线用 5 台服务器把整套平台搭出来:二进制部署 Kubernetes 1.36 高可用集群,装完 Harbor、Gitea、Nexus、Jenkins、Argo CD、监控日志链路追踪,最后把 Spring Cloud 微服务项目发布上线。每一步都给可执行命令。
- DevOps 运维中 AI 那些事把 AI 放进运维的真实分工:从服务器硬件、网络、GPU、内存,到虚拟化、Kubernetes、应用构建、CI/CD、可观测性、资源分配,再到 AI 自身的部署与算力调度。讲清楚哪些活它能接、边界划在哪、以及我踩过的那些坑。
留言 · remarks
00 条还没有留言,来说点什么吧。