资讯详情

Docker与Kubernetes日常巡检实战:从容器状态到集群健康检查

📅 2026/10/9 10:57:57 | 华诺云谱 👁 阅读
Docker与Kubernetes日常巡检实战:从容器状态到集群健康检查
简介这份《Docker容器和kubernetes日常巡检指南》面向互联网运维工程师、容器云平台管理员及希望系统掌握容器巡检技能的初中级技术人员聚焦生产环境中Docker与Kubernetes集群的日常健康检查与故障排查。资源包内含1个docx文档压缩包约5.54MB以图文并茂的文档形式呈现便于随时查阅与团队内部分享。内容围绕容器状态查看、HealthCheck健康检查、docker stats资源监控、PrometheuscAdvisorGrafana第三方监听方案以及Kubernetes中kubectl检查master组件、Pod与Service状态、事件日志排查等核心巡检环节展开并补充了Docker引擎日志与容器日志的区分与查看方法。作者曹如熙为拥有十年以上互联网运维经验的高级运维leader文档源自其多年容器云实战总结可帮助读者建立完整的巡检思路快速定位异常容器与集群故障提升系统稳定性保障能力。目前已有81人学习下载。1. 巡检不是看绿灯一份能落地的 Docker 与 Kubernetes 排查手册很多运维同行对巡检的理解还停留在“看监控大盘是不是绿的”直到某天凌晨被电话叫醒发现某个 Pod 反复重启、节点 NotReady才意识到日常巡检缺的不是工具而是一套能直接照着敲命令、看输出、定位根因的流程。这份《Docker 容器和 kubernetes 日常巡检指南》出自一位有十年互联网运维经验的高级运维 leader核心价值在于把容器状态、健康检查、资源用量、日志路径、Kubernetes 控制面与节点巡检串成了一条可复现的链路。它适合正在维护容器云的一线运维、SRE也适合刚接手 Kubernetes 集群、需要快速建立排查直觉的开发者。下面我按自己拆文档的习惯把里面真正能抄作业的部分展开讲顺带补上几个文档没写透但现场一定会遇到的坑。2. Docker 容器巡检从 STATUS 到 HealthCheck 的完整链路2.1 先看容器状态别急着进容器巡检第一步永远是确认容器到底处于什么状态。docker ps -a和podman ps -a是最基础的入口但很多人只看“有没有 Up”忽略了 STATUS 括号里的信息。正常退出是Exited(0)异常退出是Exited(其他数字)这两种都需要结合日志判断Up(Paused)表示容器被暂停通常是人为操作或资源限制导致Up(healthy)和Up(unhealthy)则依赖健康检查配置没有配 HealthCheck 的容器不会显示这两个状态。# 查看所有容器状态包括已退出的 docker ps -a # 如果使用 podman命令完全一致 podman ps -a # 只看状态和名称方便脚本处理 docker ps -a --format table {{.Names}}\t{{.Status}}\t{{.Image}}这里有个容易翻车的地方Exited(0)并不代表没问题。如果容器本该常驻却退出了即使退出码是 0也说明进程生命周期管理有问题。我一般会配合docker inspect看RestartCount和FinishedAt判断是正常停止还是意外退出。参数上--format支持 Go 模板语法上面用\t分隔是为了后续用 awk 做告警阈值判断比默认输出好解析。2.2 HealthCheck 参数怎么设才不误报健康检查是容器巡检从“看进程”升级到“看服务”的关键。文档里给出的docker run示例很完整但实际落地时参数取值需要结合应用启动时间调整。--health-cmd支持 shell 和 exec 两种格式返回值 0 表示成功1 表示失败--health-interval默认 30 秒--health-timeout默认 30 秒--health-retries默认 3 次--start-period默认 0 秒。注意这些参数需要 Docker 17.05 以上版本才支持。# 启动 nginx 并配置健康检查 docker run --namenginx \ --health-cmdcurl --silent --fail localhost/ || exit 1 \ --health-interval30s \ --health-retries3 \ --health-timeout10s \ --start-period60s \ nginx:latest # 查看健康检查的详细状态 docker inspect --format {{json .State.Health}} nginx | python -m json.tool逻辑说明--start-period60s是给应用留的初始化窗口这 60 秒内健康检查失败不计入重试次数否则一个启动要 40 秒的 Java 应用会被反复标记 unhealthy。--health-retries3配合--health-interval30s意味着最坏情况下 90 秒后才判定不健康这个延迟要跟告警系统的采集周期对齐不然会出现“容器已经恢复、告警还没发出来”的尴尬。输出健康状态时用python -m json.tool格式化是为了在巡检脚本里用 jq 或 grep 提取Status字段做判断。2.3 资源用量与日志路径docker stats 和 json-filedocker stats是看 CPU、内存、网络、IO 的实时窗口但它默认是流式输出巡检脚本里要用--no-stream取一次快照。文档里特别提到容器日志默认以 json-file 格式存在/var/lib/docker/containers/容器id/容器id-json.logCRIO 的日志在/var/log/containers/。这里有个血泪经验不要长期依赖docker logs去翻日志尤其是高流量容器json-file 会无限增长把宿主机磁盘打满。# 取一次资源快照不流式输出 docker stats --no-stream --format table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}\t{{.NetIO}} # 查看最近 1 小时日志 docker logs --since 60m nginx # 查看指定时间段日志-t 加时间戳 docker logs -t --since2024-01-01T00:00:00 --until2024-01-01T01:00:00 nginx参数上--since和--until支持相对时间和绝对时间相对时间用60m、1h这种写法。建议在docker run时就把日志目录挂载到宿主机比如-v /opt/log:/log然后让 ELK 或 Loki 去抓宿主机上的文件而不是通过docker logs轮询。这样既避免日志驱动成为瓶颈也方便做长期留存和检索。如果容器已经跑起来没挂载日志卷临时排查可以用docker cp把 json.log 拷出来但别养成习惯。3. Kubernetes 控制面与节点巡检kubectl 命令的取舍3.1 master 组件状态get cs 和 systemctl 双确认Kubernetes 巡检的第一站是控制面。kubectl get cs能快速看到 kube-scheduler、kube-controller-manager、etcd 的 Healthy/Unhealthy 状态但输出比较简略。要更细的信息用kubectl describe cs。不过在实际生产里get cs有时会因为 apiserver 自身问题返回异常所以我会同时用systemctl status确认 kube-apiserver、calico 等服务的 Active 状态。# 查看控制面组件状态 kubectl get cs kubectl describe cs # 检查关键服务运行状态 systemctl status kube-apiserver.service systemctl status calico.service # 如果服务异常先看日志再重启 journalctl -xe systemctl restart kube-apiserver逻辑说明get cs走的是 apiserver 的 API如果 apiserver 本身挂了这个命令也会失败所以不能只依赖它。systemctl status看的是宿主机上的静态 Pod 或系统服务两者互补。重启 kube-apiserver 前一定要先journalctl -xe看具体报错常见的是证书过期、etcd 连接超时、端口占用。文档里还提到用kubectl logs --tail 100 -f跟踪 kube-apiserver、kube-controller-manager、kube-scheduler、coredns、calico-kube-controllers 的日志这个-f在巡检时建议去掉否则会挂住终端改成--tail 100取最近 100 行就够了。3.2 node 状态Ready 之外的版本一致性kubectl get node看 STATUS 是 Ready 还是 NotReady但文档特别强调“version 必须保持一致”。这是很多集群升级后遗留的问题部分节点 kubelet 版本落后短期看不出毛病一旦触发新特性或 API 变更就会翻车。NotReady 的常规处理是重启 kubelet 或 docker如果不行就kubectl drain node --delete-local-data驱离 Pod 后 reset 再重新 join。# 查看节点状态和版本 kubectl get node -o wide # 检查 kubelet 和 kube-proxy 服务 systemctl status kubelet.service systemctl status kube-proxy.service # 驱离节点前先确认 Pod 分布 kubectl drain node-name --delete-local-data --ignore-daemonsets参数上--delete-local-data会删除使用 emptyDir 的 Pod 数据--ignore-daemonsets是必须的因为 DaemonSet 管理的 Pod 不能被驱离。执行 drain 之前最好先kubectl get pods --all-namespaces -o wide | grep node-name确认没有单副本的有状态服务否则驱离会导致业务中断。node 日志检查用kubectl logs --tail 100 -f kube-proxy -n kube-system和kubectl logs --tail 100 -f calico-node -n kube-system同样建议去掉-f。3.3 service 与 pod 巡检TYPE 和 STATUS 的边界kubectl get svc -o wide和kubectl get svc --all-namespaces -o wide是看 Service 的基本命令重点看 TYPE 列。NodePort 类型的 Service 可以通过集群外部访问ClusterIP 只在集群内LoadBalancer 依赖云厂商ExternalName 是 CNAME 映射。如果 Service 的 Endpoints 为空说明后端 Pod 没 Ready这时候要回到 Pod 巡检。Pod 的 STATUS 列表比 Docker 丰富得多Running、Succeeded、Waiting、ContainerCreating、Failed、Pending、Terminating、Unknown、CrashLoopBackOff、ErrImagePull、ImagePullBackOff。其中 CrashLoopBackOff 和 ImagePullBackOff 是最高频的两种异常。kubectl describe pod看 Conditions 和 EventsInitialized、Ready、ContainersReady、PodScheduled 这几个条件为 True 才算正常。RESTARTS次数不为 0 就要去查日志别等它变成 CrashLoopBackOff 才动手。# 查看所有命名空间的 Pod 状态 kubectl get pods --all-namespaces -o wide # 查看某个 Pod 的详细事件 kubectl describe pod pod-name -n namespace # 查看 Pod 日志注意 -f 在巡检时慎用 kubectl logs --tail 100 pod-name -n namespace这里有个常见误区kubectl logs只能看到当前容器的日志如果 Pod 重启过上一次的日志需要用--previous参数。另外Pod 日志文件在节点上的路径是/var/log/pods/namespace_pod-name_uid/container-name/里面的0.log是当前日志1.log是上一次的。直接进节点看文件比反复敲kubectl logs更快尤其是在 apiserver 响应慢的时候。4. 健康检查与监控告警liveness、readiness 和 Prometheus 的配合4.1 livenessProbe 与 readinessProbe 的参数差异Pod 的健康检查分两种livenessProbe 检测容器是否存活不健康就 kill 掉按 RestartPolicy 重启readinessProbe 检测容器是否 Ready不健康就从 Service 的 Endpoints 里摘掉。文档里给出的参数包括initialDelaySeconds、timeoutSeconds、periodSeconds、scheme、successThreshold、failureThreshold。其中initialDelaySeconds: 120表示 Pod 启动后延迟 120 秒再开始检测这个值要根据应用实际启动时间设设小了会误杀设大了会延迟故障发现。# pod.yaml 中的健康检查片段 livenessProbe: httpGet: path: /healthz port: 8080 scheme: HTTP initialDelaySeconds: 120 timeoutSeconds: 5 periodSeconds: 10 successThreshold: 1 failureThreshold: 3 readinessProbe: httpGet: path: /ready port: 8080 initialDelaySeconds: 30 timeoutSeconds: 3 periodSeconds: 5 failureThreshold: 2逻辑说明liveness 的successThreshold必须是 1这是 Kubernetes 的硬性限制因为“存活”没有“连续成功几次才算活”的中间状态。readiness 的failureThreshold可以设小一点比如 2这样不健康的 Pod 能更快被摘除。periodSeconds和timeoutSeconds的关系要注意timeout 不能大于 period否则探测还没结束下一轮就开始了。如果应用是 TCP 服务scheme可以改成 TCP但 HTTP 探测能拿到更明确的返回码。4.2 Prometheus cAdvisor Grafana 的巡检闭环文档里介绍的第三方监控组合是 Prometheus cAdvisor Grafana。cAdvisor 是 Google 开源的容器数据采集器收集 CPU、内存、FS、网络等 usagePrometheus 通过 node-exporter 采集节点信息通过 cAdvisor 采集容器信息Grafana 做展示和自定义报警。如果容器规模大建议用 alertmanager 做报警收敛避免告警风暴。# 检查 node-exporter 是否正常通常在 9100 端口 curl -s http://node-ip:9100/metrics | head # 检查 cAdvisor 是否正常通常在 8080 端口 curl -s http://node-ip:8080/metrics | grep container_cpu_usage_seconds_total | head参数上node-exporter 用 DaemonSet 部署保证每个节点都有一个 Pod新增节点自动扩展。cAdvisor 也是类似思路。Grafana 的 dashboard 可以去官网找现成模板导入后重点看up指标和container_last_seen指标。up 0表示采集目标挂了container_last_seen超过一定时间没更新表示容器可能已经消失。自定义报警规则里我一般会加一条count(container_last_seen{name~.}) by (node) 预期容器数用来发现“容器静默消失”这种不报错但很致命的情况。4.3 Dashboard 与令牌访问的权限边界Kubernetes Dashboard 提供图形化巡检入口通过kubernetes-dashboard.yaml部署浏览器访问https://k8sip:30443/#!/login用令牌登录。令牌获取方式是kubectl describe secret admin-token-xxxx -n kube-system。Dashboard 权限很高能创建、删除容器和 Pod能伸缩 Deployment 和 ReplicaSet能管理 Secret。文档里明确提醒了这一点我的建议是巡检用的 Dashboard 账号只给只读权限别用 admin-token 长期登录。# 获取 dashboard 登录令牌 kubectl -n kube-system describe secret $(kubectl -n kube-system get secret | grep admin-token | awk {print $1}) # 查看 dashboard 服务暴露端口 kubectl -n kube-system get svc kubernetes-dashboard如果 Dashboard 的 Service 是 ClusterIP需要改成 NodePort 或者用kubectl proxy访问。kubectl proxy的好处是不用暴露端口坏处是只能本机访问。生产环境建议用 Ingress 加认证别直接把 30443 暴露到公网。Dashboard 里看节点状态、Pod 状态、CPU 内存使用率很方便但事件和日志还是命令行更灵活。5. 巡检避坑五条现场踩出来的经验5.1 现象容器 Up 但服务不可用原因没配 HealthCheck解决补 livenessProbe这是最经典的“假活”场景。容器进程还在但内部应用已经死锁或端口不监听。docker ps显示 Upkubectl get pods显示 Running但请求全部超时。根因是只检查了进程存在没检查服务可用性。解决方式是在 Dockerfile 或 Pod yaml 里加健康检查HTTP 服务用httpGet探/healthzTCP 服务用tcpSocket实在不行用exec跑一个 curl 或 nc。注意initialDelaySeconds要给足否则启动阶段就被判定失败。5.2 现象节点磁盘满导致 Pod 被驱逐原因json-file 日志无限增长解决配 log rotation 或挂载日志卷Docker 默认的 json-file 日志驱动没有大小限制一个高流量容器一天写几十 GB 很常见。磁盘满之后 kubelet 会触发驱逐Pod 被赶到其他节点看起来像“随机漂移”。根因是日志没做轮转。解决方式有两种在/etc/docker/daemon.json里配log-opts的max-size和max-file或者把日志目录挂载到宿主机由外部系统采集。Kubernetes 里可以在 Pod 的containers[].args里加--log-opt但更推荐用 DaemonSet 统一管理。{ log-driver: json-file, log-opts: { max-size: 100m, max-file: 3 } }改完 daemon.json 要重启 docker但重启会影响所有容器建议在维护窗口做。max-size: 100m和max-file: 3表示单个日志文件最大 100MB最多保留 3 个总共 300MB。这个值根据磁盘容量和日志量调整别设太小导致关键日志被冲掉。5.3 现象Pod 一直 Pending原因资源请求超过节点可分配解决看 describe 的 Eventskubectl get pods显示 Pendingkubectl describe pod的 Events 里会写Insufficient cpu或Insufficient memory。根因是 Pod 的resources.requests设得太大或者节点上已有 Pod 占满了可分配资源。解决方式是调小 requests或者给节点扩容或者用kubectl describe node看Allocated resources确认剩余量。注意limits和requests的区别requests 影响调度limits 影响运行时上限requests 不能大于 limits。5.4 现象CrashLoopBackOff 反复重启原因应用启动依赖未就绪解决加 initContainer 或调大 failureThresholdCrashLoopBackOff 是 Pod 启动后很快退出kubelet 按指数退避重启。常见根因是应用依赖的数据库或缓存还没起来应用连不上就退出。解决方式是用initContainer做依赖检查或者把livenessProbe的initialDelaySeconds和failureThreshold调大给应用足够的重试时间。但要注意如果是配置错误导致的启动失败调大参数只是拖延时间根本解决还是要看日志里的报错。5.5 现象kubectl 命令响应慢或超时原因apiserver 负载高或 etcd 性能瓶颈解决看 apiserver 指标和 etcd 延迟巡检时如果kubectl get pods要等好几秒说明 apiserver 或 etcd 有问题。先看 apiserver 的request_latency_seconds指标再看 etcd 的wal_fsync_duration_seconds。etcd 对磁盘 IO 很敏感如果 fsync 延迟超过 10ms整个集群的写入都会变慢。解决方式是给 etcd 换 SSD或者把 etcd 独立部署避免和其他 IO 密集型服务混部。这个坑比较深日常巡检里加一条对 etcd 延迟的监控很有必要。6. 把巡检脚本化一个可复用的检查清单和告警阈值巡检做久了会发现靠人肉敲命令迟早会漏。我现在的习惯是把高频检查项写成一个 shell 脚本每天定时跑一遍输出异常项到告警通道。下面这个脚本覆盖了 Docker 容器状态、Kubernetes 节点状态、Pod 重启次数和 etcd 健康检查你可以根据自己的环境改阈值。#!/bin/bash # 容器与 K8s 日常巡检脚本 # 用法./inspect.sh 21 | tee /var/log/inspect-$(date %F).log echo Docker 容器异常状态检查 docker ps -a --format {{.Names}}\t{{.Status}} | grep -v Up | while read line; do echo [异常] $line done echo Kubernetes 节点状态检查 kubectl get node --no-headers | awk $2 ! Ready {print [NotReady] $1 $2} echo Pod 重启次数检查 kubectl get pods --all-namespaces --no-headers | awk $5 3 {print [重启过多] $1 $2 重启次数:$5} echo etcd 健康检查 kubectl -n kube-system exec etcd-$(hostname) -- etcdctl endpoint health 2/dev/null || echo [etcd] 检查失败需手动确认 echo 节点资源分配检查 kubectl describe node | grep -A 5 Allocated resources | grep -E cpu|memory | awk {if ($30 80) print [资源紧张] $0}逻辑说明第一段用grep -v Up过滤掉正常运行的容器剩下的就是 Exited、Paused、unhealthy 等异常状态。第二段用 awk 判断节点 STATUS 列是否不等于 Ready。第三段判断 RESTARTS 列是否大于 3这个阈值可以根据业务容忍度调整我一般设 3因为超过 3 次说明重启不是偶发。第四段检查 etcd 健康注意 etcd Pod 名称通常带节点名用hostname拼接。第五段看节点已分配资源是否超过 80%超过就要考虑扩容或迁移。阈值设置上CPU 和内存的告警线我一般设 80%磁盘设 85%etcd fsync 延迟设 10ms。这些值不是绝对的要根据集群规模和业务峰谷调整。脚本跑完把日志按日期存下来方便回溯“上周三是不是也出现过同样的异常”。另外脚本里的kubectl命令最好加上--request-timeout10s避免 apiserver 卡住时脚本一直挂起。从那以后我每次接手新集群第一件事就是把这个脚本跑一遍把输出里的异常项逐个确认而不是等监控告警。巡检的价值不在于工具多花哨而在于你看到Exited(1)时知道下一步该敲什么命令。希望帮到你。本文还有配套的精品资源点击获取
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