容器里的 Python 服务:用标准库做零依赖健康检查
服务上线之后,最先坏掉的往往不是业务接口,而是健康检查。探针路径写错、检查逻辑连了真实数据库、超时时间和编排平台默认值打架,容器会被反复重启,日志里却只有一句 connection refused。这篇笔记只使用 Python 标准库,给一个普通 HTTP 服务加一个可单独探测的 /healthz,并说明容器里应该怎么配。
为什么不要在业务端口里顺手做检查
很多人把健康检查挂在业务路由上,例如访问首页返回 200。这样有三个问题。第一,首页可能依赖模板、静态资源和登录态,探针一多就把这些成本放大。第二,编排系统的探针来自内网,不该走进鉴权和限流。第三,进程还活着但已经不能接新请求时,首页仍可能返回缓存页面,探针会误判为健康。
更稳妥的做法是单独开一个只监听本机的端口,专门回答“进程是否还能工作”。它不访问外网,不写数据库,只看本进程里维护的一个状态位。
一个最小实现
下面的代码把业务状态收成一个线程安全的标志。启动时先标记为未就绪,初始化完成后再打开。探针只读这个标志,因此即使业务端口堵住,检查端口仍然能在几十毫秒内返回。
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
import threading
class State:
def __init__(self):
self._ready = False
self._lock = threading.Lock()
def set_ready(self, value: bool) -> None:
with self._lock:
self._ready = value
def ready(self) -> bool:
with self._lock:
return self._ready
STATE = State()
class Handler(BaseHTTPRequestHandler):
def do_GET(self):
if self.path != "/healthz":
self.send_error(404)
return
ok = STATE.ready()
body = b"ok" if ok else b"starting"
self.send_response(200 if ok else 503)
self.send_header("Content-Type", "text/plain; charset=utf-8")
self.send_header("Content-Length", str(len(body)))
self.end_headers()
self.wfile.write(body)
def log_message(self, fmt, *args):
return
def serve():
httpd = ThreadingHTTPServer(("127.0.0.1", 8081), Handler)
httpd.serve_forever()
if __name__ == "__main__":
threading.Thread(target=serve, daemon=True).start()
STATE.set_ready(True)
threading.Event().wait()
监听地址用 127.0.0.1,是为了避免这个端口被容器网络以外的人扫到。容器编排如果从旁路容器或宿主机来探测,就改成 0.0.0.0,并只在安全组里放行探针网段。
和容器探针配合
存活探针看进程是否该被杀掉,就绪探针看是否可以接流量。两者不要共用同一个过重的检查。建议:
- liveness 访问 /healthz,失败阈值设为 3 次,间隔 10 秒,启动宽限 20 秒。初始化超过这个时间就单独加长宽限,不要把间隔拉到一分钟,否则真死了也要很久才被拉起。
- readiness 使用同一个路径即可,因为未就绪时我们返回 503。流量会暂时摘掉,进程不会被杀。
- 不要在检查里发外部请求。数据库抖动应该体现在业务错误率上,而不是让探针把所有副本同时打成不健康。
如果运行时需要主动熔断,比如连续写失败超过阈值,就调用 STATE.set_ready(False)。就绪探针立刻失败,负载均衡把流量切走,进程仍留在那里排空已有请求。恢复后重新 set_ready(True)。
上线前自己点一次
在容器里执行 curl 访问 127.0.0.1 的 8081 端口。期望看到 HTTP 200 和正文 ok。把 set_ready 那一行临时注释掉,应看到 503 和 starting。这两次结果对上,再交给编排平台。检查端口和业务端口分开,半夜被误重启的次数就会少一点。初始化日志也建议打在标准输出里,方便和探针失败时间对齐。
- 点赞
- 收藏
- 关注作者
评论(0)