【k8s】从 GitLab 504 到 Ceph 存储问题
·
详细排查与操作全过程复盘
以下是本次从 GitLab 504 到 Ceph 存储清理 的完整操作流程,每一步均包含:操作背景、具体命令、预期结果、实际结果及结论。
阶段一:问题感知与初步定位(GitLab 504)
步骤 1:确认 GitLab 服务异常
- 操作:用户反馈 GitLab GraphQL API 返回
504 Gateway Timeout。 - 命令(用户侧):
curl -I https://gitlab.blocgo.tech/api/graphql - 预期结果:返回
200 OK或200状态码。 - 实际结果:返回
504 Gateway Timeout。 - 结论:后端服务(GitLab Rails)响应超时,需要进一步检查内部组件。
步骤 2:检查 GitLab 相关 Pod 状态
- 操作:查看 GitLab 的
webservicePod 健康状态。 - 命令:
kubectl get pods -n gitlab | grep webservice - 预期结果:
webservicePod 状态应为Running且READY 1/1。 - 实际结果:Pod 状态为
Running,但READY 0/1,Readiness Probe 失败。 - 结论:Pod 已启动但未就绪,需要查看探针日志。
步骤 3:检查 Readiness Probe 失败原因
- 操作:查看 Pod 事件。
- 命令:
kubectl describe pod <webservice-pod-name> -n gitlab - 预期结果:事件显示探针成功或具体失败原因。
- 实际结果:事件显示
Readiness probe failed: Get "http://10.244.8.21:8080/-/readiness": context deadline exceeded (Client.Timeout exceeded while awaiting headers)。 - 结论:
webservice容器自身响应超时,可能是内部依赖(如数据库)不可用。
步骤 4:检查 GitLab 依赖的数据库
- 操作:查看 GitLab 配置中的数据库连接信息(通常为
gitlab-postgresql或共享数据库)。 - 命令:
kubectl get svc -n gitlab | grep postgres - 预期结果:存在
gitlab-postgresqlService。 - 实际结果:未发现独立的 GitLab 数据库,进一步检查发现 GitLab 配置指向 Harbor 的数据库(
harbor-db-postgresql)。 - 结论:GitLab 与 Harbor 共用数据库,Harbor 数据库可能存在问题。
阶段二:深入 Harbor 数据库排查
步骤 5:检查 Harbor 数据库 Pod 状态
- 操作:查看
harbor-db-postgresql-0Pod 状态。 - 命令:
kubectl get pod -n kube-infrastructure harbor-db-postgresql-0 - 预期结果:状态
Running且READY 1/1。 - 实际结果:状态
Running但READY 0/1。 - 结论:PostgreSQL 容器未就绪,可能未正常启动。
步骤 6:查看数据库容器日志
- 操作:查看
harbor-db-postgresql-0容器的日志。 - 命令:
kubectl logs -n kube-infrastructure harbor-db-postgresql-0 - 预期结果:显示 PostgreSQL 启动日志(如
database system is ready to accept connections)。 - 实际结果:日志为空,无任何输出。
- 结论:PostgreSQL 进程可能根本没有启动,或输出被重定向。
步骤 7:尝试进入容器内部
- 操作:使用
kubectl exec进入容器。 - 命令:
kubectl exec -it -n kube-infrastructure harbor-db-postgresql-0 -- /bin/bash - 预期结果:成功进入容器 shell。
- 实际结果:命令卡住或报错(无法连接到容器)。
- 结论:容器主进程未运行,无法建立交互会话。
步骤 8:检查健康探针配置
- 操作:查看 Pod 的 Liveness/Readiness 探针配置。
- 命令:
kubectl describe pod -n kube-infrastructure harbor-db-postgresql-0 | grep -A5 -B5 "Liveness" - 预期结果:探针命令为
pg_isready -h localhost -U ...。 - 实际结果:探针配置正确,但持续失败。
- 结论:PostgreSQL 未响应,问题可能在存储层。
阶段三:存储层问题定位
步骤 9:在节点上检查挂载点
- 操作:登录 Pod 所在节点
k8s-worker-00,查看 PVC 挂载情况。 - 命令:
mount | grep harbor-db - 预期结果:显示正确的挂载路径。
- 实际结果:挂载点存在,路径为
/var/lib/kubelet/pods/.../mount。 - 结论:存储已挂载,但可能 I/O 异常。
步骤 10:尝试访问数据目录
- 操作:进入挂载点目录,执行
ls -la。 - 命令:
cd /var/lib/kubelet/pods/.../mount && ls -la - 预期结果:列出数据目录内容(如
data、pg_wal等)。 - 实际结果:
ls -la命令卡死,无响应。 - 结论:存储后端 I/O 阻塞,可能存储设备不可用。
步骤 11:检查内核日志(dmesg)
- 操作:查看系统内核消息。
- 命令:
dmesg | tail -30 - 预期结果:无异常 I/O 错误。
- 实际结果:频繁出现
libceph: pool 13 is full or reached quota。 - 结论:Ceph 存储池
ceph-blockpool-retain(ID 13)已满,导致所有写入操作阻塞。
阶段四:Ceph 存储诊断
步骤 12:进入 Rook 工具箱
- 操作:进入 Rook 提供的 Ceph 工具 Pod。
- 命令:
kubectl exec -it -n rook-ceph rook-ceph-tools-xxx -- bash - 预期结果:进入 bash shell。
- 实际结果:成功进入。
- 结论:可执行 Ceph 命令。
步骤 13:检查集群整体使用情况
- 操作:查看 Ceph 存储概览。
- 命令:
ceph df - 预期结果:显示各池使用率。
- 实际结果:
RAW STORAGE: TOTAL 838 GiB, USED 796 GiB, AVAIL 42 GiB, %USED 94.99 ceph-blockpool-retain: USED 316 GiB, %USED 100.00, MAX AVAIL 0 B - 结论:集群整体接近满(94.99%),且
ceph-blockpool-retain池显示 100% 使用,MAX AVAIL为 0。
步骤 14:检查池配额
- 操作:查看池配额设置。
- 命令:
ceph osd pool get-quota ceph-blockpool-retain - 预期结果:显示配额值。
- 实际结果:
max objects: N/A, max bytes: N/A。 - 结论:未设置配额,是物理空间用尽。
步骤 15:检查 full_ratio 阈值
- 操作:查看集群 full 阈值。
- 命令:
ceph osd dump | grep -E "full_ratio|nearfull_ratio" - 预期结果:显示阈值。
- 实际结果:
full_ratio 0.95,nearfull_ratio 0.85。 - 结论:使用率达 94.99%,接近 95%,Ceph 拒绝写入操作。
阶段五:数据清理尝试(初始失败)
步骤 16:列出 RBD 镜像
- 操作:列出
ceph-blockpool-retain池中的所有镜像。 - 命令:
rbd ls -l --pool ceph-blockpool-retain - 预期结果:显示镜像列表及大小。
- 实际结果:返回约 80 个镜像列表。
- 结论:存在大量可能废弃的镜像。
步骤 17:找出孤儿镜像
- 操作:将 Kubernetes PV 中的
volumeHandle与 RBD 镜像名进行 UUID 比对。 - 命令(示例):
kubectl get pv -o json | jq -r '.items[] | .spec.csi.volumeHandle' | sed 's/.*-\([^-]*\)-\([^-]*\)-\([^-]*\)-\([^-]*\)-\([^-]*\)$/\1-\2-\3-\4-\5/' > /tmp/k8s_uuids.txt rbd ls --pool ceph-blockpool-retain | sed 's/^csi-vol-//' > /tmp/ceph_uuids.txt comm -23 /tmp/ceph_uuids.txt /tmp/k8s_uuids.txt - 预期结果:输出孤儿 UUID 列表。
- 实际结果:找到了数个体积较大的孤儿镜像,包括疑似 Harbor 数据库的镜像。
- 结论:这些镜像没有 PV 引用,理论上可以清理。
步骤 18:尝试删除一个孤儿镜像
- 操作:删除其中一个孤儿镜像(如
csi-vol-fd62458b-...)。 - 命令:
rbd rm --pool ceph-blockpool-retain csi-vol-fd62458b-... - 预期结果:删除成功。
- 实际结果:报错
(28) No space left on device,rbd rm失败。 - 结论:因存储池已满,即使删除操作也需要写入元数据,无法执行。
阶段六:临时解除写阻塞并完成清理
步骤 19:临时提高 full_ratio 阈值
- 操作:将 full_ratio 从 0.95 提升至 0.98,允许写入操作(含删除元数据)。
- 命令:
ceph osd set-full-ratio 0.98和ceph osd set-nearfull-ratio 0.90 - 预期结果:无报错。
- 实际结果:命令成功执行。
- 结论:集群暂时允许写入。
步骤 20:再次尝试删除镜像(成功)
- 操作:删除之前失败的镜像。
- 命令:
rbd rm --pool ceph-blockpool-retain csi-vol-fd62458b-... - 预期结果:删除成功。
- 实际结果:删除成功,输出
Removing image: 100% complete...。 - 结论:空间开始释放。
步骤 21:批量删除孤儿镜像
- 操作:陆续删除其他孤儿镜像(包括 Harbor 数据库对应的镜像
csi-vol-5979a964-...)。 - 命令:重复
rbd rm命令。 - 预期结果:所有孤儿镜像被删除。
- 实际结果:成功删除数个镜像,释放约 30 GiB 空间。
- 结论:存储池使用率下降至 93% 左右,恢复可用空间。
步骤 22:恢复 full_ratio 阈值
- 操作:将阈值恢复至默认值。
- 命令:
ceph osd set-full-ratio 0.95和ceph osd set-nearfull-ratio 0.85 - 预期结果:无报错。
- 实际结果:成功恢复。
- 结论:集群安全阈值恢复。
阶段七:服务恢复验证
步骤 23:检查 Harbor 数据库 Pod
- 操作:观察
harbor-db-postgresql-0Pod 状态。 - 命令:
kubectl get pod -n kube-infrastructure harbor-db-postgresql-0 -w - 预期结果:Pod 变为
Running且READY 1/1。 - 实际结果:Pod 成功启动,Readiness Probe 通过。
- 结论:PostgreSQL 正常初始化。
步骤 24:检查 Harbor 服务状态
- 操作:访问 Harbor UI 或检查相关 Pod。
- 命令:
kubectl get pods -n kube-infrastructure | grep harbor - 预期结果:所有 Harbor Pod 均就绪。
- 实际结果:Harbor 核心服务恢复。
步骤 25:检查 GitLab 服务
- 操作:查看 GitLab
webservicePod 状态。 - 命令:
kubectl get pods -n gitlab | grep webservice - 预期结果:Pod 状态
Running且READY 1/1。 - 实际结果:Readiness Probe 成功。
- 结论:GitLab 恢复,GraphQL API 正常响应。
🔚 总结
整个故障源于 Ceph 存储池 ceph-blockpool-retain 使用率达到 95%,触发 Ceph 的保护机制,拒绝一切写入操作,导致 Harbor 数据库无法启动,进而连锁影响 GitLab。通过临时提高 full_ratio 阈值,删除无用的孤儿镜像释放空间,最终恢复所有服务。
关键数据:
- 释放空间约 30 GiB
- 删除孤儿镜像数量:~8 个
- 总耗时(从开始到恢复):约 3 小时
后续建议:
- 建立存储容量监控告警(阈值 80% 预警,90% 严重)
- 定期清理孤儿 RBD 镜像
- 考虑扩容 Ceph 集群
- 梳理服务依赖,避免共用数据库导致单点故障
以上即为本次排查与操作的完整详细记录。如有遗漏或需要补充的环节,请随时指出。
更多推荐
所有评论(0)