## 结果 四容器编排从 6 个 service 降到 5 个:`postgres` / `redis` / `business` / `gateway` 常驻 + `migrate` 一次性。**常驻容器 5 → 4**,实测直连 `127.0.0.1:4000|3000/health` 均 200。 ## 为什么现在做 `docker-compose.prod.yml` 里早就写着"生产不启动自带 nginx 容器,接入层交给 1Panel OpenResty",只是用 `profiles: ["never"]` 停用的。也就是说**生产本来就没这个容器**, 默认文件里留着它反而让两条路径分叉:本地开发跑一套、生产跑另一套,`nginx.conf` 只服务前者。现在两套文件对齐,反代只在宿主一处。 ## 三个必须处理的连带问题(都不是删几行就完事) **① `&logging` 锚点原本挂在 nginx service 里**,被另外 5 个 service 用 `*logging` 引用。直接删块会让 Compose 报 YAML 锚点未定义,而**报错点在引用的那几行、不在 被删的地方**。已把它提到顶层 `x-logging:` 扩展字段(Compose 支持),并把这个坑 写进注释。 **② prod 覆盖里那段 `nginx: profiles: ["never"]` 会变成悬空引用**(服务已不存在), 一并删除并改写注释。 **③ `watchdog.sh` 探的 `/healthz` 原本是 nginx 容器提供的虚拟端点。** 删掉后它会 恒报 `entry:404` —— 一个"服务其实好好的但监控一直叫"的假故障。已把探针语义改成 "接入层活着",并在 404 时把最常见成因写进告警文本(宿主反代没配 /healthz)。 ## 宿主反代模板 `deploy/nginx.host.conf.example`(替代原来的 `deploy/nginx.conf`),关键差异: upstream 从 `gateway:3000` / `business:4000` 改为 `127.0.0.1:3000` / `127.0.0.1:4000` —— 容器服务名**在宿主上根本不解析**,照抄旧配置会 `host not found in upstream`。 四条承载性指令原样保留,且写清了缺每一条的**症状**(都不是 502): - `proxy_http_version 1.1` + `Upgrade`/`Connection` → 缺了 WebSocket 握手失败 - `proxy_read_timeout 600s` → 缺了长连接 60 秒被无声掐断 - `proxy_buffering off` → 缺了画面不实时(数据被攒住) - `/relay/` 的 `proxy_request_buffering off` → 缺了"文件不落盘"变成假话 配置已用真 `nginx -t` 校验(`nginx:1.27-alpine`,`syntax is ok / test is successful`), 不是靠肉眼或 grep 判断。 ## 护栏:把"搬到宿主"这件事本身变成可验证的 `tests/dockerfile-coverage-test.js` 新增 7 条:模板存在、四条承载性指令各一条、 upstream 必须是回环而非 Docker 服务名、以及一条**负向**断言 —— 四容器编排里不许 再冒出 `nginx:` 服务(防"顺手加回来"造成两处真相)。 不加这段的话,宿主模板被删或被简化**不会有任何测试变红**,而症状是"页面能开但画面 不刷新",从现象很难倒推回配置。 测试:`dockerfile-coverage` **60/0**、`claim-proof` **57/0**。 ## README 现状描述(目录树 / 端口表 / 起栈步骤)已改。**历史段落不改写**: - "5 容器 healthy、经 nginx :80 入口"那句加"时代注记",说明那是当时形态; - "坑 B:nginx 强依赖证书"整段加抬头说明容器已移除,但**过程与教训原样保留** —— 那两条坑(硬引用可选文件导致 clone 必崩、Compose ports 是拼接语义)在宿主反代上 一样成立,只是换了文件。
41 lines
2.1 KiB
YAML
41 lines
2.1 KiB
YAML
# 生产部署覆盖 —— 腾讯云轻量 203.0.113.10(ssh <your-host>)
|
||
#
|
||
# 用法:
|
||
# docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d --build
|
||
#
|
||
# 本文件只解决该机现状逼出来的两件事,**不改任何本地开发默认值**:
|
||
#
|
||
# ① 该机 80/443 已被 1Panel OpenResty 占用(且 OpenResty 跑在 host 网络,
|
||
# 反代的是 127.0.0.1:端口 —— 既有 searxng 就是这么接的)。
|
||
# → **两套 compose 文件里都不再有 nginx 容器**(2026-11-08 移除,本文件原先
|
||
# 只是用 profiles 停用它)。接入层一律交给宿主:1Panel 站点,或裸 nginx。
|
||
# → 宿主配置模板见 deploy/nginx.host.conf.example。必须照抄的四条承载性指令:
|
||
# WebSocket 升级头 / proxy_read_timeout 600s / proxy_buffering off /
|
||
# proxy_http_version 1.1 —— 少任何一条的表现都不是 502,而是
|
||
# "能打开页面但画面不刷新"或"WebSocket 60 秒后被无声掐断"。
|
||
#
|
||
# ② 该实例云防火墙是「全部 TCP 1-65535 放通」。
|
||
# → gateway(3000) / business(4000) **必须**绑回环:业务服务带
|
||
# TRUST_PROXY_HOPS=1,直连时客户端可伪造 X-Forwarded-For 绕过配对码 IP 限流。
|
||
#
|
||
# ⚠️ 这里必须用 `!override` 而不是普通列表:
|
||
# Compose 对 `ports` 这类多值字段是**拼接**语义(默认文件的 0.0.0.0:3000:3000
|
||
# 会与本文件的 127.0.0.1:3000:3000 同时生效),只有 `!override` 才是替换。
|
||
# 这是 Compose 的经典陷阱,写错的表现是"绑了 127.0.0.1 但公网依然连得上"。
|
||
|
||
name: inkwatch
|
||
|
||
services:
|
||
gateway:
|
||
ports: !override
|
||
- "127.0.0.1:3000:3000"
|
||
|
||
business:
|
||
ports: !override
|
||
- "127.0.0.1:4000:4000"
|
||
environment:
|
||
# 前面只有 1Panel OpenResty 一跳,故为 1(默认值即 1,这里显式写出以示"已核过")。
|
||
# 若将来改成"OpenResty → 墨观 nginx → business"(保留自带 nginx 的方案 B),
|
||
# 本值必须改成 2,否则 IP 限流会把所有请求算到反代头上。
|
||
TRUST_PROXY_HOPS: "${TRUST_PROXY_HOPS:-1}"
|