Kubernetes生产环境避坑指南:3年运维踩过的50个坑
总结在生产环境运行Kubernetes三年来的实战经验,涵盖Pod驱逐、OOMKilled排查、CNI网络故障、etcd性能优化、RBAC权限管理、HPA自动扩缩容陷阱等高频问题及其解决方案。
SteveRocket
北京,中国
2 min read
前言
Kubernetes 已经成为云原生时代的”操作系统”,但把 K8s 跑在生产环境和在 Minikube 上跑个 Demo 完全是两回事。这篇文章整理了我们在生产环境运维 K8s 集群三年多以来踩过的坑和对应的解决方案。
一、Pod 调度与生命周期
坑 1:Pod 频繁被驱逐(Evicted)
现象:Pod 状态变成 Evicted,服务不可用。
根因:节点资源(磁盘/内存)不足触发了 Kubelet 的驱逐机制。
# ❌ 没有设置 resource limit,容易触发驱逐
apiVersion: v1
kind: Pod
spec:
containers:
- name: app
image: myapp:v1
# 缺少 resources 配置!
# ✅ 正确配置
apiVersion: v1
kind: Pod
spec:
containers:
- name: app
image: myapp:v1
resources:
requests:
memory: "256Mi"
cpu: "100m"
limits:
memory: "512Mi" # limit 不要设太大,防止 OOM
cpu: "500m"
关键经验:
requests和limits必须设置,缺一不可limits.memory不要超过节点内存的 50%- 配置
podAntiAffinity避免同一个服务的 Pod 全挤在一台机器上 - 设置
priorityClassName保护核心服务不被驱逐
坑 2:OOMKilled 但日志里什么都看不到
现象:Pod 突然重启,状态显示 OOMKilled,但应用日志里没有任何异常。
根因:JVM / Node.js 的堆外内存没有被 limits 覆盖到。
# Java 应用的 JVM 参数必须和 K8s limits 对齐
env:
- name: JAVA_OPTS
value: "-Xms256m -Xmx384m -XX:MaxDirectMemorySize=64m"
# Xmx + MaxDirectMemorySize + Metaspace < limits.memory
排查方法:
# 查看 Pod 上次退出的原因
kubectl describe pod <pod-name> | grep -A5 "Last State"
# 查看节点级别的 OOM 事件
kubectl get events --field-selector reason=OOMKilling
# 使用 metrics-server 查看实际内存使用
kubectl top pod <pod-name> --containers
坑 3:Readiness Probe 配错导致流量打到未就绪的 Pod
# ❌ 探针路径返回 200 不代表应用真正就绪
readinessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 5
periodSeconds: 10
# ✅ 应该检查应用核心依赖(数据库连接、缓存连接等)
readinessProbe:
httpGet:
path: /health/ready # 这个端点检查 DB + Redis + MQ 连接
port: 8080
initialDelaySeconds: 30 # 给应用足够的启动时间
periodSeconds: 10
failureThreshold: 3 # 连续失败3次才标记为未就绪
successThreshold: 1
二、网络(CNI)问题
坑 4:Pod 间网络不通,时好时坏
现象:A Pod 访问 B Pod 的 Service 偶尔超时。
排查链路:
# 1. 检查 Service 的 Endpoints 是否正确
kubectl get endpoints <service-name>
# 2. 检查 kube-proxy 是否正常运行
kubectl -n kube-system get pods -l k8s-app=kube-proxy
# 3. 从另一个 Pod 测试连通性
kubectl run test-pod --rm -it --image=busybox -- sh
wget -O- http://<service-name>:<port>/health
# 4. 检查 iptables 规则(最常见的坑)
iptables -t nat -L KUBE-SERVICES -n | grep <service-name>
常见原因:
conntrack表满了:sysctl net.netfilter.nf_conntrack_max- DNS 解析延迟:
ndots:5导致多余的 DNS 查询 - CNI 插件版本不兼容
坑 5:DNS 解析慢导致服务超时
# 在 Pod spec 中配置 DNS 策略
spec:
dnsConfig:
options:
- name: ndots
value: "2" # 减少不必要的域名补全尝试
- name: single-request-reopen
dnsPolicy: ClusterFirst
三、存储
坑 6:PVC 挂载不上,Pod 一直 Pending
排查:
# 1. 检查 PV 状态
kubectl get pv
# 2. 检查 PVC 绑定状态
kubectl describe pvc <pvc-name>
# 3. 检查 CSI Driver Pod 是否正常
kubectl -n kube-system get pods | grep csi
# 4. 检查节点是否有卷的挂载限制(AWS EBS 单节点最多挂 39 个卷)
kubectl describe node <node-name> | grep -A5 "Allocated resources"
四、etcd 性能
坑 7:etcd 磁盘 IO 飙升导致集群响应变慢
# etcd 性能自查
# 1. 检查 etcd 磁盘是否有延迟
etcdctl endpoint health --cluster
# 2. 检查 etcd 数据库大小(超过 2GB 会触发告警)
etcdctl endpoint status --cluster -w table | grep DB SIZE
# 3. 碎片整理
etcdctl defrag --cluster
# 4. 查看哪些 key 占用最多空间
etcdctl get / --prefix --keys-only | wc -l
优化建议:
- etcd 必须使用 SSD,不能放在共享存储上
- 定期执行
defrag(建议每周一次) - 设置
--auto-compaction-retention=1自动压缩历史版本 --quota-backend-bytes=8589934592(8GB)限制数据库大小
五、HPA 自动扩缩容
坑 8:HPA 频繁扩缩导致”抖动”
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
spec:
behavior:
scaleDown:
stabilizationWindowSeconds: 300 # 缩容前等待5分钟
policies:
- type: Percent
value: 10 # 每次最多缩 10%
periodSeconds: 60
scaleUp:
stabilizationWindowSeconds: 0 # 扩容不等待
policies:
- type: Percent
value: 100 # 每次最多扩 100%
periodSeconds: 15
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70 # 不要设太低,60-80 是合理范围
六、安全
坑 9:RBAC 权限过大导致安全隐患
# 审计谁有什么权限
kubectl auth can-i --list --as=system:serviceaccount:default:my-sa
# 检查是否有 ClusterAdmin 权限的 ServiceAccount
kubectl get clusterrolebindings -o json | \
jq '.items[] | select(.subjects[]?.kind=="ServiceAccount") | .metadata.name'
原则:
- 永远不要给 default ServiceAccount 绑 ClusterRole
- 每个微服务使用独立的 ServiceAccount
- 定期审计 RBAC 权限
七、升级与维护
坑 10:K8s 版本升级后 Pod 启动失败
升级前必须检查:
# 1. 检查即将被废弃的 API 版本
kubectl get --raw /metrics | grep apiserver_requested_deprecated_apis
# 2. 使用 pluto 检查集群中的废弃 API 使用情况
pluto detect-helm -o wide
# 3. 确认所有 CRD 与新版本兼容
kubectl get crd -o yaml | grep -A2 "apiVersion"
监控检查清单
生产环境 K8s 集群每天必看的指标:
| 指标 | 健康范围 | 告警阈值 |
|---|---|---|
| 节点 CPU 使用率 | < 70% | > 85% |
| 节点内存使用率 | < 75% | > 90% |
| Pod 重启次数 | 0 | > 3/天 |
| etcd 磁盘使用 | < 60% | > 80% |
| etcd DB Size | < 4GB | > 6GB |
| API Server 延迟 P99 | < 1s | > 3s |
| 集群事件中 Warning | < 10/小时 | > 50/小时 |
总结
K8s 运维的核心不是会敲 kubectl,而是理解它每一层的工作原理:
- 资源管理是基础:request/limit 配不好,后面全是坑
- 网络是最大的变量:CNI 选型、DNS 配置、Service Mesh 引入都要慎重
- 存储要提前规划:CSI Driver 兼容性、备份策略、跨 AZ 可用性
- 安全不能后补:RBAC、Network Policy、Pod Security 从一开始就规划好
- 升级要谨慎:先在测试集群验证,再看生产
记住一句话:Kubernetes is a platform for building platforms, not an end-user product.