2023 年我们公司从 docker-compose 迁移到 Kubernetes 全栈上云 30 多个微服务 拆 50+ deployment。第一个月顺风顺水 第二个月开始事故连连 平均每周 1.5 次 P1 故障 凌晨被告警叫醒 5 次。然后我们陆续踩了一堆坑。第一种最让我傻眼 一次大版本发布 deployment apply 之后 pod 一直 ImagePullBackOff 我们以为镜像没推上去 重推 5 次都不行 一个小时后才发现 是 imagePullSecrets 没配 私有 registry 拉不到 但 Events 信息只有几个字根本没说清原因 全靠经验。第二种最难缠 一个核心服务突然 CPU 跑满 pod 自动扩到 30 个还顶不住 业务延迟飙到 5 秒 我们 kubectl exec 进去 top 一看是 GC pause 内存设了 1Gi 业务跑到 800Mi 就开始疯狂 GC 没设 JVM 参数对齐 K8s memory limit 这是 JVM 在 K8s 的著名坑。第三种最离谱 一次升级 deployment image tag 因为没设 imagePullPolicy 老 pod 还在跑老镜像 新 pod 拉新镜像 但有几个 node 用了缓存的 latest tag 实际跑的是 3 周前的版本 业务行为不一致排查 6 小时。第四种最致命 一次扩容 node 加完之后 pod 一直 Pending node 资源足够但调度不上 后来发现是 taint/toleration 没配 新 node 默认带 taint 但 pod 没声明 toleration 直接被拒绝调度 我们对 taint 机制完全没概念。第五种最莫名其妙 服务之间 service A 调 service B 突然大量 500 错误 kubectl get pods 看 B 全部 Running 但 endpoints 看 B 的 endpoint 列表是空的 后来发现是 readinessProbe 配错路径 K8s 认为 pod 没 ready 不挂 endpoint 但 pod 自己 Running 着我们以为没问题。我盯着这一连串问题想了很久才彻底想明白第一版错在一个根本的认知上我以为 K8s 就是把 docker-compose 改成 yaml 跑通就行 可这个认知是错的真正能扛业务的 Kubernetes 是一个 资源配置 加 健康检查 加 滚动发布策略 加 调度与污点 加 网络与服务发现 加 故障排查方法论 的整套工程方法论 任何一环没做都可能让你的集群在凌晨 3 点把你叫起来本文从头梳理 K8s 工程化的要点 资源 limits 怎么设 probes 怎么配 滚动发布怎么稳 调度怎么控 网络怎么排 故障怎么诊断 以及一些把 K8s 用扎实要避开的工程坑
问题背景:为什么 K8s 不是 docker-compose plus
很多团队从 docker-compose 迁过来的第一反应是把 yaml 翻译一下就行 但 K8s 复杂度比 docker-compose 高 10 倍 多了调度 多了网络 多了健康检查 多了滚动发布 每一项都有自己的坑:
- 资源 requests/limits:不设 K8s 默认无限 pod 会饿死 node 设错业务卡死 OOMKilled。
- liveness/readiness/startup:三种 probe 用途不同 配错会反复重启或挂掉流量。
- imagePullPolicy 与 image tag:Always vs IfNotPresent 影响发布行为 latest tag 是定时炸弹。
- 调度策略:nodeSelector affinity taint/toleration topologySpreadConstraints 各有适用。
- 滚动发布策略:maxSurge/maxUnavailable 控制速度与可用性 PDB 防驱逐打挂。
- 网络与服务发现:ClusterIP NodePort LoadBalancer Ingress 各有适用 service 与 endpoints 关系。
一 资源配置:requests 与 limits 的艺术
资源配置是 K8s 工程化的第一关 90% 的生产事故根源在 requests/limits 没设或者设错。下面是经过踩坑总结的资源配置原则与代码示例。
# 1 标准资源配置
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-api
spec:
replicas: 3
template:
spec:
containers:
- name: api
image: registry.example.com/web-api:v1.2.3
resources:
requests: # 调度时保证可用 实际占用基准
cpu: 500m # 0.5 核
memory: 512Mi
limits: # 上限 超过会被限流(CPU) 或 OOMKilled(memory)
cpu: 1000m # 1 核
memory: 1Gi
# 重要 JVM 应用必须设 这两个参数
env:
- name: JAVA_OPTS
value: "-XX:+UseContainerSupport -XX:MaxRAMPercentage=75.0"
# K8s 1.10+ 默认 UseContainerSupport=true 但 percentage 要手动
# 2 资源配置原则
# - requests < limits 留 buffer 防瞬间高峰
# - CPU 一般 limit / request = 2x
# - memory 一般 limit / request = 1.5x 不能太大 OOM 后果严重
# - memory limit 永远不要设太低 OOMKilled 会丢请求
# 3 QoS 等级 决定优先级
# Guaranteed: requests == limits 所有资源都设 不会被驱逐
# Burstable: requests < limits 节点压力大可能被驱逐
# BestEffort: 都不设 最先被驱逐
# 核心服务用 Guaranteed 边缘服务用 Burstable
单 pod 资源配置是基础 但生产集群必须从 namespace 维度做兜底 否则一个开发误把 limits 写成 100Gi memory 就能把整个集群干爆。LimitRange 设默认值 ResourceQuota 设上限 这两个是集群管理员必备工具。
# 4 LimitRange 默认值 防止开发忘设
apiVersion: v1
kind: LimitRange
metadata:
name: default-limits
namespace: production
spec:
limits:
- default:
cpu: 500m
memory: 512Mi
defaultRequest:
cpu: 100m
memory: 128Mi
type: Container
# 5 ResourceQuota 防止单 namespace 吃光集群
apiVersion: v1
kind: ResourceQuota
metadata:
name: prod-quota
spec:
hard:
requests.cpu: "100"
requests.memory: 100Gi
limits.cpu: "200"
limits.memory: 200Gi
pods: "100"
实战经验:核心服务必须 Guaranteed QoS 等级 否则节点资源紧张时会被驱逐;JVM 应用必须设 UseContainerSupport + MaxRAMPercentage 否则 JVM 看不到 cgroup 限制会 OOM;每个 namespace 必设 ResourceQuota 否则一个开发误操作可以把集群干爆。
二 健康检查:三种 probe 各司其职
K8s 三种探针 livenessProbe readinessProbe startupProbe 配错了轻则反复重启 重则流量打到没准备好的 pod 这是新人最容易踩错的地方。下面是每种探针的正确用法。
# 1 三种探针 完整配置
spec:
containers:
- name: app
image: myapp:v1
ports:
- containerPort: 8080
# startupProbe 启动慢应用必备 PG 11+
# 启动期间不跑 liveness 防止刚启动还没起来就被杀
startupProbe:
httpGet:
path: /health/startup
port: 8080
failureThreshold: 30 # 30 * 10s = 5 分钟启动超时
periodSeconds: 10
# livenessProbe 检测进程死锁 触发重启
livenessProbe:
httpGet:
path: /health/liveness
port: 8080
initialDelaySeconds: 0 # startupProbe 处理初始延迟
periodSeconds: 30 # 30s 一次足够 别太频繁
timeoutSeconds: 5
failureThreshold: 3 # 3 次失败重启
successThreshold: 1
# readinessProbe 检测是否可接流量 失败摘除 endpoint
readinessProbe:
httpGet:
path: /health/readiness
port: 8080
initialDelaySeconds: 0
periodSeconds: 10
timeoutSeconds: 3
failureThreshold: 3
successThreshold: 1
# 2 三种探针的语义区分
# livenessProbe 失败 -> 重启容器(deadlock 检测)
# readinessProbe 失败 -> 摘 endpoint(流量保护 不重启)
# startupProbe 失败 -> 重启容器(只在启动期间)
# 3 探针 endpoint 实现建议
# /health/liveness 只检查"我活着" 不查依赖
# 返回 200 即可 不要查 DB Redis
# /health/readiness 检查"我能服务" 查关键依赖
# 连不上 DB 返回 503 摘流量但不重启
# /health/startup 检查"我启动完了" 加载模型 warm cache 完毕
# 4 常见错误配置
# 错: liveness 检查依赖 DB 挂了导致整个集群重启循环
# liveness:
# exec:
# command: ["pg_isready -h db"] # 千万别这样
# 错: 没有 startupProbe 但 liveness initialDelay 设很长
# 导致整个启动期间 liveness 不检查 真死锁了也发现不了
# 5 TCP/exec 探针
# HTTP 不够时用 TCP
readinessProbe:
tcpSocket:
port: 6379
# 自定义脚本检查
livenessProbe:
exec:
command:
- /bin/sh
- -c
- "ps aux | grep -v grep | grep myprocess"
实战经验:三种探针必须搭配用 startupProbe 处理启动期 liveness 防死锁 readiness 流量保护;探针 endpoint 实现要精心设计 liveness 不查依赖 readiness 查关键依赖;exec 探针很慢且不稳定 优先 HTTP。我们曾经踩过 liveness 查 DB 的坑 数据库主从切换 5 秒 整个集群所有服务一起被 liveness 重启 雪崩 30 分钟。
三 滚动发布与版本管理
K8s 默认 RollingUpdate 看起来很美好 但默认参数对大流量服务并不安全。下面是滚动发布的关键参数与 PDB 配合。
# 1 RollingUpdate 完整配置
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-api
spec:
replicas: 10
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 25% # 滚动期间最多多 25%(10 pod 多 3 个 共 13)
maxUnavailable: 0 # 不允许任何不可用 推荐!
minReadySeconds: 30 # 新 pod ready 后等 30s 再继续 防瞬间问题
progressDeadlineSeconds: 600 # 10 分钟没完成认为失败
template:
spec:
containers:
- name: api
image: web-api:v1.2.3
# 关键 imagePullPolicy
imagePullPolicy: IfNotPresent # tag 是固定版本号时
# imagePullPolicy: Always # 用 latest 或 mutable tag 时
# 2 PodDisruptionBudget 防止 voluntary disruption 打挂业务
# 比如 node drain rolling update 等情况下确保最少可用 pod
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: web-api-pdb
spec:
minAvailable: 7 # 任何时候至少 7 个 pod 可用
# 或 maxUnavailable: 30%
selector:
matchLabels:
app: web-api
# 3 imagePullPolicy 与 tag 策略
# - 用语义化版本 tag (v1.2.3) + IfNotPresent 推荐
# - 用 latest 或 dev tag + Always 不推荐生产
# - 用 SHA digest (myapp@sha256:abc...) 最严格
RollingUpdate 是默认发布策略 配合 PDB 已经能应付 90% 的场景。但对核心业务我们需要更精细的发布控制 蓝绿允许快速回滚 金丝雀允许小流量验证 这两种是高可用业务必备。
# 4 蓝绿发布 用 Service selector 切换
# 部署两套 deployment 通过 service 切流
apiVersion: v1
kind: Service
metadata:
name: web-api
spec:
selector:
app: web-api
version: green # 切换 version 标签实现蓝绿
ports:
- port: 80
# 5 金丝雀发布 Istio / Argo Rollouts
# 用 Argo Rollouts 声明金丝雀步骤
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
name: web-api
spec:
strategy:
canary:
steps:
- setWeight: 10 # 先放 10%
- pause: {duration: 10m} # 观察 10 分钟
- setWeight: 30
- pause: {duration: 10m}
- setWeight: 50
- pause: {duration: 10m}
- setWeight: 100
实战经验:maxUnavailable: 0 是核心服务标配 不允许发布期间有可用性下降;minReadySeconds 30 给应用 stabilization 时间 防止刚 ready 就崩;PDB 必配 否则 cluster autoscaler drain node 时可能一次性挂太多 pod;latest tag 绝对不要在生产用 必用语义化版本。
四 调度与亲和性:让 pod 落到该落的地方
默认调度器把 pod 随便放 大部分时候够用 但生产场景需要精细控制 GPU 节点只跑 AI 服务 高 IO 节点跑数据库 不能让两个核心 pod 在同一 node 等等。下面是调度的核心机制。
# 1 nodeSelector 简单标签匹配
spec:
template:
spec:
nodeSelector:
node-type: gpu # 只调度到打 node-type=gpu 标签的节点
# 或更细致的 affinity
# 2 nodeAffinity 灵活节点亲和
spec:
template:
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: node-type
operator: In
values: ["gpu", "high-memory"]
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
preference:
matchExpressions:
- key: zone
operator: In
values: ["us-east-1a"]
# 3 podAntiAffinity 同一 deployment pod 不要在同 node
# 防止 node 挂导致服务全挂
spec:
template:
spec:
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchLabels:
app: web-api
topologyKey: kubernetes.io/hostname # 不同 node
# 4 taint 与 toleration node 准入控制
# 给 GPU node 打 taint 阻止普通 pod 调度
# kubectl taint nodes gpu-node-1 dedicated=gpu:NoSchedule
# AI pod 声明 toleration 才能调度上去
spec:
template:
spec:
tolerations:
- key: dedicated
operator: Equal
value: gpu
effect: NoSchedule
# 5 topologySpreadConstraints 跨 zone 均匀分布
spec:
template:
spec:
topologySpreadConstraints:
- maxSkew: 1
topologyKey: topology.kubernetes.io/zone
whenUnsatisfiable: ScheduleAnyway
labelSelector:
matchLabels:
app: web-api
# 保证 pod 在 3 个 zone 之间均匀分布
# 6 priorityClassName 抢占优先级
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
name: high-priority
value: 1000000 # 优先级
globalDefault: false
description: "核心业务"
---
spec:
template:
spec:
priorityClassName: high-priority
# 资源不足时优先调度 必要时驱逐低优 pod
实战经验:核心服务必加 podAntiAffinity 一个 deployment 的 pod 不能都在同一 node;多 zone 集群必加 topologySpreadConstraints 防整个 zone 挂的灾难;GPU/高性能 node 用 taint 防止普通 pod 占用;priorityClassName 给核心服务高优先级 资源不足时优先保。
[mermaid]
flowchart TD
A[业务故障告警] --> B[kubectl get pods]
B --> C{Pod 状态}
C -->|Pending| D[kubectl describe 看 Events]
D --> E{Pending 原因}
E -->|资源不足| F[扩 node 或调资源]
E -->|节点亲和不满足| G[检查 selector 与 taint]
E -->|PVC 未绑定| H[检查存储类]
C -->|ImagePullBackOff| I[检查 secret 与镜像]
C -->|CrashLoopBackOff| J[kubectl logs --previous]
J --> K[查启动失败原因]
C -->|Running 但不通| L[kubectl get endpoints]
L -->|空| M[检查 readinessProbe]
L -->|有| N[kubectl exec 内部测试]
N --> O[netshoot 容器抓包]
五 网络与服务发现:从 ClusterIP 到 Ingress
K8s 网络是最复杂的部分 service 与 endpoints 关系 ClusterIP 路由 Ingress 控制器 这些不搞清楚出问题排查半天。下面是网络的核心机制。
# 1 Service 四种类型
# ClusterIP 集群内访问(默认)
apiVersion: v1
kind: Service
metadata:
name: web-api
spec:
type: ClusterIP
selector:
app: web-api
ports:
- port: 80 # service 端口
targetPort: 8080 # pod 端口
protocol: TCP
# NodePort 通过节点 IP 访问
spec:
type: NodePort
ports:
- port: 80
targetPort: 8080
nodePort: 30080 # 30000-32767 范围
# LoadBalancer 云厂商负载均衡器
spec:
type: LoadBalancer # 云上自动建 LB(ALB SLB CLB)
# ExternalName 别名(DNS CNAME)
spec:
type: ExternalName
externalName: my-db.example.com
# 2 Headless Service 不分配 ClusterIP
# DNS 直接返回所有 pod IP 用于有状态服务
spec:
clusterIP: None
selector:
app: postgres
# 3 Ingress HTTP/HTTPS 7 层路由
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: web-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
cert-manager.io/cluster-issuer: letsencrypt
spec:
ingressClassName: nginx
tls:
- hosts: ["api.example.com"]
secretName: api-tls
rules:
- host: api.example.com
http:
paths:
- path: /v1
pathType: Prefix
backend:
service:
name: web-api-v1
port:
number: 80
- path: /v2
pathType: Prefix
backend:
service:
name: web-api-v2
port:
number: 80
# 4 NetworkPolicy 微隔离
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: db-policy
spec:
podSelector:
matchLabels:
app: postgres
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
tier: backend # 只允许 backend pod 访问 DB
ports:
- port: 5432
# 5 排查 endpoints 关键命令
# kubectl get endpoints web-api -o yaml
# 如果 endpoints 为空 说明 pod 没 ready 或 selector 不匹配
# kubectl get pods -l app=web-api -o wide
# 看 pod 是否 READY 1/1 是否符合 selector
实战经验:Service endpoints 为空是最常见网络问题 90% 是 readinessProbe 失败或者 selector 不匹配 kubectl get endpoints 一秒定位;Ingress 必加 TLS 与 cert-manager 自动续签;生产必加 NetworkPolicy 实现微隔离 默认 K8s 网络是平铺的所有 pod 互通存在安全风险。
六 故障排查方法论:从告警到根因
K8s 故障排查不能靠运气 必须有系统方法。下面是经过血泪教训总结的故障排查 SOP。
# 1 第一现场 5 个命令秒看全貌
kubectl get pods -A | grep -v Running # 找不正常 pod
kubectl get nodes # 看节点状态
kubectl top pods -A --sort-by=memory # 看资源消耗
kubectl get events -A --sort-by='.lastTimestamp' | tail -50 # 最近事件
kubectl get pdb -A # 看 PDB 状态
# 2 单 pod 排查 4 件套
kubectl describe pod <pod> -n <ns> # 看事件 + 状态
kubectl logs <pod> -n <ns> --previous # 看上一次崩溃日志
kubectl exec -it <pod> -n <ns> -- /bin/sh # 进容器排查
kubectl get pod <pod> -n <ns> -o yaml # 看完整定义
# 3 网络问题排查 netshoot 神器
# 临时启个调试容器
kubectl run netshoot --rm -it --image nicolaka/netshoot -- /bin/bash
# 然后:
# - ping <service>
# - nslookup <service>
# - curl -v http://service:port
# - tcpdump -i any port 8080
# 4 节点问题排查
kubectl describe node <node> # 看 Conditions Allocatable Events
kubectl get pods --field-selector spec.nodeName=<node> -A
# SSH 到节点(如果允许)
journalctl -u kubelet -f # kubelet 日志
crictl ps # 容器运行时
df -h # 磁盘 / inode
free -h # 内存
# 5 资源问题排查
# 找 OOMKilled
kubectl get events -A --field-selector reason=OOMKilling
# 找 Evicted
kubectl get pods -A | grep Evicted
# 找资源紧张
kubectl describe node | grep -A 5 "Allocated resources"
# 6 性能问题排查
# 用 ephemeral container 进运行中 pod 不重启
kubectl debug -it <pod> --image=busybox --target=<container>
# 或用 kubectl-trace 跑 bpftrace
# 或用 pprof for Go 应用
kubectl port-forward <pod> 6060:6060
go tool pprof http://localhost:6060/debug/pprof/profile
# 7 常用 alias 提升排查速度
alias k=kubectl
alias kgp='kubectl get pods'
alias kgs='kubectl get svc'
alias kge='kubectl get events --sort-by=.lastTimestamp'
alias kdp='kubectl describe pod'
alias klogs='kubectl logs --tail=100 -f'
实战经验:排查必须有 SOP 不能瞎 kubectl get;netshoot 是网络排查神器 一定要装在集群里;kubectl debug 是 1.23+ 排查神器 ephemeral container 不影响业务;告警 + dashboard + 日志 + tracing 四位一体 单靠 kubectl 排查现代生产 K8s 太慢。
关键概念速查
| 概念 | 说明 | 推荐 | 备注 |
|---|---|---|---|
| QoS 等级 | 资源保障级别 | 核心 Guaranteed | req==limit |
| livenessProbe | 死锁检测 | 不查依赖 | 失败重启 |
| readinessProbe | 流量保护 | 查关键依赖 | 失败摘 endpoint |
| startupProbe | 启动期保护 | 慢启动应用必加 | K8s 1.16+ |
| maxUnavailable | 滚动发布 | 核心服务 0 | 不允许中断 |
| PDB | 驱逐保护 | 必加 | node drain 安全 |
| podAntiAffinity | pod 互斥 | 必加 | 防 node 挂全挂 |
| topologySpread | 跨 zone 均匀 | 多 zone 必加 | 区域容灾 |
| NetworkPolicy | 微隔离 | 必加 | 默认全通 |
| kubectl debug | 调试容器 | 1.23+ | 不影响业务 |
避坑清单
- 不要不设 resources requests/limits 默认无限会饿死 node 也无法被正确调度。
- 不要 JVM 应用不设 UseContainerSupport + MaxRAMPercentage JVM 看不到 cgroup 限制必 OOM。
- 不要 liveness 探针查依赖 DB 挂了所有服务一起重启雪崩。
- 不要慢启动应用不加 startupProbe liveness initialDelay 设很长也不行。
- 不要生产用 latest tag 必用语义化版本 + IfNotPresent 防止意外滚动。
- 不要 maxUnavailable 设默认 25% 核心服务必须 0 不允许任何中断。
- 不要不加 PDB node drain 时可能一次挂太多 pod 业务直接挂。
- 不要核心服务不加 podAntiAffinity 一个 node 挂整个服务全挂。
- 不要不设 NetworkPolicy 默认 K8s 网络平铺所有 pod 互通存在严重安全风险。
- 不要瞎 kubectl get 排查 必有 SOP 4 件套 describe + logs + exec + yaml。
总结
把 Kubernetes 这套从我们踩过的所有坑里反过来看 你会发现真正影响业务稳定性的不是 K8s 本身 而是工程化的全栈能力。同样一个集群 不设 resources 不配 probes 不加 PDB 一周 P1 故障 5 次凌晨被告警叫醒 全套配置到位后一个月零故障 团队睡得安稳;同样一个 deployment latest tag 加默认 maxUnavailable 25% 一次升级整组服务断 2 分钟客户骂街 用语义化 tag + maxUnavailable 0 + minReadySeconds 30 滚动发布无感知。K8s 不是 docker-compose 改改 yaml 跑通就完事的玩具 它是一个 资源配置 + 健康检查 + 滚动发布 + 调度策略 + 网络与服务发现 + 故障排查 的完整系统工程。
另一个常见的认知误区是把 K8s 当成黑盒 觉得 deployment 一 apply 就万事大吉 出问题就 kubectl get pods 看看。但事实是 K8s 是一个高度声明式的系统 你的每一个配置都是合约 配错就会有相应的代价 没设 limits 就会被驱逐 没设 probe 就会有流量打到死 pod 没设 PDB 就会被 drain 打挂。投产能力的差距不在于 K8s 知识 在于工程方法论 在于把每个细节都设对设全。
打个比方 K8s 像一个高度自动化的物业管理公司。Deployment 是租客合同(声明你要住几间房什么标准) Service 是门牌号(让人能找到你) Ingress 是楼下的门禁(管外部访问) probes 是定期上门检查(确认住户还活着且能开门) resources 是水电额度(超额自动断) PDB 是搬家保护(不能一次搬走太多人) podAntiAffinity 是分散居住(不能把同公司员工都安排到一栋楼) NetworkPolicy 是楼栋通行规则(谁能去哪栋) RollingUpdate 是逐步换租客(不能整楼搬空) imagePullPolicy 是搬家方式(每次重新拉行李 还是用既有的)。哪一项没设好 物业都不能正常运转 业主投诉接连不断。
所以下一次再有人跟你说 K8s 就是把 docker-compose 改成 yaml 你可以反问他 resources 设了吗 三种 probe 都对吗 PDB 加了吗 podAntiAffinity 有吗 maxUnavailable 调了吗 NetworkPolicy 配了吗 监控告警全吗 这些工作没做完 K8s 只是一个能跑通 demo 的玩具 不是一个能扛业务的容器编排平台。从踩坑到投产 中间隔着一整套工程方法论 这条路没有捷径 但走完之后 你的集群会从凌晨告警频繁变成稳如老狗 从一周 P1 五次变成一年 P1 零次。
—— 别看了 · 2026