feat: 新增生产环境 compose 编排(直连公共 MySQL)
- 新增 docker-compose.production.yml:仅 app + nginx,数据库连公司公共 MySQL,MYSQL_HOST/MYSQL_PASSWORD 必填校验 - 新增 .env.production.example 环境模板,.gitignore 白名单放行 - 修复 docker-compose.self-hosted.yml 漏转发 AI_TAGGING_TOOL 与 WECOM_* 共 7 个环境变量 - 部署指南补充两套编排文件选用说明与生产启动命令;忽略真实账号数据 CSV 防误提交
This commit is contained in:
47
.env.production.example
Normal file
47
.env.production.example
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
# 复制为 .env.production 后填写,配合 docker-compose.production.yml 使用。
|
||||||
|
# 与 self-hosted 模式的区别:数据库用公司公共 MySQL,不启动数据库容器,无 MYSQL_ROOT_PASSWORD。
|
||||||
|
# 不要把真实密钥提交到 Git。
|
||||||
|
|
||||||
|
# 公共 MySQL 连接(要求 MySQL 8 + utf8mb4,账号需对目标库有建表/读写权限)。
|
||||||
|
MYSQL_HOST=replace-with-shared-mysql-host
|
||||||
|
MYSQL_PORT=3306
|
||||||
|
MYSQL_DATABASE=koc_loop
|
||||||
|
MYSQL_USER=koc
|
||||||
|
MYSQL_PASSWORD=replace-with-strong-app-password
|
||||||
|
|
||||||
|
# 对外地址。部署域名确定后替换。
|
||||||
|
APP_ORIGIN=https://koc.example.com
|
||||||
|
KOC_PORTAL_URL=https://koc.example.com/koc/
|
||||||
|
|
||||||
|
# 后台首次启动会创建唯一超级管理员;账号创建后建议移除明文密码并重启。
|
||||||
|
SUPER_ADMIN_USERNAME=admin
|
||||||
|
SUPER_ADMIN_PASSWORD=replace-with-strong-admin-password
|
||||||
|
ADMIN_INTERNAL_TOKEN=replace-with-random-internal-token
|
||||||
|
|
||||||
|
# KOC LOOP 自身 MCP 的访问密钥。
|
||||||
|
KOC_MCP_API_KEY=replace-with-random-mcp-key
|
||||||
|
|
||||||
|
# 飞书内容表读取。
|
||||||
|
FEISHU_APP_ID=
|
||||||
|
FEISHU_APP_SECRET=
|
||||||
|
|
||||||
|
# 小红书公开数据采集 MCP。
|
||||||
|
AI_TOOL_CENTER_MCP_URL=
|
||||||
|
AI_TOOL_CENTER_MCP_KEY=
|
||||||
|
|
||||||
|
# 账号 LLM 自动打标(可选):AI_TOOL_CENTER 的 structured_text_process 工具,留空 = 关闭自动打标。
|
||||||
|
AI_TAGGING_TOOL=
|
||||||
|
|
||||||
|
# 企业微信通知(临期催办 + 管理员汇总)。群机器人只需 webhook;KOC 侧催办还需 corp/agent/secret,
|
||||||
|
# 并在后台 partners 编辑里把 wecom_external_user_id 填好。
|
||||||
|
WECOM_ROBOT_WEBHOOK=
|
||||||
|
WECOM_CORP_ID=
|
||||||
|
WECOM_AGENT_ID=
|
||||||
|
WECOM_SECRET=
|
||||||
|
WECOM_NOTIFY_DUE_DAYS=3
|
||||||
|
WECOM_NOTIFY_ENABLED=true
|
||||||
|
|
||||||
|
# 每天北京时间 09:00 自动执行采集计划。
|
||||||
|
ENABLE_SCHEDULER=true
|
||||||
|
SEED_DEMO_DATA=false
|
||||||
|
HTTP_PORT=80
|
||||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -34,8 +34,12 @@ yarn-error.log*
|
|||||||
# env files (can opt-in for committing if needed)
|
# env files (can opt-in for committing if needed)
|
||||||
.env*
|
.env*
|
||||||
!.env.self-hosted.example
|
!.env.self-hosted.example
|
||||||
|
!.env.production.example
|
||||||
.dev.vars
|
.dev.vars
|
||||||
|
|
||||||
|
# 真实 KOC 账号资源数据(含真实主页链接与昵称),仅本地使用,禁止入库
|
||||||
|
examples/KOC资源汇总*.csv
|
||||||
|
|
||||||
# vercel
|
# vercel
|
||||||
.vercel
|
.vercel
|
||||||
|
|
||||||
|
|||||||
57
docker-compose.production.yml
Normal file
57
docker-compose.production.yml
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
# 生产环境编排:只包含 KOC 服务与入口 Nginx,数据库直连公司公共 MySQL。
|
||||||
|
# 没有公共 MySQL 可用时,请改用 docker-compose.self-hosted.yml(自带数据库容器)。
|
||||||
|
services:
|
||||||
|
app:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
MYSQL_HOST: ${MYSQL_HOST:?请在环境文件中设置公共 MySQL 主机 MYSQL_HOST}
|
||||||
|
MYSQL_PORT: ${MYSQL_PORT:-3306}
|
||||||
|
MYSQL_DATABASE: ${MYSQL_DATABASE:-koc_loop}
|
||||||
|
MYSQL_USER: ${MYSQL_USER:-koc}
|
||||||
|
MYSQL_PASSWORD: ${MYSQL_PASSWORD:?请在环境文件中设置 MYSQL_PASSWORD}
|
||||||
|
UPLOAD_DIR: /data/koc/uploads
|
||||||
|
APP_ORIGIN: ${APP_ORIGIN}
|
||||||
|
KOC_PORTAL_URL: ${KOC_PORTAL_URL}
|
||||||
|
SUPER_ADMIN_USERNAME: ${SUPER_ADMIN_USERNAME}
|
||||||
|
SUPER_ADMIN_PASSWORD: ${SUPER_ADMIN_PASSWORD}
|
||||||
|
ADMIN_INTERNAL_TOKEN: ${ADMIN_INTERNAL_TOKEN}
|
||||||
|
KOC_MCP_API_KEY: ${KOC_MCP_API_KEY}
|
||||||
|
FEISHU_APP_ID: ${FEISHU_APP_ID:-}
|
||||||
|
FEISHU_APP_SECRET: ${FEISHU_APP_SECRET:-}
|
||||||
|
AI_TOOL_CENTER_MCP_URL: ${AI_TOOL_CENTER_MCP_URL:-}
|
||||||
|
AI_TOOL_CENTER_MCP_KEY: ${AI_TOOL_CENTER_MCP_KEY:-}
|
||||||
|
AI_TAGGING_TOOL: ${AI_TAGGING_TOOL:-}
|
||||||
|
WECOM_CORP_ID: ${WECOM_CORP_ID:-}
|
||||||
|
WECOM_AGENT_ID: ${WECOM_AGENT_ID:-}
|
||||||
|
WECOM_SECRET: ${WECOM_SECRET:-}
|
||||||
|
WECOM_ROBOT_WEBHOOK: ${WECOM_ROBOT_WEBHOOK:-}
|
||||||
|
WECOM_NOTIFY_DUE_DAYS: ${WECOM_NOTIFY_DUE_DAYS:-}
|
||||||
|
WECOM_NOTIFY_ENABLED: ${WECOM_NOTIFY_ENABLED:-}
|
||||||
|
ENABLE_SCHEDULER: ${ENABLE_SCHEDULER:-true}
|
||||||
|
SEED_DEMO_DATA: ${SEED_DEMO_DATA:-false}
|
||||||
|
TZ: Asia/Shanghai
|
||||||
|
volumes:
|
||||||
|
- upload_data:/data/koc/uploads
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "node -e \"fetch('http://127.0.0.1:3000/api/health').then(r=>{if(!r.ok)process.exit(1)}).catch(()=>process.exit(1))\""]
|
||||||
|
interval: 15s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 10
|
||||||
|
start_period: 45s
|
||||||
|
|
||||||
|
nginx:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: deploy/nginx/Dockerfile
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- "${HTTP_PORT:-80}:80"
|
||||||
|
depends_on:
|
||||||
|
app:
|
||||||
|
condition: service_healthy
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
upload_data:
|
||||||
@@ -43,6 +43,13 @@ services:
|
|||||||
FEISHU_APP_SECRET: ${FEISHU_APP_SECRET:-}
|
FEISHU_APP_SECRET: ${FEISHU_APP_SECRET:-}
|
||||||
AI_TOOL_CENTER_MCP_URL: ${AI_TOOL_CENTER_MCP_URL:-}
|
AI_TOOL_CENTER_MCP_URL: ${AI_TOOL_CENTER_MCP_URL:-}
|
||||||
AI_TOOL_CENTER_MCP_KEY: ${AI_TOOL_CENTER_MCP_KEY:-}
|
AI_TOOL_CENTER_MCP_KEY: ${AI_TOOL_CENTER_MCP_KEY:-}
|
||||||
|
AI_TAGGING_TOOL: ${AI_TAGGING_TOOL:-}
|
||||||
|
WECOM_CORP_ID: ${WECOM_CORP_ID:-}
|
||||||
|
WECOM_AGENT_ID: ${WECOM_AGENT_ID:-}
|
||||||
|
WECOM_SECRET: ${WECOM_SECRET:-}
|
||||||
|
WECOM_ROBOT_WEBHOOK: ${WECOM_ROBOT_WEBHOOK:-}
|
||||||
|
WECOM_NOTIFY_DUE_DAYS: ${WECOM_NOTIFY_DUE_DAYS:-}
|
||||||
|
WECOM_NOTIFY_ENABLED: ${WECOM_NOTIFY_ENABLED:-}
|
||||||
ENABLE_SCHEDULER: ${ENABLE_SCHEDULER:-true}
|
ENABLE_SCHEDULER: ${ENABLE_SCHEDULER:-true}
|
||||||
SEED_DEMO_DATA: ${SEED_DEMO_DATA:-false}
|
SEED_DEMO_DATA: ${SEED_DEMO_DATA:-false}
|
||||||
TZ: Asia/Shanghai
|
TZ: Asia/Shanghai
|
||||||
|
|||||||
@@ -19,6 +19,13 @@
|
|||||||
|
|
||||||
第一版按单实例 KOC 服务设计。MySQL 和上传目录均持久化。以后需要横向扩容时,可以把上传卷换成共享 NAS;对象存储接口已与业务代码分离。
|
第一版按单实例 KOC 服务设计。MySQL 和上传目录均持久化。以后需要横向扩容时,可以把上传卷换成共享 NAS;对象存储接口已与业务代码分离。
|
||||||
|
|
||||||
|
仓库提供两套编排文件,按数据库归属选用:
|
||||||
|
|
||||||
|
- `docker-compose.self-hosted.yml`:自带 MySQL 容器与数据卷,适合独立服务器或没有公共数据库的环境;
|
||||||
|
- `docker-compose.production.yml`:只包含 KOC 服务与入口 Nginx,直连公司公共 MySQL(要求 MySQL 8 + utf8mb4,账号需对目标库有建表与读写权限),配套环境模板 `.env.production.example`。
|
||||||
|
|
||||||
|
两套文件的入口 Nginx 都建议保留:它除了反向代理,还托管 `/koc/` 领取页静态文件、`/api/mcp` 长连接规则与 85 MB 上传限制,公司网关只需把域名转发到容器的 `HTTP_PORT`。
|
||||||
|
|
||||||
## 2. 服务器要求
|
## 2. 服务器要求
|
||||||
|
|
||||||
- Linux 服务器一台,建议至少 4 核、8 GB 内存、100 GB 数据盘;
|
- Linux 服务器一台,建议至少 4 核、8 GB 内存、100 GB 数据盘;
|
||||||
@@ -72,7 +79,16 @@ docker compose --env-file .env.self-hosted \
|
|||||||
-f docker-compose.self-hosted.yml up -d --build
|
-f docker-compose.self-hosted.yml up -d --build
|
||||||
```
|
```
|
||||||
|
|
||||||
应用容器启动时会先执行同一套数据库迁移脚本,成功后才启动 KOC 服务。查看状态:
|
生产环境使用公司公共 MySQL 时改用:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cp .env.production.example .env.production
|
||||||
|
# 编辑 .env.production:MYSQL_HOST 指向公共实例,其余变量同 self-hosted
|
||||||
|
docker compose --env-file .env.production \
|
||||||
|
-f docker-compose.production.yml up -d --build
|
||||||
|
```
|
||||||
|
|
||||||
|
应用容器启动时会先执行同一套数据库迁移脚本,成功后才启动 KOC 服务。查看状态(生产模式把 `-f` 与 `--env-file` 换成对应文件即可):
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker compose --env-file .env.self-hosted \
|
docker compose --env-file .env.self-hosted \
|
||||||
|
|||||||
Reference in New Issue
Block a user