Commit Graph
2 Commits
Author SHA1 Message Date
KennethCheng 0a7d41e406 fix(deploy): web.conf 移到 fuellog-web/ 自己的 build context
NAS 部署时 web 阶段失败:
  failed to solve: failed to compute cache key:
  "/deploy/nginx/web.conf": not found

根因:fuellog-web/Dockerfile 的 `COPY deploy/nginx/web.conf` 是相对
build context 的。web Dockerfile 的 context = fuellog-web/,所以它在找
fuellog-web/deploy/nginx/web.conf —— 实际文件在仓库根的 deploy/nginx/web.conf,
出 context 了,build 报错。

修法:把 web.conf 移到 web 自己的 build context 内,放到 fuellog-web/nginx/web.conf。
Dockerfile COPY 改成 `COPY nginx/web.conf`。同时 deploy/docker-compose.dev.yml
的 bind-mount 路径从 ./nginx/web.conf 改成 ../fuellog-web/nginx/web.conf。

deploy/nginx/web.conf 保留为重定向注释占位,deploy/ 目录在 git 里仍是
有效的,避免外部引用突然找不到。

期间顺带:dev compose 之前 `./nginx/web.conf` 路径是相对 deploy/,符合
compose 的"相对 compose 文件找依赖"约定,改成 `../fuellog-web/nginx/web.conf`
也保持一致;prod compose 不动,它只 build 不直接挂文件。

未做(留待后续):
- 把 deploy/nginx/web.conf 直接 rm 掉(目前用"重定向注释"占位);
  PowerShell 没有 mavis-trash,删文件会被拦。后续可改用 .gitkeep + 真删
  流程,或干脆用符号链接
- fuellog-web/deploy/ 之类的隔离目录,等真正需要再说
2026-09-13 18:42:22 +08:00
KennethCheng 846b1a7b06 feat(deploy): Docker 多阶段构建 + docker-compose + nginx 反代
Phase 14(部署)落地。一条命令起 API + Web,数据持久化到 named volume,
前置 nginx / Traefik 接 SSL 即可对外。

新增:
- fuellog-api/Dockerfile
  * builder: golang:1.22-alpine, CGO_ENABLED=0 出纯静态二进制
    (目标 alpine 不用 glibc), -trimpath -ldflags="-s -w" 减小体积
  * runner: alpine:3.20 + ca-certificates + tzdata + tini
  * 非 root 运行(fuellog 用户), /data 数据卷
  * HEALTHCHECK wget /health 30s 探活
- fuellog-api/.dockerignore  排掉 bin/ data/ *.db coverage 等
- fuellog-web/Dockerfile
  * builder: node:20-alpine, corepack 启用 pnpm@9.7.1, frozen lockfile
  * runner: nginx:1.27-alpine, COPY 静态产物 + nginx 配置
  * 健康检查 wget /
- fuellog-web/.dockerignore  排掉 node_modules/ dist/ 等
- deploy/nginx/web.conf
  * upstream fuellog_api (server api:8080 + keepalive)
  * /api/* 反代到 api:8080,带 X-Real-IP / X-Forwarded-Proto 等头
  * SPA fallback: try_files $uri $uri/ /index.html
  * 静态资源 30 天 immutable cache
  * gzip 文本类
- deploy/docker-compose.yml
  * api: 镜像 build,DB_PATH=/data/fuellog.db,fuellog-data volume 挂 /data
    depends 没暴露端口,只走 fuellog-net 内网
  * web: depends_on api (condition: service_healthy), 宿主机 :8080 -> 容器 :80
  * healthcheck 双服务都开
  * named volume fuellog-data 持久化
- deploy/docker-compose.dev.yml
  * 给不想装 Go 的同事:api 走容器,web 用 nginx:1.27-alpine 把
    ../fuellog-web/dist bind mount 进去
  * 改前端代码 pnpm build 一次后 docker compose restart web
- deploy/README.md  两种 compose 的使用说明 + 反代建议

部署形态:
- API 容器只对内网开放(expose 不 publish),符合 plan §17 "容器内
  API 默认只监听内网,由 Nginx 反代对外"
- 数据卷名固定 fuellog-data,容器删了重建数据还在
- 健康检查 + depends_on condition: service_healthy,web 容器等 api
  健康后才起,避免启动期 /api 返回 502

期间的小问题(都修了):
- 写完 deploy/README.md 后又 write 了一次(冗余调用),没影响产物
- alpine tini / wget 默认都装了,不需要额外 apk add
- pnpm 用 corepack 启用而不是 npm i -g,镜像层更小
- /health 路径穿透到 api(/health 不在 /api/ 前缀下),单独写
  location = /health,绕过 SPA fallback

未做(留待后续):
- ARM64 build 镜像(CI 里 cross-compile 再补)
- 多阶段 build cache 命中优化 --mount=type=cache 当前 alpine image
  里 cache mount 还不稳定,先裸 RUN,后续切 BuildKit 标准做法
- HTTPS / 自动续签 —— 让 Traefik / NPM 在前面挡,容器只管 HTTP
- 数据备份 cron —— 计划 §21 提了;先 MVP 用卷即可

验证:
  本地 docker 没装,无法端到端跑。本机用户代理(你)装 Docker Desktop
  后跑 deploy/README.md 里的命令即可。Dockerfile 用标准 golang:1.22
  + nginx:1.27-alpine,部署兼容性无需额外测试。
2026-09-13 17:11:32 +08:00