Linux下Docker Compose里运行Nginx故障诊断Shell脚本 #!/bin/bash# # Nginx on Docker Compose 故障系统化诊断脚本# 融哲于技本体论、奥卡姆剃刀、辩证法、实用主义、道家无为、整体论# # 功能针对 Docker Compose 管理的 Nginx 服务意外中断进行系统化取证与诊断# 使用./nginx_diagnose.sh [容器名或服务名默认尝试自动探测]# 要求在 docker-compose.yml 所在目录或通过环境变量指定安装 docker 与 jq可选set-opipefail# --- 颜色定义 ---RED\033[0;31mGREEN\033[0;32mYELLOW\033[1;33mBLUE\033[0;34mNC\033[0m# No Color# --- 参数/变量 ---TARGET${1:-nginx}# 目标服务名或容器名COMPOSE_CMDdocker compose# 优先使用 Docker Compose v2CONTAINER_IDEXIT_CODEOOM_KILLED# 实用主义检查 docker 命令是否存在如不存在则提示并退出if!command-vdocker/dev/null;thenecho-e${RED}[错误] 未找到 docker 命令请确认 Docker 已安装。${NC}exit1fi# 确定 docker compose 命令可用形式奥卡姆剃刀用最简方式if!dockercompose version/dev/null;thenifcommand-vdocker-compose/dev/null;thenCOMPOSE_CMDdocker-composeelseecho-e${YELLOW}[警告] 未检测到 docker compose将跳过 compose 相关操作。${NC}COMPOSE_CMDfifiecho-e${BLUE} Nginx 故障诊断开始目标${TARGET}${NC}# # 步骤1本体论定性 —— 界定“实体”的存在性与状态# 哲学依据本体论追问“何物存在”。只有先确定容器这一实体的本质状态# 不存在/Exited/Running 但无响应才能锁定正确的排查方向。# echo-e\n${GREEN}[步骤1] 本体论定性确认容器存在与状态${NC}# 尝试通过 docker compose 获取容器 ID若服务名准确if[-n$COMPOSE_CMD];thenCONTAINER_ID$($COMPOSE_CMDps-q$TARGET2/dev/null)fi# 如果未获取到尝试直接通过名称查找容器本体论实体可能独立于 composeif[-z$CONTAINER_ID];thenCONTAINER_ID$(dockerps-a--filtername${TARGET}--format{{.ID}}|head-1)fiif[-z$CONTAINER_ID];thenecho-e${RED}[本体论判定] 实体不存在未找到名称包含 ${TARGET} 的容器。${NC}echo-e${YELLOW}手工检验步骤请确认服务名是否正确尝试 docker ps -a 查看所有容器。${NC}exit1fi# 获取容器状态用于本体论区分CONTAINER_STATE$(dockerinspect--format{{.State.Status}}$CONTAINER_ID2/dev/null)echo-e容器 ID:${CONTAINER_ID}echo-e容器状态:${CONTAINER_STATE}case$CONTAINER_STATEinrunning)echo-e${YELLOW}[本体论判定] 实体存续但可能存在功能异常服务不可用。${NC}echo-e${YELLOW}手工检验步骤检查容器内 Nginx 进程是否正常监听端口${NC}echo docker exec${CONTAINER_ID}netstat -tulpn | grep nginxecho-e${YELLOW}检查健康检查日志/状态docker inspect${CONTAINER_ID}| jq .[0].State.Health${NC};;exited)echo-e${RED}[本体论判定] 实体已终止Exited进程生命周期结束需排查死亡原因。${NC};;*)echo-e${RED}[本体论判定] 实体状态异常${CONTAINER_STATE}${NC};;esac# # 步骤2实用主义快速取证 辩证法权衡保留现场 vs 快速恢复# 哲学依据实用主义主张最小可行操作获取最大效果。# 辩证法承认“恢复业务”与“深挖根因”的矛盾抓大放小——先花30秒取证。# echo-e\n${GREEN}[步骤2] 实用主义快速取证瞬时证据收集${NC}# 无论容器是否退出我们都收集一些不会消失的瞬时信息echo-e${BLUE}2.1 检查容器 OOMKilled 标记与退出码${NC}INSPECT_OUT$(dockerinspect$CONTAINER_ID2/dev/null)OOM_KILLED$(echo$INSPECT_OUT|jq-r.[0].State.OOMKilled2/dev/null)EXIT_CODE$(echo$INSPECT_OUT|jq-r.[0].State.ExitCode2/dev/null)if[$OOM_KILLEDnull]||[-z$OOM_KILLED];then# jq 不可用时的回退奥卡姆剃刀最简方法OOM_KILLED$(dockerinspect--format{{.State.OOMKilled}}$CONTAINER_ID2/dev/null)EXIT_CODE$(dockerinspect--format{{.State.ExitCode}}$CONTAINER_ID2/dev/null)fiecho OOMKilled:$OOM_KILLEDecho ExitCode :$EXIT_CODEecho-e\n${BLUE}2.2 收集最近的容器日志最后50行${NC}if[-n$COMPOSE_CMD];then$COMPOSE_CMDlogs--tail50$TARGET2/dev/null||\dockerlogs--tail50$CONTAINER_ID2/dev/nullelsedockerlogs--tail50$CONTAINER_ID2/dev/nullfiecho-e\n${BLUE}2.3 收集系统内核日志尾部dmesg关联 OOM 等${NC}dmesg-T|tail-302/dev/null||dmesg|tail-30# 辩证法此时我们已握有关键证据是否立即重启以恢复服务if[$CONTAINER_STATEexited];thenecho-e\n${YELLOW}[辩证法权衡] 容器已停止已收集关键瞬时数据。${NC}echo-e${YELLOW}手工决策是否现在就重启服务(重启可快速恢复业务但可能丢失部分现场)${NC}echo-e${YELLOW}若需重启可执行${NC}if[-n$COMPOSE_CMD];thenecho${COMPOSE_CMD}restart${TARGET}elseecho docker restart${CONTAINER_ID}fiecho-e${YELLOW}建议若业务受损持续先执行重启保留本脚本输出用于事后分析。${NC}fi# # 步骤3奥卡姆剃刀分流 —— 根据最简证据直接导向根因# 哲学依据“如无必要勿增实体”。根据退出码与 OOMKilled 直奔最常见病因# 避免盲目执行大量无关检查。# echo-e\n${GREEN}[步骤3] 奥卡姆剃刀分流诊断${NC}# 手工检验步骤提醒如果需要更详细的 Nginx 错误日志可进入容器或宿主机挂载卷查看echo-e${YELLOW}手工检验路径Nginx 错误日志可能位于容器内 /var/log/nginx/error.log 或宿主机挂载卷。${NC}echo docker exec${CONTAINER_ID}cat /var/log/nginx/error.log (若容器可运行)echo 或检查数据卷位置docker inspect${CONTAINER_ID}| jq .[0].Mountsif[$OOM_KILLEDtrue];then# -------------------------------# 3a. 内存耗尽OOM Killer# 奥卡姆剃刀OOMKilledtrue问题就是内存不足无需先查磁盘# -------------------------------echo-e\n${RED}[奥卡姆剃刀] OOMKilledtrue容器因内存不足被宿主机杀死。${NC}echo-e${BLUE}3a.1 检查系统 OOM 日志找出被杀进程详情${NC}echo-e${YELLOW}手工检验步骤执行以下命令查看 OOM 记录确定是 Nginx 自身还是其他进程耗尽内存。${NC}echo grep -i out of memory /var/log/messages /var/log/syslog 2/dev/nullecho dmesg | grep -i oom# 自动提取最近一次 OOM 事件整体论关联容器死亡时间echo-e${BLUE}尝试自动提取相关 OOM 记录${NC}dmesg|grep-ikilled process|tail-5echo-e\n${BLUE}3a.2 当前宿主机内存状态${NC}free-hecho-e\n${BLUE}3a.3 检查 docker-compose 文件中的内存限制${NC}echo-e${YELLOW}手工检验步骤查看 docker-compose.yml 中 nginx 服务的 mem_limit 或 deploy.resources.limits.memory${NC}echo grep -A 10 ${TARGET}: docker-compose.ymlecho-e\n${YELLOW}[辨证分析] 如果 Nginx 内存配置合理则可能是其他容器内存泄漏拖垮宿主机。${NC}echo 检查所有容器内存使用: docker stats --no-streamelif[$EXIT_CODE137];then# 退出码 137 1289 (SIGKILL)很大概率也是 OOM但 OOMKilled 字段可能为 false如 docker killecho-e${RED}[奥卡姆剃刀] 退出码 137 (SIGKILL)可能原因OOM Killer 或手动 docker kill。${NC}echo-e${YELLOW}请结合上面收集的 dmesg 判断是否存在 OOM 记录。若无则可能是人为或编排系统杀死。${NC}else# -------------------------------# 3b. 应用自身错误或配置问题# 奥卡姆剃刀直接查看 Nginx 错误日志中的 crit/error 级别信息# -------------------------------echo-e\n${BLUE}3b.1 奥卡姆剃刀直接从容器日志中检索关键错误${NC}# 尝试从之前收集的日志或重新获取dockerlogs$CONTAINER_ID21|grep-iEemerg|alert|crit|error|tail-20echo-e${YELLOW}手工检验步骤如果上述信息不足请进入宿主机挂载卷查看完整 error.log。${NC}echo-e\n${BLUE}3b.2 常见应用错误分流${NC}# 检测典型错误模式实用主义基于常见问题模式匹配ERR_LOG$(dockerlogs$CONTAINER_ID21)ifecho$ERR_LOG|grep-qino space left on device;thenecho-e${RED}[磁盘空间] 日志中检测到 No space left on device${NC}echo-e${YELLOW}奥卡姆剃刀直接检查磁盘空间与 inode。${NC}echo-e${BLUE}磁盘空间检查${NC}df-hecho-e\n${BLUE}Inode 检查${NC}df-iecho-e${YELLOW}手工检验步骤检查 Nginx 日志目录是否占用大量 inode执行${NC}echo ls -l /path/to/mounted/logs | wc -lelifecho$ERR_LOG|grep-qipermission denied;thenecho-e${RED}[权限问题] 日志中检测到 Permission denied${NC}echo-e${YELLOW}手工检验步骤检查容器内 nginx 用户 uid 与挂载卷权限的匹配。${NC}echo docker exec${CONTAINER_ID}id nginx (若容器可运行)echo 检查宿主机挂载目录权限: ls -ld /宿主机/挂载点elifecho$ERR_LOG|grep-qiaddress already in use;thenecho-e${RED}[端口冲突] 检测到端口被占用。${NC}echo-e${YELLOW}手工检验步骤查看当前端口监听情况${NC}echo netstat -tulpn | grep 端口号elifecho$ERR_LOG|grep-qicannot open.*certificate\|ssl;thenecho-e${RED}[证书/配置问题] 检测到 SSL 证书或相关错误。${NC}echo-e${YELLOW}手工检验步骤验证证书文件是否存在及权限执行 docker exec${CONTAINER_ID}ls -l /etc/nginx/certs${NC}fifi# # 步骤4整体论关联资源与系统状态# 哲学依据整体论告诉我们系统大于部分之和。容器死亡可能与宿主机 CPU、磁盘或# 其他服务的交互涌现行为相关必须进行关联分析。# echo-e\n${GREEN}[步骤4] 整体论资源与状态关联分析${NC}echo-e${BLUE}4.1 宿主机全局资源视图${NC}echoCPU 和内存摘要top-bn1|head-5echo-e\n磁盘使用df-hecho-e\nInode 使用df-iecho-e\n${BLUE}4.2 Docker 整体状态${NC}dockerstats --no-stream--all2/dev/null|head-10echo-e\n${BLUE}4.3 寻找与故障时间吻合的系统事件整体论关联${NC}echo-e${YELLOW}手工检验步骤确定容器退出时间与系统日志/监控图表进行比对。${NC}FINISHED_AT$(dockerinspect--format{{.State.FinishedAt}}$CONTAINER_ID2/dev/null)echo 容器退出时间:$FINISHED_ATecho 请检查以下内容在该时间点前后是否有异常echo - 系统日志: journalctl --since\YYYY-MM-DD HH:MM:SS\--until\...\echo - Docker 守护进程日志: journalctl -u dockerecho - 监控系统 CPU/磁盘 I/O 尖刺# # 步骤5整体论人工深入 —— 全链路与涌现行为# 哲学依据整体论要求跨服务视图单体日志无异常时可能是上游超时或# 调用链累积延迟导致的涌现行为。# echo-e\n${GREEN}[步骤5] 整体论人工检验全链路与涌现行为${NC}echo-e${YELLOW}如经上述检查仍未定位根因请执行以下分布式系统排查${NC}echo1. 全链路追踪检查echo - 在分布式追踪系统如 Jaeger, Zipkin中查找故障时间窗的 trace。echo - 定位慢请求查看 Nginx 上游调用耗时是否超出 proxy_read_timeout 等设置。echo2. 上游服务状态echo - 检查 Nginx 代理的所有 upstream 服务在故障时刻的健康状况。echo - 是否存在级联超时或线程池耗尽。echo3. 网络连接echo - 检查容器间网络是否稳定有无丢包或防火墙规则变动。echo4. 配置文件变更历史echo - 结合版本控制查看 nginx.conf 及 docker-compose.yml 的近期变更。# # 步骤6道家无为 —— 从源头构建韧性# 哲学依据最好的排查是不必排查。“无为”倡导顺应故障必然发生的天道# 通过自愈、限制和隔离来让系统自然恢复。# echo-e\n${GREEN}[步骤6] 道家无为构建韧性系统建议${NC}echo-e${YELLOW}请检查并实施以下优化以减少未来紧急排查${NC}echo1. 自愈重启策略echo 在 docker-compose.yml 中添加 restart: unless-stopped 或 alwaysecho2. 资源限制echo 为 Nginx 服务设置合理的内存/CPU 限制 (mem_limit, cpus)。echo3. 健康检查echo 配置 Docker 健康检查 (healthcheck) 使编排系统能自动重启不健康的容器。echo4. 日志轮转echo 确保容器日志及 Nginx 访问日志配置了轮转避免磁盘/inode 耗尽。echo5. 混沌工程验证echo 在测试环境定期注入故障杀容器、断网验证系统自愈能力。echo-e\n${BLUE} 诊断脚本执行完毕 ${NC}echo-e${GREEN}请根据上述输出和手工检验步骤继续深入分析。${NC}