Webman 默认不暴露健康检查接口,需手动添加轻量无副作用的 HTTP 端点(如 /healthz 和 /readyz),否则 K8s 探针会因 404/500/超时反复失败,导致 Pod 重启或被剔除。

Webman 默认不暴露健康检查接口,K8s 的 livenessProbe 和 readinessProbe 无法直接使用 —— 必须手动添加轻量、无副作用的 HTTP 端点,否则探针会一直失败,导致 Pod 反复重启或被 Service 剔除。
为什么 Webman 没有内置 /healthz?
Webman 是轻量级 PHP 框架,设计上不强制内置运维接口。它的启动快、无复杂依赖初始化,但「启动完成」不等于「能稳定处理请求」:比如你加了数据库连接池、Redis 初始化、配置热加载等逻辑,这些可能在首次请求时才触发,而 K8s 探针在容器启动后几秒就开始探测。
若没提供明确的健康端点,httpGet 探针访问任意路径(如 /)可能返回 404、500 或超时,尤其在刚启动时 —— 这不是框架缺陷,而是职责未显式声明。
怎么加一个安全可用的健康检查接口?
推荐在 app/Controller/HealthController.php 中新增一个纯响应控制器,不查库、不读文件、不调外部服务,只返回固定 JSON 和 200 状态码:
namespace app\Controller;
use support\Request;
class HealthController
{
public function liveness(Request $request)
{
return json(['status' => 'ok', 'probe' => 'liveness']);
}
public function readiness(Request $request)
{
// 可选:这里可加入轻量依赖检查,比如 Redis ping 或 DB ping(需控制超时)
// 但生产环境建议 readiness 比 liveness 更严格,且必须有 fallback
return json(['status' => 'ok', 'probe' => 'readiness']);
}
}
再在 config/route.php 中注册路由(注意不要带中间件):
Route::get('/healthz', [app\Controller\HealthController::class, 'liveness']);
Route::get('/readyz', [app\Controller\HealthController::class, 'readiness']);
-
/healthz仅确认进程存活,不做任何业务判断 -
/readyz可扩展检查关键依赖,但必须保证响应快("status": "degraded") - 切勿复用
/或业务路由做健康检查 —— 它们可能含鉴权、日志、慢查询,导致探针误判
YAML 配置里最容易错的三个参数
K8s 探针行为高度依赖参数组合,PHP 应用因启动快、无 JVM 预热,initialDelaySeconds 往往设得太小,而 failureThreshold 又太激进:
-
initialDelaySeconds: 5—— Webman 启动极快,但 Worker 进程 fork、EventLoop 初始化仍需时间,设 3 秒常导致首次探测就失败;建议从5起步,观察kubectl logs -f确认首条请求时间 -
periodSeconds: 10—— 太频繁会增加 Webman 事件循环压力,尤其高并发下;低于 5 秒不建议,除非是 debug 场景 -
failureThreshold: 3—— 连续 3 次失败即重启容器,对 PHP-FPM 类模型尚可,但 Webman 是常驻内存模型,一次临时 GC 或 IO 小抖动就触发重启,反而放大不稳定性;生产建议设为5或更高,并配合timeoutSeconds: 2
典型配置示例(放在 containers[].livenessProbe 下):
livenessProbe:
httpGet:
path: /healthz
port: 80
initialDelaySeconds: 5
periodSeconds: 10
timeoutSeconds: 2
failureThreshold: 5
readinessProbe 一定要比 livenessProbe 更谨慎
很多团队把两个探针指向同一个 /healthz,结果就绪失败 → 流量剔除 → 请求压到剩余实例 → 其他实例也变慢 → 连锁就绪失败 → 整个服务雪崩。
真正该做的:
-
readinessProbe必须检查真实依赖,比如Redis::ping()、PDO::query("SELECT 1"),但要包 try/catch + 显式返回 200,不能让异常穿透成 500 - 如果依赖暂时不可用(如 DB 主从切换),
/readyz应返回{"status":"degraded","reason":"db_slave_unavailable"}并仍用 200 状态码 —— K8s 只看状态码,不解析 body - 永远不要让
readinessProbe的失败导致容器重启(那是livenessProbe的事),它只管“是否接流量”
最危险的错觉是:「PHP 启动快,所以 readiness 不用检查依赖」—— 实际上线后,第一个请求打进来才发现 Redis 连不上,而这时流量早已涌入。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











