Files
termi-blog/deploy/docker/README.md
limitcool 99a57738e0
All checks were successful
docker-images / resolve-build-targets (push) Successful in 5s
docker-images / build-and-push (admin) (push) Successful in 12s
docker-images / build-and-push (backend) (push) Successful in 27m48s
docker-images / build-and-push (frontend) (push) Successful in 15s
docker-images / submit-indexnow (push) Successful in 11s
feat: 更新后端工作者内存限制为 1g,以优化性能和稳定性
2026-04-03 15:55:26 +08:00

197 lines
8.5 KiB
Markdown
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.
# Docker 部署Package 镜像)
补充架构说明见:
- `deploy/docker/ARCHITECTURE.md`
- `deploy/caddy/Caddyfile.tohka.example`
- `deploy/caddy/Caddyfile.tohka.production.example`
- `deploy/docker/TOHKA_POCKET_ID.md`
- `deploy/docker/TOHKA_DEPLOY_RUNBOOK.md`
- `deploy/docker/config.yaml.example`
- `deploy/docker/BACKUP_AND_RECOVERY.md`
## 1) 准备主配置文件config.yaml
现在推荐把:
- `deploy/docker/config.yaml`
作为部署主配置源;`deploy/docker/.env` 改为脚本生成产物。
先复制模板:
```bash
cp deploy/docker/config.yaml.example deploy/docker/config.yaml
```
然后填写至少这些核心项:
- `compose_env.DATABASE_URL`
- `compose_env.REDIS_URL`
- `compose_env.JWT_SECRET`
- 邮件确认 / 邮件通知上线前,请同时补齐 SMTP 配置
填完后执行:
```bash
python deploy/scripts/render_compose_env.py \
--input deploy/docker/config.yaml \
--output deploy/docker/.env
```
如果你们内部喜欢先审 YAML再部署这就是现在的推荐流程。
建议在 `config.yaml -> compose_env` 下同时检查这些运行时变量:
- `BACKEND_MEMORY_LIMIT / BACKEND_MEMORY_SWAP_LIMIT`backend 容器内存 / swap 上限;对小内存主机建议显式设置
- `BACKEND_WORKER_MEMORY_LIMIT / BACKEND_WORKER_MEMORY_SWAP_LIMIT`worker 容器内存 / swap 上限
- `FRONTEND_MEMORY_LIMIT / FRONTEND_MEMORY_SWAP_LIMIT`frontend 容器内存 / swap 上限
- `ADMIN_MEMORY_LIMIT / ADMIN_MEMORY_SWAP_LIMIT`admin 容器内存 / swap 上限
- `INTERNAL_API_BASE_URL`frontend SSR 容器访问 backend 用compose 默认推荐 `http://backend:5150/api`
- `PUBLIC_API_BASE_URL`:浏览器访问 backend API 用;留空时前台会回退到“当前主机 + `:5150/api`
- `PUBLIC_COMMENT_TURNSTILE_SITE_KEY`:前台评论 / 订阅表单使用的 Cloudflare Turnstile site key
- `PUBLIC_WEB_PUSH_VAPID_PUBLIC_KEY`:前台浏览器推送订阅使用的 VAPID public key
- `PUBLIC_IMAGE_ALLOWED_HOSTS`:前台 `/_img` 图片优化端点允许的额外图片 host逗号分隔
- `ADMIN_API_BASE_URL`admin 浏览器访问 backend API 用;留空时后台会回退到“当前主机 + `:5150`
- `ADMIN_FRONTEND_BASE_URL`admin 里“打开前台 / 问答页 / 文章页预览”跳转用
- `TERMI_ADMIN_TRUST_PROXY_AUTH`:是否信任前置代理(如 Caddy + TinyAuth注入的后台认证头
- `TERMI_ADMIN_LOCAL_LOGIN_ENABLED`:是否保留本地账号密码登录兜底
- `TERMI_ADMIN_PROXY_SHARED_SECRET`:代理 SSO 共享密钥;建议和 Caddy 的 `X-Termi-Proxy-Secret` 配套使用
- `TERMI_TURNSTILE_SECRET_KEY`backend 评论 / 订阅接口使用的 Cloudflare Turnstile secret key兼容旧的 `TERMI_COMMENT_TURNSTILE_SECRET_KEY`
- `TERMI_WEB_PUSH_VAPID_PRIVATE_KEY`backend / worker 发送浏览器推送时使用的 VAPID private key
- `TERMI_WEB_PUSH_VAPID_SUBJECT`:浏览器推送 VAPID subject推荐 `mailto:xxx@example.com`
- `SMTP_ENABLE / SMTP_HOST / SMTP_PORT / SMTP_SECURE / SMTP_USER / SMTP_PASSWORD / SMTP_HELLO_NAME`:订阅确认和邮件通知需要
例如:
```yaml
compose_env:
BACKEND_MEMORY_LIMIT: 768m
BACKEND_MEMORY_SWAP_LIMIT: 768m
BACKEND_WORKER_MEMORY_LIMIT: 1g
BACKEND_WORKER_MEMORY_SWAP_LIMIT: 1g
FRONTEND_MEMORY_LIMIT: 256m
FRONTEND_MEMORY_SWAP_LIMIT: 256m
ADMIN_MEMORY_LIMIT: 128m
ADMIN_MEMORY_SWAP_LIMIT: 128m
PUBLIC_API_BASE_URL: https://api.blog.init.cool
PUBLIC_COMMENT_TURNSTILE_SITE_KEY: 1x00000000000000000000AA
PUBLIC_WEB_PUSH_VAPID_PUBLIC_KEY: replace-with-web-push-vapid-public-key
ADMIN_API_BASE_URL: https://admin.blog.init.cool
ADMIN_FRONTEND_BASE_URL: https://blog.init.cool
TERMI_ADMIN_TRUST_PROXY_AUTH: true
TERMI_ADMIN_LOCAL_LOGIN_ENABLED: false
TERMI_ADMIN_PROXY_SHARED_SECRET: replace-with-a-long-random-secret
TERMI_TURNSTILE_SECRET_KEY: replace-with-turnstile-secret-key
TERMI_WEB_PUSH_VAPID_PRIVATE_KEY: replace-with-web-push-vapid-private-key
TERMI_WEB_PUSH_VAPID_SUBJECT: mailto:noreply@blog.init.cool
```
> 这些值最终会被渲染成 `deploy/docker/.env`,再由 `compose.package.yml` 读取。
> 如果镜像构建期也注入了 `FRONTEND_PUBLIC_API_BASE_URL` / `ADMIN_VITE_API_BASE` / `ADMIN_VITE_FRONTEND_BASE_URL`,则运行时变量优先级更高。
## 2) 启动
在仓库根目录执行:
```bash
python deploy/scripts/render_compose_env.py \
--input deploy/docker/config.yaml \
--output deploy/docker/.env
docker compose -f deploy/docker/compose.package.yml --env-file deploy/docker/.env up -d
```
如果是在 `tohka` 上并且前面接宿主机 Caddy推荐改用
```bash
python deploy/scripts/render_compose_env.py \
--input deploy/docker/config.yaml \
--output deploy/docker/.env
docker compose \
-f deploy/docker/compose.package.yml \
-f deploy/docker/compose.tohka.override.yml \
--env-file deploy/docker/.env up -d
```
当前 compose 推荐一起启动 4 个容器:
- `backend`API / migration / `/healthz`
- `backend-worker`Redis 队列消费者(通知异步投递、失败重试)
- `frontend`Astro SSR(Node)
- `admin`:静态 SPA + Nginx
`compose.tohka.override.yml` 额外会把三个对外端口绑到 `127.0.0.1`,避免把 backend / admin 直接暴露到公网。
## 3) 更新镜像后重拉
```bash
docker compose -f deploy/docker/compose.package.yml --env-file deploy/docker/.env pull
docker compose -f deploy/docker/compose.package.yml --env-file deploy/docker/.env up -d
```
## 4) 问答记录2026-03-31
### Q1: 为什么前台容器是 `4321` 端口?
A: 前台是 **Astro SSR(Node)**`output: 'server'`),容器内运行 Node 服务(`dist/server/entry.mjs`),所以需要监听内部端口 `4321`
### Q2: 两个前端都能做成纯静态 + 反代吗?
A:
- `admin` 可以,当前就是静态资源由 Nginx 提供。
- `frontend` 当前不行(未做纯静态改造):项目里使用了 `prerender = false``Astro.request``Astro.cookies` 等请求期逻辑。
### Q3: SSR 和 CSR 怎么选?
A: 当前站点对外内容页优先 SEO 与首屏可见性,保留 SSR 更稳;后台管理台继续 CSR/静态站即可。
### Q4: 生产推荐端口设计是什么?
A: 推荐前置 Caddy/Nginx 统一暴露 `80/443``frontend:4321` / `backend:5150` / `admin:80` 仅走内网。
当前 `compose.package.yml` 属于直连端口版,便于快速部署与联调。
另外因为通知已经走异步队列,生产务必同时启动 `backend-worker`
### Q5: 为什么 compose 里没看到 `ADMIN_VITE_FRONTEND_BASE_URL`
A:
- 现在 compose 运行时可以直接设置 `ADMIN_FRONTEND_BASE_URL`,用于覆盖 admin 里所有前台跳转链接。
- `ADMIN_VITE_FRONTEND_BASE_URL` 仍然可以作为 **镜像构建期默认值** 保留在 CI / workflow 里。
- 如果两者都存在,**运行时 `ADMIN_FRONTEND_BASE_URL` 优先**。
### Q6: 前台 / 后台为什么拆成 public/internal 两种 API 地址?
A:
- `frontend` 是 Astro SSR服务端渲染请求 backend 时更适合走内网地址(如 `http://backend:5150/api`)。
- 但浏览器里的评论、问答、搜索请求必须走用户可访问的公开地址。
- `admin` 是纯静态 SPA也只能使用浏览器可访问的公开 API 地址。
- 所以现在区分为:
- `INTERNAL_API_BASE_URL`frontend SSR 内部访问
- `PUBLIC_API_BASE_URL`:前台浏览器访问
- `ADMIN_API_BASE_URL`admin 浏览器访问
### Q7: 现在后台 OIDC / Pocket ID 怎么接?
A:
- 推荐直接复用 tohka 上现成的 **TinyAuth + Pocket ID**
- Caddy 在 `admin` 域名入口加 `import tinyauth`,并把 `/api/*` 同域转发到 backend。
- backend 开启:
- `TERMI_ADMIN_TRUST_PROXY_AUTH=true`
- `TERMI_ADMIN_LOCAL_LOGIN_ENABLED=false`
- `TERMI_ADMIN_PROXY_SHARED_SECRET=<随机长字符串>`
- Caddy 在 `/api/*` -> backend 时补:
- `X-Termi-Proxy-Secret: {$TERMI_ADMIN_PROXY_SHARED_SECRET}`
- backend 会信任 TinyAuth 转发的:
- `Remote-User`
- `Remote-Email`
- `Remote-Groups`
- 本地开发仍可保留内置账号密码登录。
### Q8: 备份现在放在哪看?
A:
- 参考脚本:`deploy/scripts/backup/`
- 恢复文档:`deploy/docker/BACKUP_AND_RECOVERY.md`
### Q9: 现在健康检查和 migration 怎么处理?
A:
- `backend` 镜像启动时会先执行 `db migrate`
- `backend` 提供 `/healthz`
- `backend-worker` 不提供 HTTP `/healthz`compose 会覆盖镜像默认 healthcheck改为检查主进程是否仍以 `--worker` 模式运行
- `frontend` 提供 `/healthz`
- `admin` 继续由 Nginx 提供 `/healthz`
- compose 现在使用 `depends_on.condition: service_healthy`