Files
inkwatch/deploy/docker-compose.prod.yml
T
jkooe 088c9b34a0 refactor(deploy): 移除 nginx 容器,接入层改由宿主承担(常驻 5 → 4)
## 结果

四容器编排从 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 是拼接语义)在宿主反代上
  一样成立,只是换了文件。
2026-11-08 20:29:43 +08:00

41 lines
2.1 KiB
YAML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 生产部署覆盖 —— 腾讯云轻量 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}"