说实话,我刚入行做K8s运维的时候,也犯过不少低级错误。有一次生产环境直接崩了,整个集群的服务都挂掉了,那时候真是急得团团转。今天就来聊聊我在实战中踩过的坑,特别是单点故障和配置错误这两类最要命的问题,以及怎么避坑。
单点故障的那些坑
单点故障(SPOF)听起来很简单,就是某个组件一旦挂了,整个系统就瘫痪了。但在K8s里,这个坑可不浅。
etcd集群的单点陷阱
etcd是K8s的核心存储,所有配置、状态都保存在里面。很多人以为部署一个etcd就完事了,结果集群一崩,数据全没了。
正确做法:
- 部署奇数个etcd节点(3个或5个),保证多数派机制
- 分散在不同的物理机或可用区
- 定期备份etcd数据
- 使用
etcdctl snapshot save命令定期备份
# 备份etcd快照
ETCDCTL_API=3 etcdctl snapshot save \
--cacert=/etc/kubernetes/pki/etcd/ca.crt \
--cert=/etc/kubernetes/pki/etcd/server.crt \
--key=/etc/kubernetes/pki/etcd/server.key \
--endpoints=https://127.0.0.1:2379 \
/opt/backup/etcd-snapshot-$(date +%Y%m%d).db
# 恢复etcd快照
ETCDCTL_API=3 etcdctl snapshot restore \
--data-dir=/var/lib/etcd-from-snapshot \
/opt/backup/etcd-snapshot-20231015.db
控制平面的单点问题
很多新手部署K8s时,只装了一个master节点。结果master一宕机,整个集群就瘫痪了。
避坑指南:
- 至少部署3个master节点
- 每个master节点部署在不同的物理机
- 使用Keepalived或云厂商的负载均衡器
- 配置apiserver的高可用
# haproxy配置示例,实现apiserver负载均衡
global
log /dev/log local0
maxconn 4096
defaults
log global
mode http
option httplog
timeout connect 5000ms
timeout client 50000ms
timeout server 50000ms
frontend kubernetes-apiserver
bind *:6443
mode tcp
default_backend kubernetes-apiserver
backend kubernetes-apiserver
mode tcp
balance roundrobin
server apiserver1 192.168.1.10:6443 check
server apiserver2 192.168.1.11:6443 check
server apiserver3 192.168.1.12:6443 check
网络插件的单点故障
Calico、Flannel这些网络插件,如果部署不当,也会成为单点。
实践建议:
- 每个节点都部署网络插件的DaemonSet
- 配置网络插件的高可用
- 定期测试网络连通性
- 监控网络插件的日志
# Calico DaemonSet示例
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: calico-node
namespace: calico-system
spec:
selector:
matchLabels:
name: calico-node
template:
metadata:
labels:
name: calico-node
spec:
hostNetwork: true
tolerations:
- operator: Exists
effect: NoSchedule
containers:
- name: calico-node
image: calico/node:v3.24.0
env:
- name: DATASTORE_TYPE
value: "kubernetes"
配置错误的经典案例
配置错误是K8s里最常见的坑,有时候一个小错误就能让整个集群瘫痪。
资源限制配置不当
很多开发者不喜欢给Pod设置资源限制,觉得会影响性能。结果一个应用突然占用大量CPU,把整个节点都拖垮了。
正确姿势:
- 设置requests和limits
- 根据实际使用情况调整
- 使用QoS策略保证关键服务
apiVersion: v1
kind: Pod
metadata:
name: web-app
spec:
containers:
- name: web
image: nginx
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
镜像拉取策略问题
imagePullPolicy配置错误,会导致容器无法启动或重复拉取镜像。
常见错误配置:
# 错误示例:总是拉取最新镜像,影响性能
imagePullPolicy: Always
# 正确做法:根据镜像标签决定
# 使用latest标签时:Always
# 使用具体版本时:IfNotPresent
健康检查配置错误
探针配置不当,会导致Pod被错误地杀死或重启。
# 错误的健康检查配置
livenessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 1 # 太短,容器还没启动就被检测
periodSeconds: 5
failureThreshold: 1 # 一次失败就杀容器
# 正确配置
livenessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 30 # 给容器足够启动时间
periodSeconds: 10
failureThreshold: 3 # 连续3次失败才杀容器
timeoutSeconds: 5
successThreshold: 1
Service配置陷阱
Service配置错误会导致流量无法正确路由。
# 常见错误:selector配置错误
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
selector:
app: my-app # 这个标签和Pod的标签不匹配
ports:
- port: 80
targetPort: 8080
# 正确做法:确保selector和Pod的labels匹配
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
selector:
app: my-app # 和Pod的labels完全一致
ports:
- port: 80
targetPort: 8080
集群规模设计的坑
节点数量规划不当
有的公司为了省成本,只部署少量节点。结果业务一增长,集群直接撑不住。
规划建议:
- 根据业务增长趋势预估
- 预留20%-30%的冗余
- 分阶段扩容,不要一次性扩太多
- 使用自动扩缩容(HPA/VPA)
# HPA自动扩缩容配置
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: web-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: web-app
minReplicas: 3
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
集群版本升级策略
很多团队不敢升级K8s版本,结果长期停留在旧版本,安全漏洞越来越多。
升级策略:
- 制定详细的升级计划
- 先在测试环境验证
- 使用kubeadm升级工具
- 备份所有数据
- 制定回滚方案
# 使用kubeadm升级控制平面
# 1. 升级kubectl
sudo apt-get update && sudo apt-get install -y kubectl
# 2. 查看可用的升级版本
sudo kubeadm upgrade plan
# 3. 升级控制平面
sudo kubeadm upgrade apply v1.27.0
# 4. 升级kubelet和kubeadm
sudo apt-get update && sudo apt-get install -y kubelet kubeadm
sudo systemctl restart kubelet
监控和告警的缺失
没有监控的K8s集群就像盲人摸象,出了问题的第一时间完全不知道。
必须的监控组件
- Prometheus:指标监控
- Grafana:可视化展示
- Alertmanager:告警管理
- EFK/ELK:日志收集
- Metrics Server:资源使用监控
# Prometheus监控配置示例
apiVersion: monitoring.coreos.com/v1
kind: Prometheus
metadata:
name: k8s-prometheus
namespace: monitoring
spec:
replicas: 2 # 高可用
version: v2.42.0
alerting:
alertmanagers:
- staticConfigs:
- targets: ['alertmanager:9093']
ruleSelector:
matchLabels:
role: alert-rules
resources:
requests:
memory: 400Mi
cpu: 200m
limits:
memory: 2Gi
cpu: "1"
关键告警指标
一定要配置这些告警:
- 节点不可用(NodeNotReady)
- Pod频繁重启(CrashLoopBackOff)
- 资源使用率过高(CPU/Memory > 80%)
- 磁盘空间不足
- etcd延迟升高
- API Server错误率
实战避坑清单
根据我的经验,以下清单一定要定期检查:
架构层面
- [ ] etcd集群节点数为奇数(3或5个)
- [ ] 控制平面至少3个master节点
- [ ] 网络插件部署在每节点
- [ ] 关键服务部署多个副本
- [ ] 配置Pod反亲和性,分散到不同节点
配置层面
- [ ] 所有容器都配置了资源限制
- [ ] 健康检查配置合理
- [ ] Service的selector正确匹配
- [ ] 镜像拉取策略配置正确
- [ ] 持久化存储配置了合适的ReclaimPolicy
运维层面
- [ ] 定期备份etcd数据
- [ ] 配置Prometheus监控
- [ ] 配置关键告警
- [ ] 定期升级K8s版本
- [ ] 制定并测试回滚方案
总结
K8s的学习曲线确实有点陡,但踩过的坑都是宝贵的经验。记住几个核心原则:
- 不要追求极简:生产环境一定要高可用部署
- 配置要严谨:每一个参数都要验证
- 监控要完善:没有监控就是裸奔
- 备份要及时:数据无价
- 升级要谨慎:先在测试环境验证
希望这些经验能帮你避开那些我踩过的坑。K8s确实强大,但用对了是神兵利器,用错了就是定时炸弹。多实践、多验证、多反思,你也能成为K8s专家!
