Webman集群不能仅靠Portainer点选部署,必须显式安装pcntl/posix扩展、挂载runtime目录、配置init:true和restart:unless-stopped,并禁用内置多进程改用横向扩容,通过Redis共享状态。

不能直接用 Portainer 点几下就跑起 Webman 集群——Webman 的集群依赖 pcntl/posix 扩展、runtime 目录挂载、信号处理和横向扩缩容设计,Portainer 只管容器生命周期,不管这些底层约束。
Webman 容器镜像必须显式编译 pcntl 和 posix
官方 docker-compose.yml 默认用的 PHP 基础镜像(比如 php:8.2-cli)不带 pcntl 和 posix 扩展,而 Webman 启动时会调用 pcntl_fork() 和 posix_kill(),缺一不可。
- 在
Dockerfile里必须写RUN docker-php-ext-install pcntl posix,不能只写pcntl - Alpine 镜像需提前装
gcc和make,否则编译失败:RUN apk add --no-cache gcc make - 验证方式:进容器执行
php -m | grep -E "pcntl|posix",两行都得有输出 - 别用
fpm镜像——Webman 是 CLI 常驻进程,fpm模式收不到SIGTERM,热重载静默失效
docker-compose.yml 缺这三项,Portainer 部署等于裸奔
Portainer 导入或部署服务时,如果原始 docker-compose.yml 没补全这三项,容器重启后日志丢失、缓存重建、健康检查失败、平滑退出失效。
-
restart: unless-stopped:宿主机重启后自动拉起容器,否则服务消失 -
volumes: ["./runtime:/app/runtime"]:强制挂载,否则runtime/log和runtime/cache全丢,路由缓存每次启动都重建 -
init: true:启用容器 init 进程,确保SIGTERM能传给 PHP 主进程,实现优雅退出 - 端口映射必须写成
"8787:8787",别写"8080:8787"后忘了改 Nginx/Traefik 的 upstream;Webman 默认监听0.0.0.0:8787,容器内地址不能改
Portainer 中部署 Webman 多实例要禁用内置多进程
Webman 默认启动带 --process=4 这类参数,在单机 Docker 里开多个 worker 进程,既浪费资源又难监控。容器环境应靠横向扩容,而非单容器内多进程。
- 启动命令必须改为
php start.php start -d,不加--process参数 - 在 Portainer 创建服务时,通过
Replicas设置副本数(如 3),而不是靠一个容器撑多个 worker - 每个实例必须共享 Redis(用于 session、锁、事件广播),否则状态不一致;Portainer 里需额外部署 Redis 服务并配置连接
- 健康检查路径设为
/ping,Portainer 支持填curl -f http://localhost:8787/ping,但注意容器网络模式要能通
Portainer 部署后必须手动验证三件事
点完“Deploy the stack”不代表集群就跑起来了。Webman 集群的脆弱点不在部署动作本身,而在运行时契约是否满足。
- 进任一 Webman 容器,执行
ps aux | grep start.php,确认只有一个主进程,没有冗余 worker(说明多进程已关) - 访问任意实例的
:8787/ping,返回{"code":0,"msg":"ok"};再停掉一个容器,观察负载是否自动切到其余实例(验证服务发现) - 往
runtime/log写日志后重启容器,检查日志是否还在——若丢失,说明volumes挂载没生效或路径不对
最容易被忽略的是 runtime 目录的权限:Docker 默认以 root 启动,但 Webman 写日志要用 www-data 用户,需在 Dockerfile 里加 chown -R www-data:www-data /app/runtime,否则容器启动报错或日志写不进。











