首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >PHP 容器的我!终于放弃了传统 Supervisord,转向当下最流行的 S6-overlay

PHP 容器的我!终于放弃了传统 Supervisord,转向当下最流行的 S6-overlay

作者头像
Tinywan
发布2026-07-01 13:16:10
发布2026-07-01 13:16:10
490
举报
文章被收录于专栏:开源技术小栈开源技术小栈

概述

大家好,我是 Tinywan,一个在 Docker + PHP 生态里摸爬滚打好几年的老油条。

过去几年,我的 PHP 容器(Nginx + PHP-FPM + cron + 一些小脚本)几乎清一色用 supervisord 来管理多进程。配置简单,一个 ini 文件搞定所有服务,启动、重启、日志查看都挺顺手。很多老项目、公司内部镜像也都是这么玩的,稳定不出大问题,我就一直没换。

但从 2025 年下半年开始,我陆续迁移了几个核心服务到新镜像时,突然发现自己有点“跟不上时代”了。

为什么 supervisord 让我越来越不爽?

  1. 容器 stop 的时候关不干净 docker stop 发 SIGTERM,supervisord 收到后会尝试优雅关闭子进程,但经常出现:主进程(supervisord 自己)不退出,导致容器卡在 “Stopping” 状态 10–30 秒,甚至要强制 kill -9。健康检查、滚动更新、蓝绿部署时特别烦。
  2. 僵尸进程(zombie)收割不彻底 PHP 脚本偶尔 fork 出子进程(比如 exec() 调用 shell),supervisord 的 zombie reaping 能力一般,需要额外配置或 dumb-init 套娃。套娃多了,镜像就臃肿。
  3. 日志输出不 Docker friendly 默认配置下,子进程的 stdout/stderr 会被 supervisord 接管并写文件,你得自己配置 [program:xxx] 的 stdout_logfile=syslog 或者重定向,才能让 docker logs 看到实时输出。配置一多就乱。
  4. Python 依赖 & 体积 Alpine 基础镜像里塞个 Python(哪怕是 python3-minimal),体积增加 30–50MB 左右。启动也比纯 C 的东西慢一点点。
  5. 社区趋势已经变了 linuxserver.io 全家桶、Home Assistant 插件、Nextcloud 官方 fpm 镜像、serversideup/php 系列、甚至 SeleniumHQ/docker-selenium 都在 2025 年陆续提迁移到 s6-overlay 的 issue。Reddit /r/docker 里搜 “supervisord vs s6”,新帖几乎全是推荐后者。

s6-overlay 到底好在哪里?

  • 天生为容器设计 s6-overlay 的 /init 就是 PID 1,它会正确处理所有信号转发、zombie 回收、依赖启动顺序。docker stop 几乎秒退(通常 <2 秒)。
  • 日志直接 stdout 服务 run 脚本里别重定向,全部输出就进 docker logs。debug 爽翻。
  • 极致轻量 官方 noarch + arch 两个 tar.xz,加起来也就 3–5MB。纯 C + execline,无 Python 依赖。
  • 依赖关系写得优雅 用 s6-rc 的 bundle + contents.d/ 目录结构定义依赖树。比如让 nginx 等 php-fpm ready 再启动,oneshot 初始化脚本(权限、目录、环境检查)也超级好写。
  • readiness 通知机制 加个 notification-fd 文件(内容 3),s6 就知道你的服务真正 ready 了。比 supervisord 的简单 restart 策略靠谱多了。

迁移过程(以 PHP-Nginx 为例)

  1. 基础镜像从 php:8.3-fpm-alpine 改成 alpine:3.21 + 手动加 s6-overlay(固定版本 3.2.x)。
  2. 把 supervisord.conf 删掉,改成 s6-rc 目录结构:
代码语言:javascript
复制
/etc/s6-overlay/s6-rc.d/
├── nginx/
│   ├── run               # #!/usr/bin/execlineb -PW   with-contenv nginx -g "daemon off;"
│   └── notification-fd   # 内容:3
├── php-fpm/
│   ├── run
│   └── notification-fd
├── init-permissions/     # oneshot 类型,启动前跑权限脚本
│   ├── run
│   └── type              # 内容:oneshot
└── user/                 # 默认 bundle
    └── contents.d/
        ├── php-fpm
        └── nginx
  1. Dockerfile 里 COPY rootfs/ / ,ENTRYPOINT ["/init"]

