webman不能直接用php:8.2-apache或fpm镜像,因二者禁用pcntl/posix且进程模型冲突,必须基于php:8.2-cli自建镜像,关闭zts后安装扩展,用exec启动并配置健康检查与非root用户。

Webman 不能直接用 php:8.2-apache 或 php:8.2-fpm 镜像跑起来——容器会秒退,docker logs 只显示一行 Starting webman 就没了。根本原因是 Webman 依赖 pcntl 和 posix 扩展实现多进程管理,而 Apache/FPM 镜像默认禁用 pcntl,且进程模型与常驻 CLI 模式冲突。
为什么必须用 php:8.2-cli 自建镜像
官方 php:8.2-apache 在构建时启用了 ZTS(线程安全),导致 docker-php-ext-install pcntl 直接报错:configure: error: pcntl extension cannot be built when ZTS is enabled;php:8.2-fpm 虽能装上 pcntl,但其 master-worker 进程结构会 hijack SIGTERM 信号,使 php start.php restart 失效,也无法响应 Docker 的健康检查。
-
php:8.2-cli默认支持 ZTS 关闭(需显式加--disable-zts),可稳定编译pcntl/posix - CLI 模式下
exec启动能保证 PID 1 是 Webman 主进程,Docker 信号(如stop)可直达 - 无需 Nginx/Apache 层——Webman 自带 HTTP 服务器,端口直曝即可,加反向代理纯属冗余(除非你已有统一网关)
Dockerfile 四个不可省的动作
最小可行镜像不是“能跑就行”,而是要满足生产级常驻服务要求。以下四步缺一不可:
使用 Python 脚本下载 Docker 镜像并打包为 tar 文件。用户说“下载镜像”“拉取镜像”“pull xxx”“帮我下载 nginx 镜像”等时触发。支持 SOCKS5 代理直连(推荐)和国内镜像站加速两种模式。
- 用
FROM php:8.2-cli --disable-zts构建基础层(注意:必须在docker build命令中传参,或改用php:8.2-cli-bullseye+ 手动apt install) - 显式执行
docker-php-ext-install pcntl posix,别信“某些镜像已预装”——版本不匹配会导致fork()失败 - 设置关键 PHP 配置:
opcache.enable_cli=1、memory_limit=-1、max_execution_time=0,写进/usr/local/etc/php/conf.d/99-webman.ini - 入口命令必须是
ENTRYPOINT ["php", "/app/start.php", "start", "-d"],不能用CMD——否则docker stop无法触发平滑退出
docker-compose.yml 健康检查怎么写才有效
很多人的健康检查只写 curl -f http://localhost:8787/ping,但 Webman 默认的 /ping 路由不校验 Worker 进程存活,容器可能“活着却挂了”。真正有效的检查必须穿透到进程层:
- 用
healthcheck:下的test: ["CMD-SHELL", "kill -0 $$(cat /app/runtime/master.pid) 2>/dev/null || exit 1"],直接验证主进程是否存在 - 超时设为
timeout: 5s,间隔interval: 10s,失败阈值retries: 3,避免因瞬时 GC 导致误判 - 若你启用了
webman-plugin-redis等状态插件,可追加&& redis-cli -h redis ping | grep PONG确保共享存储连通
Kubernetes 部署时最易忽略的两个配置点
把 Webman 推进 K8s 不是照搬 Deployment YAML 就完事。两个硬性约束常被跳过,导致滚动更新卡死或 Pod 反复重启:
-
lifecycle.preStop必须定义:exec: { command: ["/bin/sh", "-c", "php /app/start.php stop && sleep 10"]——给 Worker 进程留出 graceful shutdown 时间,否则 K8s 强杀会丢请求 - Pod 必须加
securityContext.runAsNonRoot: true且指定runAsUser: 1001,因为 Webman 的runtime/目录需写入 PID 文件,root 用户运行会导致权限混乱,后续扩容新 Pod 无法复用 PVC
Webman 容器化真正的难点不在构建镜像,而在于让常驻进程语义与容器生命周期对齐——信号传递、PID 1 管理、健康探针设计,每一步都得抠到内核级行为。随便套个镜像模板,上线后只会遇到“容器绿着,服务黑着”的诡异现场。










