workerman在docker中主动推送常遇监听地址绑定失败、uid映射内存丢失、pcntl/posix扩展缺失、信号无法传递及日志目录未挂载五大问题,需分别改为0.0.0.0监听、redis持久化uid、启用pcntl/posix、配置init:true与exec启动、挂载runtime目录。

Workerman主动推送信息在Docker里部署会遇到什么问题
Workerman主动推送信息(如WebSocket广播、GatewayWorker UID绑定推送)在Docker容器中运行时,常出现消息发不出、客户端收不到、UID映射失效、内存持续上涨甚至容器僵死等问题——这些不是代码逻辑错误,而是容器环境与Workerman底层机制冲突导致的典型故障。
监听地址绑定失败导致推送不可达
Workerman服务启动后浏览器或客户端无法收到推送,首要排查监听地址是否写死为127.0.0.1或localhost。Docker容器网络默认使用bridge模式,宿主机和外部网络必须通过0.0.0.0才能访问容器内端口。
将$worker = new Worker('websocket://127.0.0.1:2345');改为$worker = new Worker('websocket://0.0.0.0:2345');。
【不改会导致整个推送链路在容器外完全不可见】。即使docker run加了-p映射,只要监听地址不对,端口转发也无意义。
UID映射与连接对象在容器重启后丢失
GatewayWorker或自定义推送逻辑依赖Gateway::bindUid($client_id, $uid)建立映射关系,但该映射默认存储在PHP进程内存中。Docker容器重启、scale扩缩容、或使用docker-compose up --force-recreate时,所有内存态映射全部清空。
此时调用Gateway::sendToUid($uid, $data)将静默失败——既不报错也不投递。
必须将UID映射持久化到外部存储:Redis是唯一可靠选择。改用Gateway::setUid($client_id, $uid)配合redis://配置,确保start_gateway.php中$gateway->registerAddress指向独立Redis实例,而非容器内临时Redis。
pcntl/posix扩展缺失引发多进程崩溃
方法一:使用CLI基础镜像替代FPM镜像
直接选用php:8.1-cli-alpine或php:8.2-cli作为FROM镜像,避免FPM镜像默认禁用pcntl和posix扩展。
方法二:手动编译启用扩展
在Dockerfile中添加:RUN docker-php-ext-install pcntl posixRUN docker-php-ext-enable pcntl posix
注意:仅docker-php-ext-enable不够,镜像中若未编译模块,启用会失败且无提示。必须先install再enable。
信号无法传递导致推送进程无法优雅退出
第一步:在docker-compose.yml的service块中添加init: true
第二步:确保启动命令使用exec php start.php start -d而非php start.php start -d
第三步:检查Dockerfile中CMD是否为shell形式(如CMD ["sh", "-c", "php start.php start -d"]),应改为exec形式:CMD ["php", "start.php", "start", "-d"]
若未正确配置,容器收到SIGTERM时主进程不响应,子Worker进程继续运行,造成“假停止”——看似容器退出,实则残留进程仍在内存中推送垃圾数据,且新容器启动后出现端口占用或UID冲突。
日志与runtime目录未挂载导致推送状态不可追溯
GatewayWorker的runtime/log和runtime/pid目录若未挂载到宿主机,每次容器重建都会丢失所有运行时痕迹。
在docker-compose.yml中加入:volumes:- ./runtime:/app/runtime
否则你无法查看gateway.log里是否有bindUid failed: uid not exist这类关键错误,也无法确认gateway.pid是否被正确写入——而PID文件缺失将导致php start.php restart命令在容器内彻底失效。











