From 72aa5009beb5fd41140b9877b28fd2ba1f45e783 Mon Sep 17 00:00:00 2001 From: xiaoxia Date: Fri, 11 Sep 2026 11:16:27 +0800 Subject: [PATCH] =?UTF-8?q?fix(web,=20P0):=20nginx=20entrypoint=20?= =?UTF-8?q?=E5=85=BC=E5=AE=B9=E5=A4=96=E9=83=A8=20bind-mount=20=E9=83=A8?= =?UTF-8?q?=E7=BD=B2=EF=BC=8C=E4=BF=AE=E5=A4=8D=20staging=20=E9=83=A8?= =?UTF-8?q?=E7=BD=B2=E5=90=8E=20web=20=E6=97=A0=E6=B3=95=E5=90=AF=E5=8A=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 根因:PR #1853 引入 nginx-entrypoint.sh 用于按 APP_ENV 切换配置, 但 staging/production CI 部署脚本通过 -v /path/nginx-staging.conf:/etc/nginx/conf.d/default.conf:ro 把环境配置以只读 bind mount 提供,default.conf 已经是正确配置。 entrypoint 里的 rm -f 在只读挂载点失败,set -e 导致脚本直接退出, nginx 从未启动,30s 健康检查失败触发自动回滚。 回滚到旧镜像(29ca51d,PR #1853 本身)后问题依然存在—— 说明 PR #1853 引入的 entrypoint 本身就与现有部署方式不兼容, 第一次部署就已失败,#1855 的 rm+ln 修复只是解决了 alpine ln -sf 在 普通文件上的行为问题,未解决 bind-mount 冲突。 修复:entrypoint 检测 default.conf 是否可被 rm 替换: - 可删(镜像自包含普通文件):按 APP_ENV 建立正确 symlink - rm 失败(外部只读 bind mount):跳过替换,直接启动 nginx --- infra/docker/nginx-entrypoint.sh | 41 ++++++++++++++++++++++---------- 1 file changed, 28 insertions(+), 13 deletions(-) diff --git a/infra/docker/nginx-entrypoint.sh b/infra/docker/nginx-entrypoint.sh index a0ca7653b..e25ddedeb 100755 --- a/infra/docker/nginx-entrypoint.sh +++ b/infra/docker/nginx-entrypoint.sh @@ -2,22 +2,37 @@ # Select nginx config based on APP_ENV (staging/production). # Both configs are baked into the image at well-known paths. # nginx reads config only at startup, so symlink before exec. -# 注意:基础镜像 /etc/nginx/conf.d/default.conf 是普通文件(非 symlink/目录), -# alpine busybox ln -sf 在 target 已存在且为普通文件时行为不稳定(会尝试在 -# target 目录下建子链接),必须先 rm 再 ln 才能正确替换。 +# +# 兼容两种部署方式: +# 1) 镜像自包含模式(local dev / 无外部挂载):基础镜像自带 default.conf 普通文件, +# entrypoint 按 APP_ENV 先 rm 再 ln -s 指向烤入的环境配置。 +# 注意:alpine busybox ln -sf 在 target 为已存在普通文件时行为不稳定, +# 必须先 rm 再 ln 才能正确替换。 +# 2) 外部 bind-mount 模式(staging / production CI 部署):CI 脚本通过 +# -v /path/nginx-.conf:/etc/nginx/conf.d/default.conf:ro 把环境 +# 配置以只读方式挂载进来。此时 default.conf 已经是正确的环境配置, +# 且为只读挂载点:rm 会报 "Read-only file system" 失败。 +# entrypoint 应识别此情况并跳过 rm/ln,直接 exec nginx。 set -e NGINX_CONF_DIR="/etc/nginx/conf.d" +DEFAULT_CONF="$NGINX_CONF_DIR/default.conf" -case "${APP_ENV:-production}" in - staging) - rm -f "$NGINX_CONF_DIR/default.conf" - ln -s /etc/nginx/nginx-staging.conf "$NGINX_CONF_DIR/default.conf" - ;; - *) - rm -f "$NGINX_CONF_DIR/default.conf" - ln -s /etc/nginx/nginx-production.conf "$NGINX_CONF_DIR/default.conf" - ;; -esac +# 判断 default.conf 是否可被 rm 替换(镜像自包含普通文件 → 可删; +# 外部只读 bind mount → rm 失败)。rm 失败时视为外部已提供正确配置,跳过。 +if rm -f "$DEFAULT_CONF" 2>/dev/null; then + # 镜像自包含:按 APP_ENV 建立正确 symlink + case "${APP_ENV:-production}" in + staging) + ln -s /etc/nginx/nginx-staging.conf "$DEFAULT_CONF" + ;; + *) + ln -s /etc/nginx/nginx-production.conf "$DEFAULT_CONF" + ;; + esac +else + # 外部 bind-mount(如 CI staging/prod 部署):配置已挂好,什么都不做。 + echo "[nginx-entrypoint] default.conf is externally mounted (read-only), skipping config symlink." +fi exec nginx -g "daemon off;" -- 2.54.0