迁移后,镜像体积反而小了 20–40MB,docker stop 时间从 15s+ 降到 1–2s,docker logs 干净实时,健康检查也更准。

webman使用

拉取镜像

代码语言:javascript
复制
docker pull tinywan/docker-php-webman:8.4.16-s6

挂载启动webman

代码语言:javascript
复制
docker run --name webman-s6 --rm -it -p 8787:8787 -v /home/www/webman:/app tinywan/docker-php-webman:8.4.16-s6

输出日志

代码语言:javascript
复制
s6-rc: info: service s6rc-oneshot-runner: starting
s6-rc: info: service s6rc-oneshot-runner successfully started
s6-rc: info: service fix-attrs: starting
s6-rc: info: service fix-attrs successfully started
s6-rc: info: service legacy-cont-init: starting
s6-rc: info: service legacy-cont-init successfully started
s6-rc: info: service legacy-services: starting
s6-rc: info: service legacy-services successfully started
Workerman[start.php] start in DEBUG mode
Master pid:67 is not alive
-------------------------------------------- WORKERMAN ---------------------------------------------
Workerman/5.1.6         PHP/8.4.16 (JIT off)          Linux/6.6.87.2-microsoft-standard-WSL2
--------------------------------------------- WORKERS ----------------------------------------------
event-loop  proto       user        worker      listen                 count       state
event       tcp         root        webman      http://0.0.0.0:8787    16           [OK]
event       tcp         root        monitor     none                   1            [OK]
----------------------------------------------------------------------------------------------------
Press Ctrl+C to stop. Start success.

查看进程

代码语言:javascript
复制
$ docker top webman-s6  acxf
PID                 TTY                 STAT                TIME                COMMAND
60483               ?                   Ss                  0:00                \_ s6-svscan
60515               pts/0               Ss+                 0:00                \_ rc.init
60566               pts/0               S+                  0:00                | \_ php
60568               pts/0               S+                  0:00                | \_ php
60569               pts/0               S+                  0:00                | \_ php
60570               pts/0               S+                  0:00                | \_ php
60571               pts/0               S+                  0:00                | \_ php
60572               pts/0               S+                  0:00                | \_ php
60573               pts/0               S+                  0:00                | \_ php
60574               pts/0               S+                  0:00                | \_ php
60575               pts/0               S+                  0:00                | \_ php
60576               pts/0               S+                  0:00                | \_ php
60577               pts/0               S+                  0:00                | \_ php
60578               pts/0               S+                  0:00                | \_ php
60579               pts/0               S+                  0:00                | \_ php
60580               pts/0               S+                  0:00                | \_ php
60581               pts/0               S+                  0:00                | \_ php
60582               pts/0               S+                  0:00                | \_ php
60583               pts/0               S+                  0:00                | \_ php
60584               pts/0               S+                  0:00                | \_ php
60516               ?                   S                   0:00                \_ s6-supervise
60519               ?                   Ss                  0:00                | \_ s6-linux-init-s
60526               ?                   S                   0:00                \_ s6-supervise
60533               ?                   Ss                  0:00                | \_ s6-ipcserverd
60527               ?                   S                   0:00                \_ s6-supervise

最后想说

supervisord 没有错,它在 2015–2024 年几乎是 Docker 多进程的事实标准。但到了 2025–2026 年,容器哲学更纯粹了:容器应该像单个进程一样行为。s6-overlay 更贴合这个理念,轻、准、现代。

如果你还在维护老项目,supervisord 继续用没问题。但新项目、特别是 PHP + Nginx/FPM + cron 的组合,我现在是 100% 推荐 s6-overlay。

你最近有没遇到 supervisord 的痛点?或者已经在用 s6 了?欢迎交流~

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2026-01-13,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 开源技术小栈 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 概述
  • 为什么 supervisord 让我越来越不爽?
  • s6-overlay 到底好在哪里?
  • 迁移过程(以 PHP-Nginx 为例)
  • webman使用
  • 最后想说
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档