接手过不少公有云上跑的Kubernetes集群,腾讯云的TKE和阿里云的ACK占了大多数。前两天翻自己的运维笔记,正好到第12章第2节,写的就是这两个托管平台的生产级运维。网上聊自建kubeadm的教程一抓一把,但真正在TKE、ACK上把集群玩明白、把线上事故摁下去的实战经验,反而散得很。这篇就把我这些年攒下的选型思路、建集群时埋过的雷、排障链路、升级胆量训练,一次性倒出来。正在用或者准备上TKE、ACK做生产环境的同学,这套东西基本可以直接照着抄。
- 先搞清楚自己用的是什么"托管":TKE与ACK的形态差异
很多人一听"托管集群"就觉得万事大吉,这是第一个误区。TKE和ACK的托管是分档位的,选错了形态,后面运维姿势完全是两码事。
1.1 托管版、自管版与自建集群的取舍
先看一张对比表:
形态 | 控制面(Master)谁运维 | 能否SSH到Master | 自定义组件参数 | 适合场景 自建kubeadm | 自己 | 可以 | 完全自由 | 想彻底掌控、愿意投入人力 TKE 独立集群 | 自己 | 可以 | 完全自由 | 需要自定义kube-apiserver参数 TKE 托管集群 | 腾讯云 | 不可以 | 受限 | 绝大多数生产业务 ACK Pro 托管 | 阿里云 | 不可以 | 受限 | 绝大多数生产业务 ACK 专有版 | 自己 | 可以 | 完全自由 | 合规要求必须自管Master
生产环境我几乎无脑推荐托管版,原因很简单:控制面的高可用、etcd备份、apiserver异常恢复这些脏活,云平台替你扛了。托管版出问题,工单一发,平台侧能直接查控制面组件状态,比自己半夜爬Master节点强太多。
但代价也得知道:托管之后你上不了Master,像自定义apiserver的审计策略、改controller-manager的某些启动参数,平台控制台不开放就不行。所以如果你的团队有强烈的Control Plane定制需求,或者等保合规明确要求运维人员可登录Master,那就选自管版或干脆自建。
提到自建,我多说一句。网上搜kubeadm教程时常见这么一段输出:
[init] using kubernetes version: v1.26.0 [preflight] running pre-flight checks ... kubeadm join 192.168.1.10:6443 --token xxx \ --discovery-token-ca-cert-hash sha256:xxx很多人以为init跑完集群就自动完好,实际上控制面初始化成功之后,还需要手动把这些 join 命令复制到每个Worker节点上执行,Worker才会加进来。这个环节漏了,kubectl get node永远只有Master一个节点。托管集群没有这一步,控制台添加节点就行,但底层逻辑一样——节点加入是独立动作,别把"创建集群"和"节点就绪"划等号。
1.2 网络模型差异决定了你的排障姿势
TKE和ACK在网络模型上的选择直接决定了以后排查问题的手段。
TKE主要两种模式:
- GlobalRouter:基于VPC路由的容器网络,Pod IP和Node IP同在一个VPC平面,通过路由表转发,性能和传统虚拟机网络接近,排查时可以在VPC路由表里看到容器网段的路由条目。
- VPC-CNI(含Cilium):弹性网卡直连,每个Pod一张ENI,网络延迟最低,安全组可以精细到Pod,但可分配的Pod数量受节点规格和可用子网IP数量限制。
ACK主要也是两种:
- Flannel:经典overlay网络,VXLAN封装,Pod网段与VPC网段隔离,排查时容易遇到跨节点通信走隧道,抓包要进隧道口看。
- Terway:阿里云自研CNI,基于ENI直连,性能强,支持Trunk弹性网卡,同样存在IP资源上限问题。
从运维视角看,这两家有个共同规律:
网络模型 | Pod IP是否VPC内直接路由 | 排障关注点 Flannel/GlobalRouter路由表模式 | 部分隔离/路由可达 | 路由表、iptables规则、conntrack表 VPC-CNI/Terway ENI直连 | 直接可达 | 弹性网卡配额、安全组规则、子网IP余量
我建议生产环境优先选ENI直连模式(VPC-CNI或Terway),性能好,Pod IP和云资源互通方便,安全组能直接管理Pod粒度。代价就是IP规划要精细,很多搞不定的人工裁减问题实际是子网IP不够。选Flannel类overlay虽然IP压力小,但排查网络问题时要多查一层封装,conntrack满载、iptables规则膨胀这类坑,够你喝一壶。
1.3 节点的选择:实例规格、系统盘、数据盘分开看
节点选型不是越大越好。我见过有人一台64C256G裸奔跑所有业务,最后单点爆炸。生产建议:
- 业务节点每台规格控制在8C16G到32C64G之间,太大故障爆炸半径大,太小Pod密度上不去浪费资源。
- 系统盘和数据盘必须分开。系统盘用50GB左右的高效云盘起步,数据盘挂独立的SSD/ESSD给容器运行时和镜像存储。默认40G系统盘跑生产,一周爆满是常事。
- 如果有GPU业务,GPU节点单独建池,不要和CPU业务混部。
另外,ACK的节点池和TKE的节点池逻辑类似,都是"一组配置相同的节点"。我后面单独讲节点池设计,但选型阶段的铁律是:不同付费模式(包年包月、按量、Spot)、不同机型、不同标签用途的节点,一定分开池子。
- 建集群阶段就埋下的雷:网络规划、节点池与权限
集群创建只是半天的事,但创建时填错的每个选项,都会在半年后的某个凌晨变成事故。这个阶段最值得花时间的就三件事:CIDR规划、节点池设计、权限边界。
2.1 网段规划:一段CIDR规划示例
容器网段和VPC网段重叠,是最低级的错误,但真有人踩。Kubernetes里Service网段和Pod网段一旦定下来,后期几乎不可能改,只能重建集群。
我常用的生产规划示例:
对象 | 网段 | 说明 VPC主网段 | 10.10.0.0/16 | 承载节点、SLB/NLB、数据库等云资源 Pod网段(TKE GlobalRouter/ACK Flannel) | 172.16.0.0/16 | 独立大网段,和VPC不重叠 Service网段 | 172.16.128.0/17 | 从Pod网段中单独划出,或云平台默认分配 节点子网 | 10.10.0.0/19、10.10.32.0/19 | 按可用区划分,方便多AZ容灾
给TKE的VPC-CNI或ACK的Terway设计时,Pod子网要从VPC主网段里划,比如10.10.128.0/18和10.10.192.0/18分别放在不同可用区。这时候有个容易被忽略的约束:Terway/VPC-CNI创建Pod要占用VPC IP,一个节点最大Pod数取决于弹性网卡能挂的辅助IP数量,而不是你想跑多少跑多少。实例规格越大、单卡辅助IP越多,Pod密度才越高。
还有一点,Service网段不要和VPC内任何网段重叠,否则kube-proxy的ClusterIP会和云上资源IP冲突,表现就是Pod里访问某个内网地址时通不通全看运气。
2.2 节点池是生产集群的骨架
节点池建得好,扩缩容、升级、故障隔离都是点几个按钮的事。我通常按三个维度拆分:
维度 | 节点池划分 | 典型配置 业务维度 | 核心交易、通用业务、离线任务 | 不同规格,核心业务独占池 付费维度 | 包年包月池、按量池、Spot池 | Spot池跑无状态可重放任务 调度维度 | 带污点池、无污点池 | 关键应用容忍度控制
以ACK为例,一个金融客户生产集群我会拆成:core-production节点池(包年包月,c7系列8C32G,taint专用)、common-online节点池(按量,g7系列4C16G)、spot-offline节点池(抢占式实例,跑批量计算)、gpu-inference节点池(GPU节点,带NVIDIA污点)。
这样拆的好处:Spot节点被回收只影响离线池,不会把核心业务带走;包年包月池打底,按量池弹性兜底,成本可控。TKE的节点池玩法一样,腾讯云叫弹性伸缩+节点池,抢占式实例就叫竞价实例,原理相通。
创建节点池时的两个坑:
- 一定要给节点池打标签(比如pool=spot),部署时通过nodeSelector指定调度目标,否则调度器把关键Pod扔到Spot池就悲剧了。
- 节点池的扩缩容阈值要结合集群剩余可分配量看,别只盯着CPU。内存接近耗尽但CPU还有余量的情况非常普遍,HPA和节点扩缩容都容易失灵。
2.3 权限与安全组的最小化配置
权限问题是最容易拖后腿的。TKE走CAM,ACK走RAM,一开始就按最小权限建模,后面省无数事。
我的落地经验:
- 创建独立的服务角色(TKE的QCloudTKE/ACK的AliyunCSDefaultRole),不要让集群使用主账号默认角色。
- 开启RAM Roles for Pods(ACK)、OIDC联邦(TKE),让Pod通过云平台临时凭证访问OSS/COS等云资源,而不是在代码里硬编码AccessKey。AK泄露调MFA、轮换密钥的痛,真不想再经历第二次。
- RBAC按命名空间收敛:给每个业务团队建独立Namespace和ServiceAccount,绑定只对该Namespace的Role,ClusterRole资源(如节点查看权)收紧到运维组。
安全组方面,节点安全组不要为了省事直接放通0.0.0.0/0的所有端口。至少要做到:管控端口(22、10250)只对运维跳板机网段开放;Pod网段的互访规则在VPC-CNI/Terway模式下通过Pod安全组控制;节点连接SLB/NLB的健康检查端口要放通。TKE默认的安全组规则比较保守,ACK的Terway模式对安全组依赖更强,加白名单时一定要把Pod网段覆盖进去,而不是只加节点IP。
- 节点NotReady与Pod Pending:一条能复现的排障链路
集群出问题的前两大信号就是节点NotReady和Pod Pending。很多人一上来就重启节点,治标不治本。我从告警触发开始讲完整的排查链路,这部分可以当作标准作业程序直接收藏。
3.1 Node NotReady:从告警到根因的递进式排查
生产环境我收到过无数次节点NotReady告警,90%的根因集中在几个地方。按下面顺序排查,基本不会漏:
- 先看云平台控制台的节点信息。TKE/ACK的节点列表里会显示NotReady的状态时间,如果整批节点同时NotReady,优先怀疑网络组件(Terway/GlobalRouter/Cilium)或集群升级操作;单个节点异常,优先怀疑节点自身。
- SSH登录节点,第一件事看kubelet状态和服务日志:
systemctl status kubelet journalctl -u kubelet -f --since "10 minutes ago"kubelet的常见错误有几种:证书过期、连接apiserver超时、容器运行时不可用。日志里说话很直白。 3. 检查容器运行时。现在默认都是containerd:
crictl ps -a crictl images如果crictl执行卡住或报错,基本就是容器运行时G了,和kubelet本身无关。 4. 看磁盘和inode:
df -h df -i注意看/var/lib/containerd和/var/lib/kubelet所在分区,镜像堆积和数据盘写满是最常被忽视的元凶。df -h看着还有空间,但inode满了也一样会挂。 5. 看内核和网络组件。Terway/GlobalRouter这类CNI如果有单独的Agent进程,也要检查它们的日志。节点长时间NotReady还要看一眼内核日志里有无oom、panic。
根因对照表:
症状特征 | 大概率根因 | 首次处理 kubelet日志大量"node xxx not found" | kubelet证书过期 | 过期时间确认后,重签发证书或更新节点 crictl ps卡死,docker进程异常 | containerd故障/镜像堆积 | 清理镜像,必要时重启containerd df -h显示100%分区 | 数据盘满 | 清理/var/lib/containerd,设置镜像GC策略 某安全组规则改动后集体NotReady | 安全组阻止kubelet连apiserver | 检查10250端口放通 节点实例被释放/抢占 | Spot节点回收 | 节点池自动扩容补位
3.2 Pod Pending:kubectl describe里的信息怎么读
Pod Pending的第一现场永远是describe:
kubectl describe pod <pod-name> -n <namespace>Events字段里会直接告诉你调度失败原因。最常见的几类信息,我翻译一下:
- 0/1 nodes are available: 1 Insufficient cpu。CPU不足,看该节点是否被别的Pod打满,或者请求值是否过大。
- 0/1 nodes are available: 1 node(s) had untolerated taint。节点有污点,Pod没配容忍。要问一句:这个Pod真的不该跑在那台节点上吗?还是忘了给容忍?
- 0/1 nodes are available: 1 node(s) didn't match Pod's node affinity/selector。nodeSelector和节点标签不匹配。这是配节点池后最容易踩的坑,标签打错或selector写错都是常事。
- no PersistentVolumes available for this claim。PV调度失败,常见于云盘类型与可用区不匹配,比如Pod调度到可用区A,但静态PV的云盘在可用区B,隔区就用不了。
注意,describe看Event,但Event会滚动,被顶掉就看不到了。我习惯先跑一遍
kubectl describe pod xxx -n xxx | tail -30再叠加
kubectl get events --sort-by=.lastTimestamp -n xxx两条命令对着看,基本能把Pending原因钉死。
3.3 一次CPU Limit引发的雪崩复盘
讲个真实事故。有个无状态网关服务,YAML里写了resources.limits.cpu=500m,但业务高峰期单个Pod实际能跑到1.2核。Kubernetes对CPU Limit的压制导致Pod反复重启,每次重启都有几十秒冷启动,流量在Pod间抖来抖去,节点CPU被反复打高,触发了节点压力驱逐,最后集群里一大片Pod变成Evicted。
排查链条是这样的:先是告警爆CrashLoopBackOff,describe看到Liveness探针失败,但log里业务日志又没异常,只有OOMKilled字样;然后看节点监控,发现CPU使用率曲线是锯齿状;最后翻到ResourceQuota和limit配置,才发现是limit设得太死。
这类坑的根本解法不是调大limit,而是:
- 无状态服务尽量不设CPU limit,靠HPA按CPU使用率扩缩容来兜底;
- 如果团队规范强制要limit,那就用requests和limits分离,限制值至少是稳定峰值的1.5倍;
- 配上PodDisruptionBudget,防止节点排空时Pod被一波清掉。
- 可观测性建设:监控、日志与告警的实战配置
生产集群没有可观测性,等于裸奔。很多团队只依赖控制台自带的基础监控,这是不够的。
4.1 双轨监控:云监控保底,Prometheus做深度
TKE和ACK控制台都自带云监控(节点CPU、内存、负载均衡流量等),这些是保底项,零成本,必须都开。但深度可观测性一定要上Prometheus。
腾讯云有托管的Prometheus监控服务,阿里云有ARMS Prometheus,直接和TKE/ACK打通,省去自己维护Thanos的麻烦。开好后,至少要盯下面这些指标:
- 节点层:CPU利用率、内存利用率、磁盘I/O、网络重传率
- 容器层:Pod内存RSS、CPU usage、restart次数
- 集群层:APIServer请求错误率、etcd磁盘延迟、ControllerManager队列深度
- 业务层:工作负载RPS、P99延迟、错误率、HPA当前副本数
有一个容易被忽略的指标:HPA的currentReplicas与desiredReplicas。扩不起来和缩不下去都是事故前兆。
Prometheus探活Kubernetes组件时,注意托管版的etcd和apiserver指标暴露点要按云平台文档配置,不要照搬自建集群的serviceMonitor写法。TKE和ACK各自有对应的组件指标接入配置,控制台上勾选即可。
4.2 日志采集:容器标准输出、文件日志与审计日志
日志采集上,TKE默认对接CLS日志服务,ACK默认对接SLS。方案上比自建ELK省心不少,但有几个配置细节:
- 标准输出日志用default采集配置就行,正则按json_lines或single_line选好。
- 应用写文件日志的场景,容器里用emptyDir或hostPath挂载后,采集路径要写到宿主机真实路径,别写成容器内路径。CLS/SLS的日志采集Agent跑在节点上,读不到容器内路径。
- 多行日志(比如Java堆栈)一定要开多行处理正则,否则一行异常堆栈会被拆成几十条日志。
- 审计日志强烈建议开启。TKE控制台里有审计相关开关,ACK也有集群审计功能,把apiserver的审计日志接到日志服务,安全合规和排障都能用。出过一次恶意操作后,回头翻审计日志才知道是谁在什么时候改了关键Deployment——这种后悔药不是每次都买的到。
4.3 告警规则设计与告警噪音治理
告警规则设计有一条铁律:每条告警都必须能对应一个可执行的处置动作。无法执行的告警,不如不建。
我通常把告警分三级:
级别 | 示例 | 响应方式 P0 | 节点NotReady超过5分钟、APIServer不可用、业务错误率突增 | 立即on-call,15分钟内介入 P1 | PVC使用率超过85%、Pod反复重启、HPA扩缩容异常 | 工作时间内响应,2小时内处理 P2 | 节点CPU持续超过75%、镜像堆积 | 记录跟踪,日常优化
告警渠道用Webhook接钉钉/企业微信/飞书,分不同群。P0群永远有人值班,P2只进日报群。TKE的监控告警和ACK的ARMS告警都支持配置分组、静默策略和通知周期,一定要把"非工作时间只发P0"这种规则配上,不然告警疲劳是必然的。
- 集群升级与节点维护:生产环境最考验人的操作
升级是生产集群运维里最刺激的操作,没有之一。控制面托管已经是云平台给你兜底,但节点升级、业务Pod迁移仍是高危动作。
5.1 升级前的检查清单
无论TKE还是ACK,升级前我必做这几件事:
- 查Kubernetes版本变更里的API弃用列表。不同版本会有API移除,比如旧版本里CronJob用的batch/v1beta1、PodDisruptionBudget用的policy/v1beta1,在新版本里直接不可用。升级前跑一下
kubectl get --raw /openapi/v3 2>/dev/null | head更直观的是用第三方工具比如pluto扫描集群里的API资源,把已弃用和即将移除的API列出来,逐个排查YAML。 2. 确认集群里的自定义Controller和Webhook与新版本兼容。特别是ValidatingWebhookConfiguration,版本升级导致的webhook故障会直接阻塞Pod创建。 3. 备份关键YAML和PV数据。托管版不好直接备份etcd,至少把Deployment、ConfigMap、Secret、ServiceAccount等核心资源用Velero或kubectl备份导出。有PV的数据库类服务,升级前打好快照。 4. 提前阅读云平台升级文档中关于"升级顺序"和"回滚入口"的部分。TKE和ACK都要求先升级控制面,再升级节点,顺序反了会出兼容性问题。
5.2 节点池滚动升级的实操步骤
节点池滚动升级逻辑上就是三步:隔离旧节点、排空Pod、替换新节点。具体操作:
- 在节点池配置里设好升级策略,TKE可以设置最大不可用节点数,ACK的节点池升级也有类似参数。我一般设maxUnavailable=1,一次只动一个节点。
- 手动执行时,按三条命令走:
kubectl cordon <node-name> kubectl drain <node-name> --ignore-daemonsets --delete-emptydir-datacordon是给节点打禁止调度标记,drain是排空Pod。注意尽量加--ignore-daemonsets,DaemonSet的Pod会被重新调度,不用强赶。 3. 云平台会重置或替换节点,新节点起来后,确认节点状态Ready、业务Pod迁移成功后,再处理下一个。
坑点提醒:
- drain时遇到PodDisruptionBudget不允许驱逐,命令会卡住。这是保护机制在工作,别硬删Pod,先看PDB配置是否过严。
- 有状态应用(StatefulSet)的Pod,排空时要注意PVC会不会因为节点迁移而失联。跨可用区的节点池升级,云盘类型PVC会有问题。
- 原地升级的节点(不是替换),drain后要等节点上的Pod完全终止,再让平台触发升级动作。有些平台在节点未排空时会直接拒绝升级,态度很明确。
5.3 升级失败的回滚与自救
节点升级失败的表现通常有两类:新节点启动后NotReady,或者业务Pod迁移后状态异常。
先说预防:每升级完一个节点池,观察15到30分钟,看节点Ready状态、业务错误率、Pod重启次数。没问题再动下一个池子。很多事故就是一口气把所有节点升完,出了问题连回滚的立足之地都没有。
回滚策略分两层:
- 云平台回滚:TKE节点池有"回滚"操作,能把节点池恢复到升级前版本。ACK的节点池也支持回滚到原先的Kubelet版本。前提是节点池还在、旧版本的节点模板没被删。
- 手动自救:如果平台回滚不了,最稳的办法是用旧版本的节点池模板重新扩容节点,把业务引到旧节点池,再把新节点池缩容到零。前提是你在升级前没有把旧节点池模板删掉。
升级之后etcd版本提升一般不可逆。所以升级前的备份不止是"预防",也是"认赔"的依据——真到了无法回滚的地步,至少业务数据还在。
- 网络与存储进阶:Ingress、负载均衡与PV/PVC
最后聊日常业务接触最多、也最容易出问题的网络入口和存储。
6.1 入口流量选型:CLB/ALB/NLB/Nginx Ingress
很多团队创建完集群就把Service指名成LoadBalancer,然后任由它堆满一堆公网SLB实例,既不统一也不经济。生产入口流量我建议这样分层:
场景 | 推荐方案 | 说明 公网七层路由 | Nginx Ingress Controller + 云负载均衡 | 路径路由、灰度发布、限流都靠Ingress规则 高性能七层网关 | ALB(ACK)/ CLB Ingress(TKE) | 托管网关,性能好、免运维 四层高性能TCP/UDP | NLB(ACK)/ CLB四层(TKE) | 数据库、RPC等不需要七层路由的场景 多集群统一入口 | 各自Ingress + 上层GSLB/云DNS | 做流量调度、故障转移
TKE上我把Nginx Ingress挂在CLB后面,CLB只做流量引入,真正的路由规则全部收敛到Ingress Controller。ACK上通常直接用ALB Ingress Controller,省掉Nginx层,配置也简单。注意Ingress Controller的副本数至少2个,并开启反亲和,跨可用区部署。
另一个常被忽略的是Service的externalTrafficPolicy。想保留客户端真实IP,要设置externalTrafficPolicy: Local,但会让负载均衡只调度到有Pod的节点,流量可能不均。Cluster模式下SNAT会让后端拿不到真实源IP。这个取舍要根据业务类型提前确定。
6.2 存储方案选型与挂载避坑
存储选型表:
存储类型 | 适用场景 | 注意点 云盘(CBS/ESSD) | 单Pod读写,数据库 | 单可用区限制,不能跨区挂载 NAS(CFS/NAS) | 多Pod共享读写 | 性能受吞吐上限影响,注意协议差异 对象存储(COS/OSS) | 静态文件、大数据分析 | 走内网endpoint,公网流量贵且慢 本地盘 | 高吞吐缓存 | 节点故障数据丢,仅限无状态
三个高频坑:
- 同一块云盘挂多个Pod。常见于把PVC做成静态,多个副本的Deployment都指定同一个PV,结果第二个Pod起来就发现VolumeAlreadyInUse。云盘本质是块存储,只支持单节点读写,多副本场景老老实实换NAS或者用ReadWriteMany的云存储。
- PVC的storageClassName没配对。集群里有多套存储类(ssd、essd、nfs),Pod不指定或指定错,调度时PVC都是Pending。检查一下kubectl get sc,把默认storageClass设置好。
- NAS挂载用错协议。TKE的CFS和ACK的NAS都有NFS和SMB协议,Linux容器只能用NFS,在StorageClass里配好协议即可。挂载后若出现文件锁问题,检查nfsvers参数,通常建议nfsvers=4.0。
6.3 备份与容灾:Velero与跨集群迁移
TKE和ACK都能用Velero做集群维度的备份。Velero可以把Namespace下的所有资源连同PV快照备份到对象存储,恢复时一键拉起来。
我的做法:
- 每天早上定时备份关键命名空间到COS/OSS;
- 数据库类Pod不依赖Velero的PV快照,而是走业务层备份(比如MySQL定时备份);
- 每个月做一次完整的恢复演练,不只是"备份成功"就完事,要真恢复出一个环境验证数据可读。
跨集群迁移场景也一样:TKE迁ACK(或反过来),Velero的备份文件格式统一,资源定义可以平移。但要注意存储类映射,TKE的CBS对应ACK的ESSD,恢复时需要在Velero的StorageClass映射配置里指过去,否则PVC起不来。
最后说点不太中听的大实话:托管集群不是买了保险,它只是把"你亲自运维Master"换成了"云平台帮你运维Master",但节点、Pod、网络、存储、业务安全,这些责任永远在自己手里。我见过太多人把TKE/ACK当黑盒,出问题只会提单,连describe都不跑,最后明明是业务配置问题,硬拖成P0事故。把这篇文章里提到的网段规划、节点池拆分、排障链路、升级清单落到自己的环境里,比什么都强。这套东西不敢说让你从此零事故,但至少能让事故来了的时候,你手里有家伙、心里有底。