找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

2390

积分

0

好友

337

主题
发表于 昨天 01:38 | 查看: 2| 回复: 0

S6-overlay工具介绍图

概述

在 Docker 与 PHP 的生态环境中,多进程管理一直是个绕不开的话题。过去几年,supervisord 因其配置简单(一个 ini 文件管理所有服务)和稳定的特性,成为许多 PHP 容器(如 Nginx + PHP-FPM + cron 组合)的事实标准。众多老项目和内部镜像都沿用此方案,平稳运行了相当长的时间。

然而,从 2025 年下半年开始,在为新核心服务构建镜像时,一个趋势变得愈发明显:社区的主流选择正在发生转变。许多新兴项目和主流镜像开始放弃传统的 Supervisord,转而投向 S6-overlay 的怀抱。

为什么 Supervisord 在容器中越来越力不从心?

尽管 supervisord 稳定可靠,但在现代的容器化部署场景下,其设计上的某些“不适应症”也逐渐暴露:

  1. 容器停止时难以优雅退出
    Docker stop 会发送 SIGTERM 信号,supervisord 收到后会尝试关闭子进程。但主进程自身时常无法及时退出,导致容器卡在 “Stopping” 状态长达 10 到 30 秒,最终不得不依赖 kill -9 强制终止。这在依赖健康检查、滚动更新和蓝绿部署的现代运维体系中,尤其令人头疼。

  2. 僵尸进程回收不彻底
    PHP 脚本偶尔会通过 exec() 等方式 fork 出子进程,supervisord 在僵尸进程收割方面的能力有限,往往需要额外的配置或引入 dumb-init 这类工具来“套娃”解决。工具链的叠加,无疑增加了镜像的复杂度和体积。

  3. 日志输出不够“Docker友好”
    在默认配置下,子进程的 stdout/stderr 会被 supervisord 接管并写入指定文件。若想通过 docker logs 命令实时查看日志,就必须为每个 [program:xxx] 单独配置 stdout_logfile=syslog 或进行重定向。服务一多,配置就变得繁琐且混乱。

  4. Python 依赖与镜像体积
    即便在 Alpine 这样的轻量级基础镜像中,引入 Python(哪怕是 python3-minimal)也会使镜像体积增加 30 到 50 MB。与纯 C 实现的方案相比,启动速度也会稍慢一筹。

  5. 社区风向已变
    观察 linuxserver.io 的全家桶镜像、Home Assistant 插件、Nextcloud 官方 fpm 镜像、serversideup/php 系列,乃至 SeleniumHQ/docker-selenium 等项目,在 2025 年都陆续出现了迁移到 s6-overlay 的相关议题。在 Reddit 的 /r/docker 等社区搜索 “supervisord vs s6”,新帖的推荐也几乎一边倒地倾向于后者。

S6-overlay 的优势究竟在哪里?

supervisord 相比,s6-overlay 更像是为容器环境量身定制的解决方案,其设计哲学与现代容器化理念高度契合:

  • 天生为容器设计
    s6-overlay/init 进程直接作为容器的 PID 1,能够正确处理所有信号转发、僵尸进程回收,并管理服务间的依赖启动顺序。这使得 docker stop 的响应速度极快,通常能在 2 秒内完成优雅退出。

  • 日志直接输出到 stdout
    服务脚本中的输出无需任何重定向,便会直接进入 docker logs 的流中。这让调试和实时监控变得异常便捷。

  • 极致轻量
    其官方发布的 noarch 和 arch 两个 tar.xz 包,加起来仅约 3 到 5 MB。基于纯 C 和 execline,没有任何 Python 运行时依赖。

  • 优雅的依赖关系管理
    通过 s6-rc 的 bundle 概念和 contents.d/ 目录结构,可以清晰定义服务间的依赖树。例如,让 Nginx 等待 PHP-FPM 就绪后再启动,或者编写一次性的初始化脚本(如检查权限、创建目录),都变得非常直观。

  • 就绪状态通知机制
    只需在服务目录下放置一个包含数字“3”的 notification-fd 文件,s6 就能精确知道服务何时真正进入就绪状态。这比 supervisord 简单的重启策略要可靠得多。

迁移实战:以 PHP-Nginx 容器为例

迁移过程并不复杂,核心是将基于配置文件的静态管理,转变为基于目录结构的声明式管理。

  1. 更换基础镜像
    将基础镜像从 php:8.3-fpm-alpine 改为 alpine:3.21,然后手动添加指定版本(如 3.2.x)的 s6-overlay

  2. 重构服务目录结构
    删除原有的 supervisord.conf 文件,建立如下的 s6-rc 目录结构:

    /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
  3. 修改 Dockerfile
    将构建好的目录树(例如放在 rootfs/ 下)复制到镜像根目录,并将入口点设置为 /init

    COPY rootfs/ /
    ENTRYPOINT ["/init"]

迁移完成后,通常会观察到几个明显的改进:镜像体积减少 20 到 40 MB,docker stop 时间从 15 秒以上降至 1-2 秒,docker logs 的输出干净实时,服务的健康检查也更为准确。

在 Webman 项目中使用

这里提供一个基于 S6-overlay 的 PHP 镜像在 Webman 框架下的使用示例。

拉取镜像

docker pull tinywan/docker-php-webman:8.4.16-s6

挂载并启动容器

docker run --name webman-s6 --rm -it -p 8787:8787 -v /home/www/webman:/app tinywan/docker-php-webman:8.4.16-s6

启动后,可以在日志中看到 s6-rc 和服务顺利启动的信息:

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.

查看容器内进程
使用 docker top 命令可以清晰地看到由 s6-svscans6-supervise 管理的进程树,这正是 s6-overlay 多进程管理能力的体现。

$ 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
... (多个php worker进程)
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 + 定时任务的组合,笔者现在会毫无保留地推荐 s6-overlay。如果你也遇到了类似的痛点,或已在使用 S6,欢迎到 云栈社区 的相关板块交流心得。




上一篇:Linux date命令月份计算的陷阱与规避方法(GNU date)
下一篇:PVE磁盘格式如何选择?qcow2、raw、vmdk性能与快照指南
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-1-16 00:34 , Processed in 0.204292 second(s), 40 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2025 云栈社区.

快速回复 返回顶部 返回列表