
简介这是一份面向运维人员和容器平台管理者的Docker与Kubernetes日常巡检指南凝结了作者十余年互联网运维及容器云实践经验。Docker部分围绕docker/podman ps查看容器状态教读者区分Exited(0)正常退出、非0异常退出、Up(Paused)暂停以及healthy/unhealthy健康状态HealthCheck健康检查部分说明--interval、--timeout、--retries、--start-period等参数设置再用docker stats观察CPU、内存、网络和IO占用并介绍docker logs查询最近或指定时段日志的方法同时提醒可将容器日志挂载到宿主机便于ELK采集。Kubernetes部分以kubectl/oc get cs检查master核心组件、describe查看详情、logs排查服务日志为主线并涉及calico网络状态与kube-apiserver等服务的systemctl检查同时给出Prometheus、cAdvisor、Grafana搭建监控告警的落地思路。文档为1个docx文件约5.54MB结构清晰命令与判断标准可直接对照执行既能帮助新手建立巡检框架也可作为团队日常运维手册。已有81人学习下载适合容器化转型中的运维团队参考。1. 为什么说“救火式运维”是被逼出来的Docker容器和Kubernetes日常巡检到底在查什么Docker容器和Kubernetes日常巡检听起来像是运维团队“没事找事”的例行公事但我见过太多凌晨两点爬起来修集群的人——他们的共同点是平时只等服务报警报警响了就救火火灭了就当无事发生。日常巡检要解决的不是“现在坏没坏”而是“明天会不会坏”。它查的是镜像漂移、磁盘水位、容器异常重启趋势、节点状态变化这些不会当场爆炸、但会慢慢积累的东西。这套指南适合两种人刚接手一个Docker或Kubernetes环境、急着摸清家底的人以及已经被凌晨电话折磨过、想从救火转向防火的人。2. 巡检前先立基线把“正常”变成一组可以对比的数据巡检最怕的不是发现问题而是看到一堆输出却不知道什么是“不对”。比如kubectl get nodes看到STATUS是NotReady你当然知道出问题了但如果STATUS全绿却没发现昨天有3台worker节点、今天只剩2台那这个巡检就是白做了。Docker和Kubernetes都是同一套逻辑单看一条命令的输出什么都看不出来只有和上一次运行的结果做差异对比问题才会浮出水面。所以我做巡检的第一件事不是跑命令而是先给整个环境拍一组基线照片——记录这套环境健康时该有的样子。基线的核心是回答三个问题哪些容器在跑、镜像版本是什么、端口和依赖关系是什么。这三个问题不解决后面所有巡检命令都是对着黑匣子猜。我会把基线落成一份文本按日期存档之后每次巡检输出的结果都和它做 diff新增了什么容器、哪个镜像悄悄变了一眼就能看到。2.1 镜像、标签与摘要用docker inspect给容器拍一张“身份证”容器是易变的但镜像本身的数据是固定的问题出在latest这类可变标签上。任何人手动执行一次docker tag再docker pushlatest指向的内容就变了容器下次重建跑的就是另一个代码版本。我一般会把每个运行中容器的镜像摘要digest和启动参数记录下来命令是这样# 把每个运行中容器的关键元数据导出为基线文件 mkdir -p ~/ops-baseline # 列出所有容器并提取镜像摘要、启动命令、端口映射、挂载点 docker ps -q | while read cid; do docker inspect --format {{.Name}}|{{.Config.Image}}|{{.Image}}|{{.HostConfig.PortBindings}}|{{range .Mounts}}{{.Source}}:{{.Destination}};{{end}} $cid done | tee ~/ops-baseline/containers_$(date %F).txt这里{{.Image}}是镜像的sha256摘要不是tag。tag可以被随便改digest只要镜像内容发生变化就会变所以巡检时做差异比对用digest比用nginx:latest可靠得多。我把这份文件按日期存成基线巡检时对比两次的差异新增容器和镜像变更立刻暴露。docker inspect的字段很多不用全记思路是抓四个关键点Config.Image是启动时用的镜像名Image是真正的摘要HostConfig.PortBindings是端口映射关系Mounts是卷挂载。如果管理的宿主机多把这文件同步到集中位置别只存在单机本地。基线文件建议记录的关键字段大致是下面这个表字段用途巡检时怎么比容器名与ID标识身份新出现或消失都能发现镜像tag与digest检测镜像漂移digest变了一定有内容变更端口映射暴露面管理多了新端口要确认来源挂载目录数据与配置归属挂载点变化可能导致数据读不到restart策略理解容器异常行为和STATUS列的Restarting配合看2.2 端口映射与依赖清单画一张集群的“交通图”镜像漂移之外巡检常见的盲区是端口和依赖。Docker容器互相通信靠网络Kubernetes内部靠Service和DNS一旦有人手动改过防火墙或者两个服务抢同一个宿主端口表现往往是“某个接口突然超时”。我接手环境的第一步永远是画交通图这台宿主机上哪些端口被容器占用、哪个容器依赖哪个数据库、Redis主从和MySQL主从的拓扑是什么。常见做法是先用ss -tlnp把监听端口和进程对起来再对照docker ps里的映射信息验证# 查看宿主机上所有监听端口对应的进程 ss -tlnp | awk NR1 {print $4, $6} # 查看当前所有容器的端口映射和上面结果互相印证 docker ps --format table {{.Names}}\t{{.Ports}}ss输出里127.0.0.1:3306表示只监听回环0.0.0.0:3306表示对外暴露。线上事故经常是同一个端口被两个容器抢着映射docker ps不一定看得出来但ss能立刻露马脚。对照完以后把端口、容器名、依赖方向写进一张表每次巡检先问自己今天的端口关系是不是和表里一致不一致就是有东西被改动过。Kubernetes环境还要额外看Service和Endpointkubectl get endpoints -A比Pod列表更早暴露问题Service指向的Pod如果被删了Endpoint列表会先空出来Pod本身可能还在重启中。2.3 基线不是建一次就完事定期刷新才不会被“新常态”骗过基线最大的陷阱是“过期”。环境正常演进新服务上线、旧服务下线基线三个月不更新新常态和旧基线对不上巡检就会天天误报。我在基线文件里额外记一个刷新日期每个月月底固定花十分钟按2.1的命令重新生成一份然后人工确认diff结果——哪些是计划内的变更哪些是没人认领的改动。没人认领的改动才是巡检真正要找的东西。提示基线刷新时别直接覆盖旧文件按日期归档保留最近三个月的版本。查“什么时候开始不正常”这种问题时多份历史基线就是时间轴。3. Docker容器日常巡检三条命令定位九成容器异常有了基线做参照日常巡检就可以按固定套路跑命令了。Docker层面的巡检我用得最多的命令就三条docker ps看状态、docker stats看资源、docker logs看日志。这三条命令覆盖了容器九成以上的异常场景剩下的交给daemon本身的检查。3.1 docker ps和docker stats看懂STATUS与资源水位先看状态。docker ps只显示运行中的容器docker ps -a会把Exited状态的也翻出来。我巡检时一定加-a因为要看的恰恰是那些“退出了但没人知道”的容器# 显示所有容器格式化输出关键字段 docker ps -a --format table {{.Names}}\t{{.Status}}\t{{.Image}} # 单独列出退出状态的容器按创建时间排序找出最近谁挂过 docker ps -a --filter statusexited --format {{.Names}} {{.Status}} ({{.FinishedAt}})STATUS这一列是重点Up 3 hours正常Restarting (1) 5 seconds ago说明容器在崩溃重启循环要马上看日志Exited (0)是主动退出通常没问题Exited (137)是被kill常见原因是OOM或有人执行了docker stop。这里有个细节容易翻车Up不等于健康它只表示进程还在进程内线程池满不满、接口通不通docker ps看不出来要靠日志和业务探活。资源水位用docker stats看# --no-stream 只输出一次统计避免刷屏 docker stats --no-stream --format table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}\t{{.MemPerc}}MemUsage是“当前使用/硬性限制”两段式。如果容器limit没设就是宿主机全部内存一旦Java应用堆开得大宿主机Swap会被打满。巡检时别只看百分比还要看MemUsage左边的绝对值一个容器占宿主机8G内存即使只有容器limit的40%对整台机器也是巨大压力。CPU持续多轮巡检超过80%且不是业务高峰就要怀疑循环任务或垃圾回收风暴。PIDS列也值得看线程数异常上涨通常是连接池泄漏。3.2 docker logs与docker events日志是出事后线的第一现场docker logs是排障第一现场。容器重启过ps里只能看到Restarting具体为什么崩溃全在日志里。日常巡检不用全量捞日志捞最近N行就够# 查看最近200行日志并带时间戳确认崩溃时间点 docker logs --tail 200 --timestamps myapp # 按关键词过滤适合发现持续性报错 docker logs --tail 1000 myapp 21 | grep -iE error|exception|panic | tail 50--tail控制行数防止几万行的日志刷爆终端--timestamps必须加没有时间线的日志等于没日志21把stderr和stdout合并Java和Node.js的堆栈常写stderr不合并会漏掉一半信息。--since 30m只看最近半小时比全量捞再过滤快得多。再提醒一次默认的json-file日志驱动会写本地文件容器每秒钟打几百行日志/var/lib/docker/containers下会堆出几个G磁盘告警很多是从这来的。docker events是另一个维度的巡检。它记录容器生命周期事件创建、销毁、重启、OOM、kill。我习惯每次巡检先回看一小时内的异常事件# 只看退出和OOM两类事件通常都对应真实故障 docker events --since 1h --filter eventdie --filter eventoomeventdie是容器退出eventoom是被系统OOM Killer干掉。这两个事件在巡检窗口里频繁出现说明宿主机内存可能已经紧张到内核出手杀进程。此时配合dmesg | grep -i oom看完整上下文能确认是哪类进程吃掉了内存。3.3 别忘了巡检docker daemon自己磁盘、驱动与配置容器全正常不代表Docker本体没问题daemon是容器共同的父进程它挂了容器全灭。我巡检daemon时按顺序看三样东西daemon活没活、磁盘还剩多少、存储驱动有没有隐患# 查看daemon状态和关键配置信息 systemctl status docker docker info --format {{.ServerVersion}} {{.StorageDriver}} # 查看docker目录占用镜像和日志可能吃满根分区 du -sh /var/lib/docker 2/dev/nulldocker info的输出里值得盯的是Storage Driveroverlay2是当前主流看到devicemapper要尽快规划迁移。磁盘方面/var/lib/docker不受控制地增长主要来源是构建镜像的历史层残留和日志文件。前者用docker system prune清理悬空镜像后者靠日志驱动配置限制单文件大小。daemon.json里如果改过iptables或bridge相关配置容器网络行为会突变这个问题在5.3展开。注意生产环境不要随手执行docker system prune -a它会连没有被容器引用的镜像层一起删如果镜像仓库里正好没有这个tag后悔药都没有。先docker system df看空间分布再决定清理策略。4. Kubernetes集群巡检从Pod状态看到节点水位再看到控制面Kubernetes的巡检视角比Docker高一层。Docker关心的是单个容器Kubernetes要关心的是集群整体节点状态、Pod分布、控制面健康。这三层缺一不可顺序上我是先看整体再看个体最后才看控制面。4.1 kubectl get nodes与kubectl top先看集群水位第一条命令一定是kubectl get nodes而且要看宽格式# 查看节点状态、版本和角色-o wide额外输出内网IP kubectl get nodes -o wide # 节点资源水位请求量、限制量、实际使用量都在这里 kubectl top nodesSTATUS列健康值是Ready但只看Ready不够。VERSION列多个节点版本参差升级时容易出兼容性问题ROLES列master和worker混跑调度器行为会变复杂。再看kubectl top nodes它输出每台节点的CPU和内存请求量、限制量和实际用量。重点盯两个数字实际用量是否逼近节点容量以及requests总量是否超过节点可分配资源。requests总和超过100%节点表面还是Ready实际调度器已经塞不进新Pod滚动更新和扩容都会卡住。这个巡检环节里还有个容易漏掉的点节点磁盘和镜像空间。kubelet默认--image-gc-high-threshold是85%磁盘用到85%才开始回收镜像平时不显眼一旦出现“no space left on device”就是事故先兆。所以我的巡检清单固定有一项# 通过ssh批量看节点磁盘水位 for h in node1 node2 node3; do ssh $h df -h / /var/lib/docker /var/lib/kubelet done节点NotReady的原因大体集中在四类kubelet挂了、磁盘满、网络分区、证书过期。前两种系统日志里直接能看到后两种表现很像排查时优先确认。4.2 Pod的重启次数与镜像拉取kubectl describe才是排障主力节点没问题之后看Pod。kubectl get pods -A是每天都会敲的命令但大多数人只看READY列忽略RESTARTS列。我的习惯是全集群扫一遍重启次数异常高的Pod用这步立刻锁定怀疑对象# 列出所有命名空间的Pod按重启次数倒序 kubectl get pods -A --sort-by.status.containerStatuses[0].restartCount -o wide--sort-by用JSONPath把restartCount取出来排序每次巡检扫一遍排在最前面的就是重点排查对象。这里有个新手常踩的坑RESTARTS指容器重启次数不是Pod重启次数一个Pod里两个容器时列表只显示一个数字明细要往下看。下一步用kubectl describe pod做精准定位# 看事件、镜像、探针、卷挂载的完整现场 kubectl describe pod pod-name -n namespacedescribe输出的Events段是排障主战场。CrashLoopBackOff背后原因基本三类启动命令crash、镜像拉取失败、探针太激进把健康进程杀掉。镜像拉取失败时Events里会出现Failed to pull image和错误码manifest unknown是tag不存在denied是仓库认证失效no space left on device是磁盘满。探针问题要同时看Liveness probe failed和日志里进程是否真的存活别看到probe failed就削阈值先确认业务进程有没有假死。4.3 控制面与etcd的巡检preflight只是入场券不是护身符很多同事对Kubernetes的巡检止于Pod和节点但控制面才是“平时不出声、出事就全挂”的部分。初装集群时kubeadm init会输出类似[init] using kubernetes version: v1.26.0 [preflight] running pre-flight checks的检查清单——网络、端口、cgroup驱动、交换分区全过一遍集群才拉得起来。可问题是preflight只在init和join时跑一次运行一年后环境早变了iptables被改写、证书快过期、etcd磁盘快满这些preflight没覆盖。我有个季度级控制面巡检清单# 查看控制面组件状态新版已标记废弃但很多环境仍可用 kubectl get componentstatuses # 检查证书剩余有效期很多人栽在这上面 kubeadm certs check-expiration # etcd健康检查能返回health就说明leader在线 ETCDCTL_API3 etcdctl endpoint health --endpointshttps://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证书这个坑值得多说。kubeadm一年的某个时间点kubelet和apiserver证书会集体到期现象是节点状态莫名飘红、kubectl logs拉不下来稍不注意就被当成网络问题排查好几天。kubeadm certs check-expiration是我每季度必跑的。etcd方面重点看健康和磁盘使用率etcd数据目录增长过快会造成读写延迟进而拖垮整个kube-apiserverdu -sh /var/lib/etcd就能提前发现。提示kubectl get componentstatuses在Kubernetes 1.20后被官方废弃有些环境输出永远是空的。不用慌改用kubectl get --raw/healthz直接探apiserver的健康状况效果一样。5. Docker和Kubernetes巡检路上的翻车现场5个高频坑与排查路径巡检本身不难难的是踩过的坑不踩第二次。下面五个坑是我见过最多、也是网上提问最频繁的方向每个都给出现象、原因和解法。5.1 现象Docker Desktop启动失败报“virtualization support not detected”Windows上装Docker Desktop最常见的报错就是virtualization support not detected。原因是两层BIOS里虚拟化被关了或者Windows的Hyper-V/WSL2功能没启用。Docker Desktop的Linux容器跑在虚拟化层上没有CPU虚拟化支持就像没有发动机怎么启动都白搭。解决路径按顺序来先在BIOS里开启Intel VT-x或AMD SVM并在任务管理器“性能”页确认虚拟化显示“已启用”然后在“启用或关闭Windows功能”里勾上“适用于Linux的Windows子系统”和“虚拟机平台”最后在PowerShell里执行wsl --status确认发行版存在内核太旧就wsl --update。这三步走完再启动九成的启动失败都能解决。剩下的极少数是Docker Desktop安装损坏卸载重装即可。5.2 现象docker服务启动失败systemctl里一片红Linux下systemctl start docker失败第一反应该是看daemon日志不是反复重启服务反复试。daemon启动失败的高频原因三种daemon.json写错、iptables规则冲突、存储驱动在挂载点上不可用。解决路径先journalctl -u docker --since 10 minutes ago | grep -i error看daemon在哪个环节挂掉如果错误指向daemon.json用dockerd --validate单独校验配置文件语法不用重启服务改错如果指向iptables说明有别的组件改写了NAT链承接5.3细说。还有一种常见情况是/var/lib/docker所在分区不支持overlay2docker info直接报backing filesystem is unsupported这时要换分区或换存储驱动没有第三条捷径。5.3 现象容器内部通、外部不通docker网络像是断了最难受的坑容器里去连外网、连别的容器都通但从宿主机或外部访问它就是不通。原因通常是端口映射被防火墙挡了或宿主机的iptables NAT规则被docker之外的进程改写。Docker daemon启动时维护一套自己的iptables规则网firewalld在docker之后启动或者有人手动清过规则桥接网络的SNAT和DNAT就废了。解决路径先docker port 容器名确认映射存在再iptables -t nat -L DOCKER -n看规则有没有被清掉规则在再查宿主机防火墙是否放行端口云服务器还要确认安全组同步放行。最不推荐的做法是一通操作后重启docker服务恢复网络——那等于把所有容器的连接全部掐断重建业务侧叫苦不迭。正确做法是定位哪条链被冲突只修对应链。5.4 现象docker pull镜像龟速像回到了拨号时代镜像下载慢是每个刚接触Docker的人都会遇到的现实原因很简单默认镜像源在你网络环境下往返延迟太高。第一个动作永远是检查是不是在反复拉大镜像而不是增量拉取——Docker按层拉取本地已经有上一层就只下载新增层很多“慢”其实是本地没有该层导致的全量下载。解决路径是给dockerd配置registry mirror。在/etc/docker/daemon.json里加registry-mirrors数组填上你网络环境下访问延迟低的镜像仓库地址然后重启docker{ registry-mirrors: [https://your-reachable-mirror.example.com] }注意两点mirror只对docker pull生效docker push不走它私有仓库也不会自动走mirror。配置后用docker info确认镜像源已经生效再实际pull一次小镜像验证速度。选择mirror地址时别堆太多一两个稳定可达的就够先用curl -o /dev/null -s -w %{time_total}测一下延迟再写进配置。5.5 现象Pod反复重启kubectl get pods里RESTARTS疯涨Kubernetes里看到CrashLoopBackOff第一反应别是kubectl delete pod删了也没用控制器会再拉一个新的问题原封不动回来。先看这个Pod被谁管理Deployment、StatefulSet还是DaemonSet再去describe里找根因。kubectl describe pod看Events是第一步看退出码是第二步。Kubernetes会按指数退避自动重启从10秒开始每次翻倍封顶300秒所以RESTARTS的上涨是有韵律的。退出码137说明被OOM或节点重启杀掉退出码1说明应用启动即崩去看应用日志里的报错128加信号码的组合比如137就是1289说明被kill。定位到根因之前反复删Pod只会让RESTARTS清零再涨没有实际意义。找到日志中的真实报错修应用或调整资源request/limit才是停止循环的唯一路径。6. 把巡检变成每天自动跑一遍的脚本cron定时与核心检查项手动巡检最大的问题是今天做了明天就忘三天后连命令都懒得敲。我自己的做法是把最核心的检查项写成一个bash脚本crontab每天早上执行产出固定格式的文本日志。脚本不需要很复杂覆盖“宿主磁盘、容器异常状态、Kubernetes节点和Pod状态”四件事就够#!/bin/bash # daily-check.sh —— 每天早上跑的Docker/Kubernetes巡检脚本 LOG/var/log/ops/daily-check-$(date %F).log { echo $(date %F %T) 巡检开始 df -h / | tail -1 docker ps -a --format {{.Names}}\t{{.Status}} | grep -vE Up [0-9] (second|minute) || true docker stats --no-stream --format {{.Name}}\t{{.MemPerc}} | awk -F\t $2 85 {print $0} kubectl get nodes kubectl get pods -A -o wide | grep -E CrashLoopBackOff|Error|Pending || true echo 巡检结束 } $LOG 21脚本逻辑第一段检查根分区和Docker目录容量第二段找出启动不足一分钟的容器——刚重启完的容器会出现一次但连续两次巡检都出现说明正在反复重启第三段过滤内存超85%的容器最后两段是Kubernetes最小集检查把异常状态的Pod捞出来。加入crontab -e每天早上8点跑日志保留30天。验证方法很简单手动执行一次脚本确认日志有内容、格式没乱连续看三天的数据。再往后可以升级成把异常结果转成一条webhook通知到日常沟通工具里但优先级不高先把日志体系跑通。做巡检这些年我最深的体会是巡检的价值不在于每天发现大故障而在于发现“昨天和今天不一样”。Docker和Kubernetes的世界里多数故障都是渐变积累出来的磁盘多涨三个百分点、某个Pod比昨天多重启两次这些才是巡检要抓的信号。脚本不怕简陋就怕没有数据不怕少就怕不连贯。希望你也能把这套东西落到自己的集群里把凌晨的闹钟换成早上的日志文件希望帮到你。本文还有配套的精品资源点击获取