健康检查端点必须用get方法且不带body,frankenphp需自行实现轻量级/health路由,caddy中应显式放行或静态响应,kubernetes探针须配置host头、正确端口及0.0.0.0监听。

健康检查端点必须用 GET 方法且不带 body
FrankenPHP 本身不内置健康检查路由,得自己写。它基于 PHP-FPM + Caddy(或自定义 HTTP 服务器),所以健康检查逻辑要落在 PHP 层——但不能依赖框架中间件(比如 Laravel 的 health 路由),因为 FrankenPHP 启动时可能绕过完整请求生命周期。最稳妥的方式是单独配一个轻量级 GET /health 路由,直接返回 200 OK 和简单 JSON。
常见错误是把健康检查写成 POST 或加了认证头,导致 Kubernetes/LB 探针失败。Caddy 的 reverse_proxy 默认会透传探针请求,但如果你在 Caddyfile 里加了 handle 拦截所有路径,就得显式放行 /health,否则 404。
- 在
public/index.php顶部快速判断:如果$_SERVER['REQUEST_URI'] === '/health'且$_SERVER['REQUEST_METHOD'] === 'GET',立刻http_response_code(200)并exit('{"status":"ok"}'); - 不要调用 ORM、DB 连接或 Redis —— 健康检查不是就绪检查(readiness),它只确认服务进程活着;真要查 DB 就另设
/ready - 别用
die()或exit()带 HTML 内容,LB 探针通常只认纯文本或 JSON,且期望无重定向
在 Caddyfile 中避免健康检查被重写或拦截
FrankenPHP 官方推荐用 Caddy 作前端,而 Caddy 的 php_fastcgi 指令默认会把所有请求转发给 FrankenPHP,包括 /health。这时候 PHP 层能收到,但如果你在 Caddyfile 里写了类似 handle_path /api/* 这类路由分发规则,又没提前匹配 /health,就可能被漏掉或误导向。
正确做法是在 handle 块最前面加一条静态响应:
handle /health {
respond "{'status':'ok'}" 200
header Content-Type application/json
}
这样连 PHP 都不进,更快更稳。注意 respond 是 Caddy v2.6+ 的语法,旧版要用 respond + header 分开写,且必须放在所有 php_fastcgi 规则之前。
- 别在
php_fastcgi块里加transport http相关配置来“代理健康检查”,FrankenPHP 不走 HTTP 回环 - 如果用了
encode zstd或其他压缩,确保/health不被压缩(Caddy 默认不压 JSON,但自定义编码器可能影响) - Caddy 的
reverse_proxy如果用于多实例负载均衡,它的health_uri必须指向这个/health,且协议为http(FrankenPHP 默认监听127.0.0.1:8080)
容器化部署时要同步暴露和探测配置
Docker 或 Kubernetes 里,光有端点不够,还得让编排系统知道怎么探。FrankenPHP 容器默认暴露 80 端口(Caddy),但健康检查的 livenessProbe 和 readinessProbe 必须明确指定 httpGet.path: /health,且不能用 exec 或 tcpSocket —— 因为 FrankenPHP 进程活着不代表 PHP 应用已加载完毕。
Kubernetes 示例关键字段:
livenessProbe:
httpGet:
path: /health
port: 80
httpHeaders:
- name: Host
value: your-domain.com
initialDelaySeconds: 30
periodSeconds: 10
-
Host头很重要:Caddy 是虚拟主机模式,没这个头可能路由到默认站点或 404 - 别设
timeoutSeconds小于 2,FrankenPHP 启动初期可能因 OPCache 编译慢导致首次响应延迟 - 如果用了自签名证书或 HTTP/HTTPS 混合,确保探针走 HTTP(Caddy 默认把 80 重定向到 443,这时要关掉
redir或单独开个 HTTP 端口)
为什么 curl -I http://localhost/health 返回 200 但 K8s 一直重启
最常被忽略的是网络可达性。FrankenPHP 容器里跑的是 Caddy + PHP,而 K8s 的 livenessProbe 是从 kubelet 发起的请求,走的是 Pod 网络栈。如果 Caddy 的 bind 配置写死了 127.0.0.1:80,外部(包括 kubelet)根本连不上。
检查 Caddyfile 的 bind 或 listen 指令:
- 必须是
:80或0.0.0.0:80,不能是127.0.0.1:80 - 如果用了
docker run -p 8080:80,宿主机curl localhost:8080/health能通 ≠ Pod 内部探针能通 - 用
kubectl exec -it <pod> -- curl -v http://localhost/health</pod>在容器内验证,再对比kubectl logs <pod> -c caddy</pod>看访问日志是否出现探针请求
另外,FrankenPHP 的 FRANKENPHP_WORKERS 环境变量设太高可能导致冷启动卡住,探针超时前 worker 还没 ready,看起来就像健康检查失败。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











