Phorge 现代化改造实战(二):改进容器化的七个细节

💡 原文中文,约11100字,阅读约需27分钟。
📝

内容提要

本文介绍Phorge容器现代化改造的第二阶段,聚焦将方案从“能运行”提升至“可配置、可持久化、可观测”。主要解决七个关键问题:预创建卷目录并设置属主、修复Dockerfile变量展开错误、优化配置生成逻辑、降权启动phd进程、安全清理构建依赖、改进健康检查及数据库账号迁移。改造后容器配置稳定、权限正确、可观测性增强,为后续认证和外部服务拆分奠定基础。

🔎

延伸解读

卷目录预创建与属主设置:避免“本机正常,换机就坏”

容器挂载命名卷时,若目标路径在镜像中不存在,Docker 会以 root 创建目录,导致非 root 进程(如 www-data)无法写入。r2 在构建阶段预先 mkdir 并 chown,确保首次挂载即具备正确属主。但此修复仅对新卷有效,已被 root 污染的旧卷需显式 chown 或重建。升级时应将旧卷迁移列入步骤,而非只验证全新安装。

变量展开的“三层陷阱”:Compose、Dockerfile 与 Shell

Compose 中 $$ 用于转义 $,但 Dockerfile 的 shell 形式 RUN 中,$$ 会被 shell 展开为 PID,导致变量名错误。文中示例因使用 $$f 而非 $f,使软件源替换逻辑从未执行,且构建不报错,难以察觉。跨文件复制脚本时需重新检查变量转义,并对“优化”类操作增加可观测验证,如从构建日志确认实际访问的域名。

配置生成策略:从“每次覆盖”到“存在即保留”

r1 每次启动都覆盖 local.json,破坏用户手工配置,且逐项写入失败时留下半成品。r2 改为仅当文件不存在或为空时生成,使用 PHP json_encode 一次写出完整 JSON,并通过 rename 原子替换,避免中断留下残缺文件。用户可挂载自定义配置,删除 local.json 即可重新生成。此策略兼顾易用性与可维护性。

健康检查的边界:liveness 不等于 readiness

r2 的 HTTP 健康检查通过请求 /status/ 验证 Apache、PHP 与路由可用,但无法证明 Schema 已升级、数据库可写或 phd 正常。它属于 liveness 而非完整 readiness。此外,Compose 仅标记 unhealthy,不会自动重启容器,告警与恢复需依赖外部编排。生产环境应区分存活与就绪探针,并考虑将迁移作为独立任务。

Q&A

Phorge 容器化改造中,为什么需要预先创建卷目录并设置属主?

因为如果卷目录不存在,Docker 首次挂载空命名卷时会以 root 创建目录,导致 Apache 和 phd 进程(以 www-data 运行)无法写入。预先创建并 chown 给 www-data 可以避免权限问题,并防止后续出现 root 属主文件。

在 Dockerfile 中,为什么 '$$f' 会导致软件源替换不生效?

在 Dockerfile 的 shell 形式 RUN 中,'$$' 会被 shell 展开为当前进程 PID,因此 '$$f' 变成类似 '12345f' 的字符串,而不是变量 f 的值,导致条件判断永远为假,sed 替换不会执行。应直接使用 '$f'。

Phorge 容器配置生成逻辑做了哪些优化?

r2 改为仅在配置文件不存在或为空时生成,使用 PHP 的 json_encode 一次生成完整 JSON,并通过 rename 原子替换,避免半成品配置。同时,配置目录被持久化,重启不会覆盖用户手工维护的配置。

如何安全地降权启动 phd 进程?

使用系统自带的 su 命令,以 www-data 用户启动 phd,例如:su -s /bin/sh www-data -c "$PHD_BIN start"。同时确保相关目录(如 /var/repo)属主正确,否则会直接报权限错误。

清理构建依赖时,如何避免误删 PHP 扩展所需的共享库?

采用 PHP 官方镜像的方法:先保存手工安装的软件包列表,编译扩展后将其标记为自动安装,再用 ldd 反查扩展依赖的共享库,将所属包重新标记为手工安装,最后执行 autoremove。这样可以安全清理开发包而保留运行时库。

Phorge 容器的健康检查是如何改进的?

r2 使用 PHP 脚本请求 /status/ 端点,并显式发送 Host 头(从 PHORGE_BASE_URI 解析),避免因 Host 不匹配导致探针失败。同时设置超时和重试参数,确保检查有效。

从 r1 升级到 r2 时,数据库账号迁移需要注意什么?

MySQL 官方镜像的初始化变量只在数据目录为空时生效,旧卷不会自动创建新用户。需要手动使用 root 凭据创建应用账号并授权,或备份后重建卷。否则 db-init 会失败,导致 Phorge 无法启动。

🏷️

标签

➡️

继续阅读