《Docker 运维入门实战:日志 + 健康检查,出问题先知道去哪看》

举报
yd_274623194 发表于 2026/10/29 09:47:28 2026/10/29
【摘要】 关键词:docker compose logs、健康检查、healthcheck、日志轮转上一篇我们把服务收敛成了一个入口:网关 Nginx 在前,web 和 api 在后,HTTPS 也接上了。但到这里还缺运维最关键的一环——服务一旦出问题,你怎么第一时间发现、又去哪里看原因?靠"感觉不对就重启"是最贵的排查方式。今天给这套 my-app 加上两样东西:日志查看和健康检查。本文接着前面的结...

关键词:docker compose logs、健康检查、healthcheck、日志轮转

上一篇我们把服务收敛成了一个入口:网关 Nginx 在前,web 和 api 在后,HTTPS 也接上了。但到这里还缺运维最关键的一环——服务一旦出问题,你怎么第一时间发现、又去哪里看原因?靠"感觉不对就重启"是最贵的排查方式。今天给这套 my-app 加上两样东西:日志查看和健康检查。

本文接着前面的结构讲:gateway(Nginx 网关)、web(静态网页)、api(8000 端口的 Python 接口服务),假设服务器上已经装好 Docker 和 Docker Compose。

一、先看日志:别进容器翻文件

容器里的进程往标准输出打的日志,Docker 都替你收着,不用进容器找日志文件。最常用的就几条:

docker compose logs              # 看所有服务的日志
docker compose logs api          # 只看 api
docker compose logs -f api       # 跟踪实时输出,相当于 tail -f
docker compose logs --tail 100 web   # 只看 web 最近 100 行
docker compose logs --since 10m gateway  # 只看网关最近 10 分钟的
docker compose logs -t api       # 每行前面带上时间戳

一个习惯要先养成:出问题先看日志,再决定动不动手。接口 500 了,先 logs api 看报错;网关转发不通,先 logs gateway 看它把请求发到哪去了、后端回了什么状态码。日志里没有报错,再去怀疑配置和网络。

还有一个容易忽略的点:前面 api 的示例代码里把请求日志关掉了(log_message 空实现)。排查阶段建议先把它打开,或者至少让异常和启动信息能打出来——一个从不说话的服务,出问题时你连它死在哪一步都不知道。

二、给日志加个上限:别让它把磁盘吃满

默认情况下容器日志文件会一直增长,跑久了可能把磁盘写满,反过来把服务拖垮。在 docker-compose.yml 里给每个服务加一行日志配置:

services:
  api:
    build: ./api
    logging:
      driver: json-file
      options:
        max-size: "10m"
        max-file: "3"

意思是单个日志文件最多 10MB,轮转保留 3 个,超过就覆盖最旧的。改完重新 docker compose up -d 生效。这一步现在做成本最低——等磁盘报警那天再做,就已经晚了。

三、健康检查:让 Compose 替你判断"活着还是能用"

容器进程在跑,不等于服务能用:接口进程可能卡住了还在监听端口,也可能启动到一半就僵住了。健康检查就是定期在容器里跑一条探活命令,告诉 Compose 这个服务到底健不健康:

services:
  api:
    build: ./api
    healthcheck:
      test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:8000/')"]
      interval: 30s
      timeout: 5s
      retries: 3
      start_period: 10s

逐项看:

  • test:探活命令。python:3.12-alpine 镜像里没有 curl,就用自带的 urllib 发一次请求,能拿到响应才算通过——不要用"进程在不在"代替"接口通不通"。
  • interval: 30s:每 30 秒查一次,别设太密,探活本身也是负载。
  • timeout: 5s:一次探活超过 5 秒就判失败。
  • retries: 3:连续失败 3 次才标记为不健康,避免一次网络抖动就误判。
  • start_period: 10s:启动后 10 秒内即使失败也不计入,给服务留出启动时间。

web 和 gateway 都是 nginx:alpine,里面没有 curl,但有 busybox 的 wget,写法换一下:

  web:
    build: ./web
    healthcheck:
      test: ["CMD", "wget", "-q", "-O", "/dev/null", "http://localhost/"]
      interval: 30s
      timeout: 5s
      retries: 3
      start_period: 10s

四、让网关等后端健康了再启动

健康检查写好后,还能顺手解决一个启动顺序问题:以前网关可能比 api 先起来,前几秒转发过去全是失败。有了健康状态,depends_on 可以改成等后端"健康"再启动:

services:
  gateway:
    image: nginx:alpine
    depends_on:
      web:
        condition: service_healthy
      api:
        condition: service_healthy

注意:condition: service_healthy 只保证启动顺序,不保证运行中后端挂了网关会跟着处理——运行时的故障发现,还是靠日志和健康状态本身。

改完启动并验证:

docker compose up -d
docker compose ps    # STATUS 一列会显示 (healthy) 还是 (unhealthy)
docker inspect my-app-api-1 --format '{{.State.Health.Status}}'

看到 (healthy),这套探活就算通了。故意把 api 的端口改错再启动一次,你会看到它长时间停在 (health: starting) 然后变成 (unhealthy)——这正是健康检查的价值:问题不用等用户报上来,状态里已经写明了。

五、两个新手最容易踩的坑

1. 健康检查命令在镜像里根本不存在

最常见的失败不是服务坏了,是探活命令本身跑不起来:alpine 镜像里写 curl、debian 镜像里写 wget,结果容器一启动就被判不健康。写之前先确认镜像里有什么:docker compose exec api sh 进去试一条,通了再写进配置。

2. 只看健康状态,不看日志

健康检查只能告诉你"不健康",不能告诉你"为什么"。状态变红之后,下一步永远是 docker compose logs 看具体报错——健康检查是报警器,日志才是案发现场。两个配合用,出问题先知道去哪看,而不是凭感觉重启。

结语

从单容器、Compose 编排、数据卷、反向代理和 HTTPS,到今天的日志与健康检查,这条线已经是一套能对外服务、出了问题也能快速定位的部署了。下一篇可以往"怎么更新不中断服务"走一步:改了代码之后,如何滚动更新这几个容器,而不用停掉整个站。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。