KennethCheng
|
f81047f9c9
|
fix(backend): Dockerfile 升 Go base image 到 1.27-alpine 匹配 go.mod
NAS 部署时 builder 阶段 `go mod download` 失败:
go: go.mod requires go >= 1.26.0 (running go 1.22.12; GOTOOLCHAIN=local)
根因:今天早上 `go mod tidy` 用本机 Go 1.27.0 跑,`go.mod` 的 go 指令
被写到 1.26.0(`go mod tidy` 行为:用当前 toolchain 的 minor),
但 `fuellog-api/Dockerfile` 写死 `FROM golang:1.22-alpine`,base 自带
Go 1.22.12,跟 go.mod 不一致 → Go 工具链自检不通过,go mod download
直接 exit 1。
GOTOOLCHAIN=local 也是这个错的成因:容器内默认不下载更新 toolchain,
如果 go.mod 要求的版本高于 base,会拒绝构建。要么升 base,要么放开
GOTOOLCHAIN=auto 走网络下载新工具链。升 base 是更确定的做法(无网也跑)。
修法:把 builder 阶段的 `FROM golang:1.22-alpine` 改成
`FROM golang:1.27-alpine`(与本机一致,与 go.mod 要求 >=1.26 都满足)。
runner 阶段 (alpine:3.20) 不需要 Go,不动。
未做(留待后续):
- 用 ARG 让 base Go 版本参数化,后续 `go mod tidy` 升 go.mod 时同步
Dockerfile base。短期先写死 1.27
- 同样的"go.mod vs Dockerfile base"漂移问题可能在 web 那边再出现
(目前 web 用 node:20-alpine,本机 node 24,node 不会因 minor 不一致
拒绝 npm install,暂时没风险)
|
2026-09-13 18:34:51 +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 |
|