存储和集群核心组件的故障,影响范围比 Pod 故障大一个数量级。一个 etcd 抖动可能让整个集群停摆,一个 PV 挂错可能让 StatefulSet 起不来,一个证书过期能让 kubectl 直接罢工。这一卷专治"看起来不太对劲但又说不清楚"的疑难杂症。
# 1. 看 PVC 状态和事件 kubectl describe pvc <pvc-name> # 重点看 Events 段,会明确告诉你哪里不匹配 # 2. 列出可用 PV(静态场景) kubectl get pv # 看 STATUS=Available 的 PV,对比 PVC 要求 # 3. 检查 StorageClass(动态场景) kubectl get storageclass kubectl get sc -o wide # 默认的 SC 后面会有 (default) 标识 # 4. 检查 provisioner Pod kubectl -n kube-system get pod | grep -E "nfs|csi|provisioner" kubectl -n kube-system logs <provisioner-pod> --tail=50
| 模式 | 简写 | 含义 | 典型存储 |
|---|---|---|---|
| ReadWriteOnce | RWO | 单节点读写 | 云盘、本地盘 |
| ReadOnlyMany | ROX | 多节点只读 | NFS、CephFS |
| ReadWriteMany | RWX | 多节点读写 | NFS、CephFS |
| ReadWriteOncePod | RWOP | 单 Pod 读写(K8s 1.22+) | 云盘 |
kubectl patch storageclass <sc-name> -p \ '{"metadata":{"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'
# 1. 详细错误信息 kubectl describe pod <pod> | grep -A 10 MountVolume # 2. 节点上手动挂载测试 NFS ssh <node> showmount -e <nfs-server-ip> mount -t nfs <nfs-ip>:/data /mnt/test # 3. 检查挂载工具 rpm -qa | grep nfs-utils # CentOS apt list --installed | grep nfs-common # Ubuntu # 4. 看节点 kubelet 日志 journalctl -u kubelet -f | grep -i mount
spec: securityContext: runAsUser: 1000 runAsGroup: 1000 fsGroup: 1000 # 关键!挂载后会把卷的属组改成 fsGroup,Pod 可写 containers: - name: app image: myapp volumeMounts: - name: data mountPath: /data
no_root_squash 选项,否则 Pod 内 root 用户写入会变成 nobody。生产环境不建议这么配,而是用 fsGroup + 非 root 用户。
kubernetes.io/pv-protection 未清理# 1. 看 PV 详情 kubectl describe pv <pv-name> # 2. Released 状态:删除 claimRef 让它回到 Available kubectl patch pv <pv> -p '{"spec":{"claimRef":null}}' # 3. Terminating 卡死:移除 finalizer(谨慎!确认底层存储已清) kubectl patch pv <pv> -p '{"metadata":{"finalizers":null}}'
| 策略 | PVC 删除后 | 使用建议 |
|---|---|---|
Retain | 保留 PV 和数据,变 Released | 生产数据,需人工干预 |
Delete | PV 和底层存储一起删 | 测试环境、临时存储 |
Recycle | 清空数据后变 Available(已废弃) | 不推荐使用 |
<template>-<sts-name>-<序号># 删除 StatefulSet 但保留数据(标准做法) kubectl delete sts <name> --cascade=orphan # 或先用这个命令把 PVC 的 reclaimPolicy 改成 Retain # 查看 sts 关联的 PVC kubectl get pvc | grep <sts-name>
Retain,即使 StorageClass 默认是 Delete 也要 patch 单个 PV 修改。删数据前用 kubectl get pv -o yaml > backup.yaml 备份元数据。
# 1. 看节点状态详情 kubectl describe node <node> | grep -A 5 Conditions # 关注 Type/Status/Reason,定位是哪类问题 # 2. 登录节点检查关键服务 ssh <node> systemctl status kubelet systemctl status containerd # 或 docker # 3. kubelet 日志(最有价值) journalctl -u kubelet --since "10 min ago" | tail -100 # 4. 节点资源 df -h df -i free -h top # 5. 网络连通性 ping <master-ip> curl -k https://<master-ip>:6443 # 6. 重启 kubelet systemctl restart kubelet
| Condition Type | True 含义 | 排查方向 |
|---|---|---|
| Ready | 节点正常 | False 时看其他 Conditions |
| MemoryPressure | 内存压力大 | free -h, 找内存大户 |
| DiskPressure | 磁盘压力大 | df -h, 清理镜像和日志 |
| PIDPressure | 进程数过多 | ps aux 看进程,可能是 fork 炸弹 |
| NetworkUnavailable | 网络异常 | 检查 CNI |
# 1. 找大目录 du -h --max-depth=1 / 2>/dev/null | sort -hr | head du -h --max-depth=1 /var/lib | sort -hr # 2. 容器镜像占用(通常是 90% 的元凶) crictl images crictl rmi --prune # containerd 清理悬挂镜像 # Docker 环境 docker system df docker system prune -af --volumes # 清所有未使用资源 # 3. 容器日志(单个容器日志默认无上限!) find /var/lib/docker/containers/ -name "*-json.log" -size +500M find /var/log/pods/ -name "*.log" -size +100M # 4. 系统日志 journalctl --vacuum-time=7d journalctl --vacuum-size=500M
# 修改 /etc/docker/daemon.json (Docker) { "log-driver": "json-file", "log-opts": { "max-size": "100m", "max-file": "3" } } # containerd: kubelet 配置 --container-log-max-size=100Mi
docker system prune -af 加上 --volumes 会一并清理 dangling 卷,误删风险高,生产慎用。
# 1. 测 API Server 响应 time kubectl get nodes time kubectl get pods -A # 2. 看 API Server 日志 kubectl -n kube-system logs -l component=kube-apiserver --tail=100 # 重点看 "slow request" 警告 # 3. API Server 指标 kubectl get --raw /metrics | grep apiserver_request_duration # 4. 谁在频繁请求 API(找出元凶) kubectl get --raw /metrics | grep apiserver_request_total | sort | tail
# 1. 看 etcd Pod 状态 kubectl -n kube-system get pod | grep etcd # 2. 集群健康检查 ETCDCTL_API=3 etcdctl \ --endpoints=https://127.0.0.1:2379 \ --cacert=/etc/kubernetes/pki/etcd/ca.crt \ --cert=/etc/kubernetes/pki/etcd/server.crt \ --key=/etc/kubernetes/pki/etcd/server.key \ endpoint health # 3. 看成员列表和 leader etcdctl member list etcdctl endpoint status --write-out=table # 4. etcd 数据库大小(默认 quota 2GB,超了会拒写) etcdctl endpoint status --write-out=json | grep dbSize # 5. 数据库压缩(碎片整理) etcdctl compact <rev> etcdctl defrag
etcdctl snapshot save backup.db 可热备份。所有 etcd 节点同时挂掉是最严重情况,只能从快照恢复,会丢失最后一次快照之后的数据。
etcd_disk_wal_fsync_duration_seconds,p99 超过 25ms 就该报警。
# 1. 检查证书过期时间(每个 master 都要查) kubeadm certs check-expiration # 输出每个证书的剩余有效期 # 2. 一键续签所有证书(kubeadm 集群) kubeadm certs renew all # 3. 重启 control plane 组件让新证书生效 cd /etc/kubernetes/manifests mv kube-apiserver.yaml /tmp/ sleep 30 # 等 kubelet 删掉旧 Pod mv /tmp/kube-apiserver.yaml . # controller-manager 和 scheduler 同样操作 # 4. 更新 kubeconfig cp -f /etc/kubernetes/admin.conf $HOME/.kube/config # 5. 验证 kubeadm certs check-expiration kubectl get nodes
rotateCertificates: true 后会自动续签。生产环境务必开启,不然 1 年后所有节点变 NotReady。
kubeadm certs check-expiration,小于 30 天就报警。
| 报错 | 含义 | 解决 |
|---|---|---|
| connection refused | API Server 端口不通 | 检查 6443 端口、防火墙 |
| x509 expired | 证书过期 | kubeadm certs renew |
| x509 unknown authority | CA 不匹配 | kubeconfig 用错集群 |
| Unable to connect to server | kubeconfig 无效 | 检查 KUBECONFIG 环境变量 |
| Forbidden | RBAC 没权限 | 看 ClusterRoleBinding |
| Unauthorized | token/证书无效 | 重新生成 kubeconfig |
# 1. 看当前 context kubectl config current-context kubectl config view --minify # 2. 测 API Server 端口连通性 curl -k https://<api-server>:6443/healthz # 3. 详细模式看请求过程 kubectl get nodes -v=8 # 4. RBAC 权限问题:看自己有什么权限 kubectl auth can-i --list kubectl auth can-i get pods -n default
"运维不是把出问题的修好,而是让该出的问题
在出现之前就被发现。
监控、告警、备份、演练,缺一不可。"