refactor(offline): 重构离线部署脚本和文档结构
移动 docker-compose 文件到项目根目录并添加详细注释 更新 SQL 脚本路径引用和部署说明 删除旧的离线部署 compose 文件codex/offline
parent
abf851eded
commit
6322171418
|
|
@ -1,156 +1,163 @@
|
||||||
services:
|
# Dashboard Nanobot Docker 编排文件(Full 模式)
|
||||||
postgres:
|
# 说明:
|
||||||
image: ${POSTGRES_IMAGE:-postgres:16-alpine}
|
# 1. 当前文件用于“前端 + 后端 + PostgreSQL + Redis”整套部署。
|
||||||
container_name: dashboard-nanobot-postgres
|
# 2. 数据库和 Redis 都在本 compose 中启动,适合客户没有外部中间件时使用。
|
||||||
restart: unless-stopped
|
# 3. 客户通常需要重点修改 `.env` 里的端口、数据库密码、工作目录路径。
|
||||||
environment:
|
# 4. 如果需要调整宿主机挂载路径,可以直接修改下方 `volumes`。
|
||||||
TZ: ${TZ:-Asia/Shanghai}
|
|
||||||
POSTGRES_USER: ${POSTGRES_SUPERUSER:-postgres}
|
|
||||||
POSTGRES_PASSWORD: ${POSTGRES_SUPERPASSWORD:?POSTGRES_SUPERPASSWORD is required}
|
|
||||||
POSTGRES_DB: ${POSTGRES_BOOTSTRAP_DB:-postgres}
|
|
||||||
volumes:
|
|
||||||
- ./data/postgres:/var/lib/postgresql/data
|
|
||||||
expose:
|
|
||||||
- "5432"
|
|
||||||
healthcheck:
|
|
||||||
test: ["CMD-SHELL", "pg_isready -U \"$${POSTGRES_USER}\" -d \"$${POSTGRES_DB}\""]
|
|
||||||
interval: 10s
|
|
||||||
timeout: 5s
|
|
||||||
retries: 10
|
|
||||||
start_period: 20s
|
|
||||||
logging:
|
|
||||||
driver: json-file
|
|
||||||
options:
|
|
||||||
max-size: "20m"
|
|
||||||
max-file: "3"
|
|
||||||
|
|
||||||
redis:
|
services: # 定义当前 compose 里需要启动的服务
|
||||||
image: ${REDIS_IMAGE:-redis:7-alpine}
|
postgres: # PostgreSQL 数据库服务
|
||||||
container_name: dashboard-nanobot-redis
|
image: ${POSTGRES_IMAGE:-postgres:16-alpine} # PostgreSQL 镜像名
|
||||||
restart: unless-stopped
|
container_name: dashboard-nanobot-postgres # PostgreSQL 容器固定名称
|
||||||
environment:
|
restart: unless-stopped # 异常退出后自动拉起
|
||||||
TZ: ${TZ:-Asia/Shanghai}
|
environment: # PostgreSQL 启动参数
|
||||||
command: ["redis-server", "--appendonly", "yes", "--save", "60", "1000"]
|
TZ: ${TZ:-Asia/Shanghai} # 容器时区
|
||||||
volumes:
|
POSTGRES_USER: ${POSTGRES_SUPERUSER:-postgres} # PostgreSQL 超级用户
|
||||||
- ./data/redis:/data
|
POSTGRES_PASSWORD: ${POSTGRES_SUPERPASSWORD:?POSTGRES_SUPERPASSWORD is required} # PostgreSQL 超级用户密码
|
||||||
expose:
|
POSTGRES_DB: ${POSTGRES_BOOTSTRAP_DB:-postgres} # 启动时默认数据库
|
||||||
- "6379"
|
volumes: # 数据库存储挂载
|
||||||
healthcheck:
|
- ./data/postgres:/var/lib/postgresql/data # 宿主机数据库目录映射到容器数据目录
|
||||||
test: ["CMD", "redis-cli", "ping"]
|
expose: # 仅对内部网络开放
|
||||||
interval: 10s
|
- "5432" # PostgreSQL 默认端口
|
||||||
timeout: 5s
|
healthcheck: # PostgreSQL 健康检查
|
||||||
retries: 10
|
test: ["CMD-SHELL", "pg_isready -U \"$${POSTGRES_USER}\" -d \"$${POSTGRES_DB}\""] # 检测数据库是否就绪
|
||||||
start_period: 10s
|
interval: 10s # 每 10 秒检查一次
|
||||||
logging:
|
timeout: 5s # 单次检查超时 5 秒
|
||||||
driver: json-file
|
retries: 10 # 连续失败 10 次判定不健康
|
||||||
options:
|
start_period: 20s # 启动后预留 20 秒缓冲时间
|
||||||
max-size: "20m"
|
logging: # 容器日志策略
|
||||||
max-file: "3"
|
driver: json-file # 使用 Docker 默认 json-file 日志驱动
|
||||||
|
options: # 日志滚动配置
|
||||||
|
max-size: "20m" # 单个日志文件最大 20MB
|
||||||
|
max-file: "3" # 最多保留 3 个日志文件
|
||||||
|
|
||||||
backend:
|
redis: # Redis 缓存服务
|
||||||
build:
|
image: ${REDIS_IMAGE:-redis:7-alpine} # Redis 镜像名
|
||||||
context: .
|
container_name: dashboard-nanobot-redis # Redis 容器固定名称
|
||||||
dockerfile: backend/Dockerfile
|
restart: unless-stopped # 异常退出后自动拉起
|
||||||
args:
|
environment: # Redis 运行环境变量
|
||||||
PYTHON_BASE_IMAGE: ${PYTHON_BASE_IMAGE:-python:3.12-slim}
|
TZ: ${TZ:-Asia/Shanghai} # 容器时区
|
||||||
PIP_INDEX_URL: ${PIP_INDEX_URL:-https://pypi.org/simple}
|
command: ["redis-server", "--appendonly", "yes", "--save", "60", "1000"] # 开启 AOF 持久化并保留快照策略
|
||||||
PIP_TRUSTED_HOST: ${PIP_TRUSTED_HOST:-}
|
volumes: # Redis 数据挂载
|
||||||
image: dashboard-nanobot/backend:${BACKEND_IMAGE_TAG:-latest}
|
- ./data/redis:/data # 宿主机 Redis 数据目录映射到容器
|
||||||
container_name: dashboard-nanobot-backend
|
expose: # 仅对内部网络开放
|
||||||
restart: unless-stopped
|
- "6379" # Redis 默认端口
|
||||||
depends_on:
|
healthcheck: # Redis 健康检查
|
||||||
postgres:
|
test: ["CMD", "redis-cli", "ping"] # 检测 Redis 是否响应
|
||||||
condition: service_healthy
|
interval: 10s # 每 10 秒检查一次
|
||||||
redis:
|
timeout: 5s # 单次检查超时 5 秒
|
||||||
condition: service_healthy
|
retries: 10 # 连续失败 10 次判定不健康
|
||||||
environment:
|
start_period: 10s # 启动后预留 10 秒缓冲时间
|
||||||
TZ: ${TZ:-Asia/Shanghai}
|
logging: # 容器日志策略
|
||||||
APP_HOST: 0.0.0.0
|
driver: json-file # 使用 Docker 默认 json-file 日志驱动
|
||||||
APP_PORT: 8000
|
options: # 日志滚动配置
|
||||||
APP_RELOAD: "false"
|
max-size: "20m" # 单个日志文件最大 20MB
|
||||||
DATABASE_ECHO: "false"
|
max-file: "3" # 最多保留 3 个日志文件
|
||||||
DATABASE_POOL_SIZE: ${DATABASE_POOL_SIZE:-20}
|
|
||||||
DATABASE_MAX_OVERFLOW: ${DATABASE_MAX_OVERFLOW:-40}
|
|
||||||
DATABASE_POOL_TIMEOUT: ${DATABASE_POOL_TIMEOUT:-30}
|
|
||||||
DATABASE_POOL_RECYCLE: ${DATABASE_POOL_RECYCLE:-1800}
|
|
||||||
DATA_ROOT: /app/data
|
|
||||||
BOTS_WORKSPACE_ROOT: ${HOST_BOTS_WORKSPACE_ROOT}
|
|
||||||
DOCKER_NETWORK_NAME: ${DOCKER_NETWORK_NAME:-dashboard-nanobot-network}
|
|
||||||
DATABASE_URL: postgresql+psycopg://${POSTGRES_APP_USER}:${POSTGRES_APP_PASSWORD}@postgres:5432/${POSTGRES_APP_DB}
|
|
||||||
REDIS_ENABLED: ${REDIS_ENABLED:-true}
|
|
||||||
REDIS_URL: redis://redis:6379/${REDIS_DB:-8}
|
|
||||||
REDIS_PREFIX: ${REDIS_PREFIX:-dashboard_nanobot}
|
|
||||||
REDIS_DEFAULT_TTL: ${REDIS_DEFAULT_TTL:-60}
|
|
||||||
DEFAULT_BOT_SYSTEM_TIMEZONE: ${DEFAULT_BOT_SYSTEM_TIMEZONE:-Asia/Shanghai}
|
|
||||||
PANEL_ACCESS_PASSWORD: ${PANEL_ACCESS_PASSWORD:-}
|
|
||||||
WORKSPACE_PREVIEW_SIGNING_SECRET: ${WORKSPACE_PREVIEW_SIGNING_SECRET:-}
|
|
||||||
WORKSPACE_PREVIEW_TOKEN_TTL_SECONDS: ${WORKSPACE_PREVIEW_TOKEN_TTL_SECONDS:-3600}
|
|
||||||
CORS_ALLOWED_ORIGINS: ${CORS_ALLOWED_ORIGINS:-}
|
|
||||||
STT_ENABLED: ${STT_ENABLED:-true}
|
|
||||||
STT_MODEL: ${STT_MODEL:-ggml-small-q8_0.bin}
|
|
||||||
STT_MODEL_DIR: ${STT_MODEL_DIR:-/app/data/model}
|
|
||||||
STT_DEVICE: ${STT_DEVICE:-cpu}
|
|
||||||
STT_MAX_AUDIO_SECONDS: ${STT_MAX_AUDIO_SECONDS:-20}
|
|
||||||
STT_DEFAULT_LANGUAGE: ${STT_DEFAULT_LANGUAGE:-zh}
|
|
||||||
STT_FORCE_SIMPLIFIED: ${STT_FORCE_SIMPLIFIED:-true}
|
|
||||||
STT_AUDIO_PREPROCESS: ${STT_AUDIO_PREPROCESS:-true}
|
|
||||||
STT_AUDIO_FILTER: ${STT_AUDIO_FILTER:-highpass=f=120,lowpass=f=7600,afftdn=nf=-20}
|
|
||||||
STT_INITIAL_PROMPT: ${STT_INITIAL_PROMPT:-以下内容可能包含简体中文和英文术语。请优先输出简体中文,英文单词、缩写、品牌名和数字保持原文,不要翻译。}
|
|
||||||
volumes:
|
|
||||||
- /var/run/docker.sock:/var/run/docker.sock
|
|
||||||
- ./data:/app/data
|
|
||||||
- ${HOST_BOTS_WORKSPACE_ROOT}:${HOST_BOTS_WORKSPACE_ROOT}
|
|
||||||
expose:
|
|
||||||
- "8000"
|
|
||||||
healthcheck:
|
|
||||||
test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8000/api/health', timeout=3).read()"]
|
|
||||||
interval: 15s
|
|
||||||
timeout: 5s
|
|
||||||
retries: 5
|
|
||||||
start_period: 20s
|
|
||||||
logging:
|
|
||||||
driver: json-file
|
|
||||||
options:
|
|
||||||
max-size: "20m"
|
|
||||||
max-file: "3"
|
|
||||||
|
|
||||||
nginx:
|
backend: # 后端 API 服务
|
||||||
build:
|
build: # 保留构建信息,便于有源码时重新 build;离线部署通常直接用 image
|
||||||
context: ./frontend
|
context: . # 构建上下文为项目根目录
|
||||||
dockerfile: Dockerfile
|
dockerfile: backend/Dockerfile # 后端 Dockerfile 路径
|
||||||
args:
|
args: # 构建参数
|
||||||
NODE_BASE_IMAGE: ${NODE_BASE_IMAGE:-node:22-alpine}
|
PYTHON_BASE_IMAGE: ${PYTHON_BASE_IMAGE:-python:3.12-slim} # Python 基础镜像
|
||||||
NGINX_BASE_IMAGE: ${NGINX_BASE_IMAGE:-nginx:alpine}
|
PIP_INDEX_URL: ${PIP_INDEX_URL:-https://pypi.org/simple} # pip 源地址
|
||||||
NPM_REGISTRY: ${NPM_REGISTRY:-https://registry.npmjs.org/}
|
PIP_TRUSTED_HOST: ${PIP_TRUSTED_HOST:-} # pip 信任主机
|
||||||
VITE_API_BASE: /api
|
image: dashboard-nanobot/backend:${BACKEND_IMAGE_TAG:-latest} # 后端运行镜像名
|
||||||
VITE_WS_BASE: /ws/monitor
|
container_name: dashboard-nanobot-backend # 后端容器固定名称
|
||||||
image: dashboard-nanobot/nginx:${FRONTEND_IMAGE_TAG:-latest}
|
restart: unless-stopped # 异常退出后自动拉起
|
||||||
container_name: dashboard-nanobot-nginx
|
depends_on: # 依赖中间件健康后再启动
|
||||||
restart: unless-stopped
|
postgres: # 依赖 PostgreSQL
|
||||||
environment:
|
condition: service_healthy # 要求 PostgreSQL 健康
|
||||||
TZ: ${TZ:-Asia/Shanghai}
|
redis: # 依赖 Redis
|
||||||
UPLOAD_MAX_MB: ${UPLOAD_MAX_MB:-100}
|
condition: service_healthy # 要求 Redis 健康
|
||||||
depends_on:
|
environment: # 后端环境变量
|
||||||
backend:
|
TZ: ${TZ:-Asia/Shanghai} # 容器时区
|
||||||
condition: service_healthy
|
APP_HOST: 0.0.0.0 # 服务监听地址,容器内通常保持 0.0.0.0
|
||||||
ports:
|
APP_PORT: 8000 # 服务监听端口,需与 expose 和健康检查保持一致
|
||||||
- "${NGINX_PORT}:80"
|
APP_RELOAD: "false" # 生产环境关闭热重载
|
||||||
healthcheck:
|
DATABASE_ECHO: "false" # 生产环境关闭 SQL 日志回显
|
||||||
test: ["CMD", "wget", "-q", "-O", "/dev/null", "http://127.0.0.1/"]
|
DATABASE_POOL_SIZE: ${DATABASE_POOL_SIZE:-20} # 数据库连接池基础连接数
|
||||||
interval: 15s
|
DATABASE_MAX_OVERFLOW: ${DATABASE_MAX_OVERFLOW:-40} # 连接池额外可溢出连接数
|
||||||
timeout: 5s
|
DATABASE_POOL_TIMEOUT: ${DATABASE_POOL_TIMEOUT:-30} # 获取连接超时时间(秒)
|
||||||
retries: 5
|
DATABASE_POOL_RECYCLE: ${DATABASE_POOL_RECYCLE:-1800} # 连接回收周期(秒)
|
||||||
start_period: 10s
|
DATA_ROOT: /app/data # 容器内业务数据目录
|
||||||
logging:
|
BOTS_WORKSPACE_ROOT: ${HOST_BOTS_WORKSPACE_ROOT} # Bot 工作目录,容器内外路径保持一致
|
||||||
driver: json-file
|
DOCKER_NETWORK_NAME: ${DOCKER_NETWORK_NAME:-dashboard-nanobot-network} # 业务容器使用的 Docker 网络名称
|
||||||
options:
|
DATABASE_URL: postgresql+psycopg://${POSTGRES_APP_USER}:${POSTGRES_APP_PASSWORD}@postgres:5432/${POSTGRES_APP_DB} # Full 模式固定连接内部 PostgreSQL
|
||||||
max-size: "20m"
|
REDIS_ENABLED: ${REDIS_ENABLED:-true} # Full 模式默认启用 Redis
|
||||||
max-file: "3"
|
REDIS_URL: redis://redis:6379/${REDIS_DB:-8} # Full 模式固定连接内部 Redis
|
||||||
|
REDIS_PREFIX: ${REDIS_PREFIX:-dashboard_nanobot} # Redis key 前缀
|
||||||
|
REDIS_DEFAULT_TTL: ${REDIS_DEFAULT_TTL:-60} # Redis 默认过期时间(秒)
|
||||||
|
DEFAULT_BOT_SYSTEM_TIMEZONE: ${DEFAULT_BOT_SYSTEM_TIMEZONE:-Asia/Shanghai} # Bot 默认时区
|
||||||
|
PANEL_ACCESS_PASSWORD: ${PANEL_ACCESS_PASSWORD:-} # 面板访问密码
|
||||||
|
WORKSPACE_PREVIEW_SIGNING_SECRET: ${WORKSPACE_PREVIEW_SIGNING_SECRET:-} # 预览签名密钥
|
||||||
|
WORKSPACE_PREVIEW_TOKEN_TTL_SECONDS: ${WORKSPACE_PREVIEW_TOKEN_TTL_SECONDS:-3600} # 预览令牌有效期(秒)
|
||||||
|
CORS_ALLOWED_ORIGINS: ${CORS_ALLOWED_ORIGINS:-} # 前端跨域白名单
|
||||||
|
STT_ENABLED: ${STT_ENABLED:-true} # 是否启用语音识别
|
||||||
|
STT_MODEL: ${STT_MODEL:-ggml-small-q8_0.bin} # 语音识别模型文件名
|
||||||
|
STT_MODEL_DIR: ${STT_MODEL_DIR:-/app/data/model} # 语音识别模型目录
|
||||||
|
STT_DEVICE: ${STT_DEVICE:-cpu} # 语音识别运行设备
|
||||||
|
STT_MAX_AUDIO_SECONDS: ${STT_MAX_AUDIO_SECONDS:-20} # 单次音频最大秒数
|
||||||
|
STT_DEFAULT_LANGUAGE: ${STT_DEFAULT_LANGUAGE:-zh} # 默认语音识别语言
|
||||||
|
STT_FORCE_SIMPLIFIED: ${STT_FORCE_SIMPLIFIED:-true} # 是否强制输出简体中文
|
||||||
|
STT_AUDIO_PREPROCESS: ${STT_AUDIO_PREPROCESS:-true} # 是否预处理音频
|
||||||
|
STT_AUDIO_FILTER: ${STT_AUDIO_FILTER:-highpass=f=120,lowpass=f=7600,afftdn=nf=-20} # 音频滤波参数
|
||||||
|
STT_INITIAL_PROMPT: ${STT_INITIAL_PROMPT:-以下内容可能包含简体中文和英文术语。请优先输出简体中文,英文单词、缩写、品牌名和数字保持原文,不要翻译。} # 语音识别初始提示词
|
||||||
|
volumes: # 宿主机与容器挂载关系
|
||||||
|
- /var/run/docker.sock:/var/run/docker.sock # 必须保留,后端需要管理 Bot 容器
|
||||||
|
- ./data:/app/data # 项目数据目录,建议保留在交付目录下
|
||||||
|
- ${HOST_BOTS_WORKSPACE_ROOT}:${HOST_BOTS_WORKSPACE_ROOT} # Bot 工作目录挂载,路径通常由客户现场决定
|
||||||
|
expose: # 只暴露给内部网络,不直接发布到宿主机
|
||||||
|
- "8000" # 后端服务端口
|
||||||
|
healthcheck: # 健康检查,供 nginx 依赖判断使用
|
||||||
|
test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8000/api/health', timeout=3).read()"] # 检测后端健康接口
|
||||||
|
interval: 15s # 每 15 秒检查一次
|
||||||
|
timeout: 5s # 单次检查超时 5 秒
|
||||||
|
retries: 5 # 连续失败 5 次判定不健康
|
||||||
|
start_period: 20s # 启动后预留 20 秒缓冲时间
|
||||||
|
logging: # 容器日志策略
|
||||||
|
driver: json-file # 使用 Docker 默认 json-file 日志驱动
|
||||||
|
options: # 日志滚动配置
|
||||||
|
max-size: "20m" # 单个日志文件最大 20MB
|
||||||
|
max-file: "3" # 最多保留 3 个日志文件
|
||||||
|
|
||||||
networks:
|
nginx: # 前端 Nginx 服务
|
||||||
default:
|
build: # 保留构建信息,离线部署通常直接使用导入镜像
|
||||||
name: ${DOCKER_NETWORK_NAME:-dashboard-nanobot-network}
|
context: ./frontend # 前端构建上下文
|
||||||
driver: bridge
|
dockerfile: Dockerfile # 前端 Dockerfile 路径
|
||||||
ipam:
|
args: # 前端构建参数
|
||||||
config:
|
NODE_BASE_IMAGE: ${NODE_BASE_IMAGE:-node:22-alpine} # Node 基础镜像
|
||||||
- subnet: ${DOCKER_NETWORK_SUBNET:-172.20.0.0/16}
|
NGINX_BASE_IMAGE: ${NGINX_BASE_IMAGE:-nginx:alpine} # Nginx 基础镜像
|
||||||
|
NPM_REGISTRY: ${NPM_REGISTRY:-https://registry.npmjs.org/} # npm 源地址
|
||||||
|
VITE_API_BASE: /api # 前端 API 前缀
|
||||||
|
VITE_WS_BASE: /ws/monitor # 前端 WebSocket 前缀
|
||||||
|
image: dashboard-nanobot/nginx:${FRONTEND_IMAGE_TAG:-latest} # 前端运行镜像名
|
||||||
|
container_name: dashboard-nanobot-nginx # 前端容器固定名称
|
||||||
|
restart: unless-stopped # 异常退出后自动拉起
|
||||||
|
environment: # 前端环境变量
|
||||||
|
TZ: ${TZ:-Asia/Shanghai} # 容器时区
|
||||||
|
UPLOAD_MAX_MB: ${UPLOAD_MAX_MB:-100} # 上传大小限制,传给 Nginx 配置使用
|
||||||
|
depends_on: # 依赖后端健康后再启动
|
||||||
|
backend: # 依赖后端容器
|
||||||
|
condition: service_healthy # 要求后端健康
|
||||||
|
ports: # 对外开放端口
|
||||||
|
- "${NGINX_PORT}:80" # 宿主机端口映射到容器 80 端口
|
||||||
|
healthcheck: # Nginx 健康检查
|
||||||
|
test: ["CMD", "wget", "-q", "-O", "/dev/null", "http://127.0.0.1/"] # 检测首页是否可访问
|
||||||
|
interval: 15s # 每 15 秒检查一次
|
||||||
|
timeout: 5s # 单次检查超时 5 秒
|
||||||
|
retries: 5 # 连续失败 5 次判定不健康
|
||||||
|
start_period: 10s # 启动后预留 10 秒缓冲时间
|
||||||
|
logging: # 容器日志策略
|
||||||
|
driver: json-file # 使用 Docker 默认 json-file 日志驱动
|
||||||
|
options: # 日志滚动配置
|
||||||
|
max-size: "20m" # 单个日志文件最大 20MB
|
||||||
|
max-file: "3" # 最多保留 3 个日志文件
|
||||||
|
|
||||||
|
networks: # 自定义网络配置
|
||||||
|
default: # 默认网络
|
||||||
|
name: ${DOCKER_NETWORK_NAME:-dashboard-nanobot-network} # 网络名称,客户通常无需修改
|
||||||
|
driver: bridge # 使用 bridge 网络驱动
|
||||||
|
ipam: # IP 地址管理配置
|
||||||
|
config: # 网段配置列表
|
||||||
|
- subnet: ${DOCKER_NETWORK_SUBNET:-172.20.0.0/16} # 自定义子网,现场冲突时可修改
|
||||||
|
|
|
||||||
|
|
@ -1,101 +1,108 @@
|
||||||
services:
|
# Dashboard Nanobot Docker 编排文件(Prod 模式)
|
||||||
backend:
|
# 说明:
|
||||||
build:
|
# 1. 当前文件用于“前端 + 后端”部署。
|
||||||
context: .
|
# 2. PostgreSQL 与 Redis 由客户现场外部提供,本文件不会启动这两个服务。
|
||||||
dockerfile: backend/Dockerfile
|
# 3. 客户通常需要重点修改 `.env` 里的端口、数据库连接串、Redis 连接串、工作目录路径。
|
||||||
args:
|
# 4. 如果需要调整宿主机挂载路径,可以直接修改下方 `volumes`。
|
||||||
PYTHON_BASE_IMAGE: ${PYTHON_BASE_IMAGE:-python:3.12-slim}
|
|
||||||
PIP_INDEX_URL: ${PIP_INDEX_URL:-https://pypi.org/simple}
|
|
||||||
PIP_TRUSTED_HOST: ${PIP_TRUSTED_HOST:-}
|
|
||||||
image: dashboard-nanobot/backend:${BACKEND_IMAGE_TAG:-latest}
|
|
||||||
container_name: dashboard-nanobot-backend
|
|
||||||
restart: unless-stopped
|
|
||||||
environment:
|
|
||||||
APP_HOST: 0.0.0.0
|
|
||||||
APP_PORT: 8002
|
|
||||||
APP_RELOAD: "false"
|
|
||||||
DATABASE_ECHO: "false"
|
|
||||||
DATABASE_POOL_SIZE: ${DATABASE_POOL_SIZE:-20}
|
|
||||||
DATABASE_MAX_OVERFLOW: ${DATABASE_MAX_OVERFLOW:-40}
|
|
||||||
DATABASE_POOL_TIMEOUT: ${DATABASE_POOL_TIMEOUT:-30}
|
|
||||||
DATABASE_POOL_RECYCLE: ${DATABASE_POOL_RECYCLE:-1800}
|
|
||||||
DATA_ROOT: /app/data
|
|
||||||
BOTS_WORKSPACE_ROOT: ${HOST_BOTS_WORKSPACE_ROOT}
|
|
||||||
DOCKER_NETWORK_NAME: ${DOCKER_NETWORK_NAME:-dashboard-nanobot-network}
|
|
||||||
DATABASE_URL: ${DATABASE_URL:-}
|
|
||||||
REDIS_ENABLED: ${REDIS_ENABLED:-false}
|
|
||||||
REDIS_URL: ${REDIS_URL:-}
|
|
||||||
REDIS_PREFIX: ${REDIS_PREFIX:-dashboard_nanobot}
|
|
||||||
REDIS_DEFAULT_TTL: ${REDIS_DEFAULT_TTL:-60}
|
|
||||||
DEFAULT_BOT_SYSTEM_TIMEZONE: ${DEFAULT_BOT_SYSTEM_TIMEZONE:-Asia/Shanghai}
|
|
||||||
PANEL_ACCESS_PASSWORD: ${PANEL_ACCESS_PASSWORD:-}
|
|
||||||
WORKSPACE_PREVIEW_SIGNING_SECRET: ${WORKSPACE_PREVIEW_SIGNING_SECRET:-}
|
|
||||||
WORKSPACE_PREVIEW_TOKEN_TTL_SECONDS: ${WORKSPACE_PREVIEW_TOKEN_TTL_SECONDS:-3600}
|
|
||||||
CORS_ALLOWED_ORIGINS: ${CORS_ALLOWED_ORIGINS:-}
|
|
||||||
STT_ENABLED: ${STT_ENABLED:-true}
|
|
||||||
STT_MODEL: ${STT_MODEL:-ggml-small-q8_0.bin}
|
|
||||||
STT_MODEL_DIR: ${STT_MODEL_DIR:-/app/data/model}
|
|
||||||
STT_DEVICE: ${STT_DEVICE:-cpu}
|
|
||||||
STT_MAX_AUDIO_SECONDS: ${STT_MAX_AUDIO_SECONDS:-20}
|
|
||||||
STT_DEFAULT_LANGUAGE: ${STT_DEFAULT_LANGUAGE:-zh}
|
|
||||||
STT_FORCE_SIMPLIFIED: ${STT_FORCE_SIMPLIFIED:-true}
|
|
||||||
STT_AUDIO_PREPROCESS: ${STT_AUDIO_PREPROCESS:-true}
|
|
||||||
STT_AUDIO_FILTER: ${STT_AUDIO_FILTER:-highpass=f=120,lowpass=f=7600,afftdn=nf=-20}
|
|
||||||
STT_INITIAL_PROMPT: ${STT_INITIAL_PROMPT:-以下内容可能包含简体中文和英文术语。请优先输出简体中文,英文单词、缩写、品牌名和数字保持原文,不要翻译。}
|
|
||||||
volumes:
|
|
||||||
- /var/run/docker.sock:/var/run/docker.sock
|
|
||||||
- ./data:/app/data
|
|
||||||
- ${HOST_BOTS_WORKSPACE_ROOT}:${HOST_BOTS_WORKSPACE_ROOT}
|
|
||||||
expose:
|
|
||||||
- "8002"
|
|
||||||
healthcheck:
|
|
||||||
test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8002/api/health', timeout=3).read()"]
|
|
||||||
interval: 15s
|
|
||||||
timeout: 5s
|
|
||||||
retries: 5
|
|
||||||
start_period: 20s
|
|
||||||
logging:
|
|
||||||
driver: json-file
|
|
||||||
options:
|
|
||||||
max-size: "20m"
|
|
||||||
max-file: "3"
|
|
||||||
|
|
||||||
nginx:
|
services: # 定义当前 compose 里需要启动的服务
|
||||||
build:
|
backend: # 后端 API 服务
|
||||||
context: ./frontend
|
build: # 保留构建信息,便于有源码时重新 build;离线部署通常直接用 image
|
||||||
dockerfile: Dockerfile
|
context: . # 构建上下文为项目根目录
|
||||||
args:
|
dockerfile: backend/Dockerfile # 后端 Dockerfile 路径
|
||||||
NODE_BASE_IMAGE: ${NODE_BASE_IMAGE:-node:22-alpine}
|
args: # 构建参数
|
||||||
NGINX_BASE_IMAGE: ${NGINX_BASE_IMAGE:-nginx:alpine}
|
PYTHON_BASE_IMAGE: ${PYTHON_BASE_IMAGE:-python:3.12-slim} # Python 基础镜像
|
||||||
NPM_REGISTRY: ${NPM_REGISTRY:-https://registry.npmjs.org/}
|
PIP_INDEX_URL: ${PIP_INDEX_URL:-https://pypi.org/simple} # pip 源地址
|
||||||
VITE_API_BASE: /api
|
PIP_TRUSTED_HOST: ${PIP_TRUSTED_HOST:-} # pip 信任主机
|
||||||
VITE_WS_BASE: /ws/monitor
|
image: dashboard-nanobot/backend:${BACKEND_IMAGE_TAG:-latest} # 后端运行镜像名
|
||||||
image: dashboard-nanobot/nginx:${FRONTEND_IMAGE_TAG:-latest}
|
container_name: dashboard-nanobot-backend # 后端容器固定名称
|
||||||
container_name: dashboard-nanobot-nginx
|
restart: unless-stopped # 异常退出后自动拉起,手动停止时不自动启动
|
||||||
restart: unless-stopped
|
environment: # 后端环境变量
|
||||||
environment:
|
APP_HOST: 0.0.0.0 # 服务监听地址,容器内通常保持 0.0.0.0
|
||||||
UPLOAD_MAX_MB: ${UPLOAD_MAX_MB:-100}
|
APP_PORT: 8002 # 服务监听端口,需与 expose 和健康检查保持一致
|
||||||
depends_on:
|
APP_RELOAD: "false" # 生产环境关闭热重载
|
||||||
backend:
|
DATABASE_ECHO: "false" # 生产环境关闭 SQL 日志回显
|
||||||
condition: service_healthy
|
DATABASE_POOL_SIZE: ${DATABASE_POOL_SIZE:-20} # 数据库连接池基础连接数
|
||||||
ports:
|
DATABASE_MAX_OVERFLOW: ${DATABASE_MAX_OVERFLOW:-40} # 连接池额外可溢出连接数
|
||||||
- "${NGINX_PORT}:80"
|
DATABASE_POOL_TIMEOUT: ${DATABASE_POOL_TIMEOUT:-30} # 获取连接超时时间(秒)
|
||||||
healthcheck:
|
DATABASE_POOL_RECYCLE: ${DATABASE_POOL_RECYCLE:-1800} # 连接回收周期(秒)
|
||||||
test: ["CMD", "wget", "-q", "-O", "/dev/null", "http://127.0.0.1/"]
|
DATA_ROOT: /app/data # 容器内业务数据目录
|
||||||
interval: 15s
|
BOTS_WORKSPACE_ROOT: ${HOST_BOTS_WORKSPACE_ROOT} # Bot 工作目录,容器内外路径保持一致
|
||||||
timeout: 5s
|
DOCKER_NETWORK_NAME: ${DOCKER_NETWORK_NAME:-dashboard-nanobot-network} # 业务容器使用的 Docker 网络名称
|
||||||
retries: 5
|
DATABASE_URL: ${DATABASE_URL:-} # 外部 PostgreSQL 连接串,Prod 模式必须配置
|
||||||
start_period: 10s
|
REDIS_ENABLED: ${REDIS_ENABLED:-false} # 是否启用 Redis
|
||||||
logging:
|
REDIS_URL: ${REDIS_URL:-} # 外部 Redis 连接串
|
||||||
driver: json-file
|
REDIS_PREFIX: ${REDIS_PREFIX:-dashboard_nanobot} # Redis key 前缀
|
||||||
options:
|
REDIS_DEFAULT_TTL: ${REDIS_DEFAULT_TTL:-60} # Redis 默认过期时间(秒)
|
||||||
max-size: "20m"
|
DEFAULT_BOT_SYSTEM_TIMEZONE: ${DEFAULT_BOT_SYSTEM_TIMEZONE:-Asia/Shanghai} # Bot 默认时区
|
||||||
max-file: "3"
|
PANEL_ACCESS_PASSWORD: ${PANEL_ACCESS_PASSWORD:-} # 面板访问密码
|
||||||
|
WORKSPACE_PREVIEW_SIGNING_SECRET: ${WORKSPACE_PREVIEW_SIGNING_SECRET:-} # 预览签名密钥
|
||||||
|
WORKSPACE_PREVIEW_TOKEN_TTL_SECONDS: ${WORKSPACE_PREVIEW_TOKEN_TTL_SECONDS:-3600} # 预览令牌有效期(秒)
|
||||||
|
CORS_ALLOWED_ORIGINS: ${CORS_ALLOWED_ORIGINS:-} # 前端跨域白名单
|
||||||
|
STT_ENABLED: ${STT_ENABLED:-true} # 是否启用语音识别
|
||||||
|
STT_MODEL: ${STT_MODEL:-ggml-small-q8_0.bin} # 语音识别模型文件名
|
||||||
|
STT_MODEL_DIR: ${STT_MODEL_DIR:-/app/data/model} # 语音识别模型目录
|
||||||
|
STT_DEVICE: ${STT_DEVICE:-cpu} # 语音识别运行设备
|
||||||
|
STT_MAX_AUDIO_SECONDS: ${STT_MAX_AUDIO_SECONDS:-20} # 单次音频最大秒数
|
||||||
|
STT_DEFAULT_LANGUAGE: ${STT_DEFAULT_LANGUAGE:-zh} # 默认语音识别语言
|
||||||
|
STT_FORCE_SIMPLIFIED: ${STT_FORCE_SIMPLIFIED:-true} # 是否强制输出简体中文
|
||||||
|
STT_AUDIO_PREPROCESS: ${STT_AUDIO_PREPROCESS:-true} # 是否预处理音频
|
||||||
|
STT_AUDIO_FILTER: ${STT_AUDIO_FILTER:-highpass=f=120,lowpass=f=7600,afftdn=nf=-20} # 音频滤波参数
|
||||||
|
STT_INITIAL_PROMPT: ${STT_INITIAL_PROMPT:-以下内容可能包含简体中文和英文术语。请优先输出简体中文,英文单词、缩写、品牌名和数字保持原文,不要翻译。} # 语音识别初始提示词
|
||||||
|
volumes: # 宿主机与容器挂载关系
|
||||||
|
- /var/run/docker.sock:/var/run/docker.sock # 必须保留,后端需要管理 Bot 容器
|
||||||
|
- ./data:/app/data # 项目数据目录,建议保留在交付目录下
|
||||||
|
- ${HOST_BOTS_WORKSPACE_ROOT}:${HOST_BOTS_WORKSPACE_ROOT} # Bot 工作目录挂载,路径通常由客户现场决定
|
||||||
|
expose: # 只暴露给内部网络,不直接发布到宿主机
|
||||||
|
- "8002" # 后端服务端口
|
||||||
|
healthcheck: # 健康检查,供 nginx 依赖判断使用
|
||||||
|
test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8002/api/health', timeout=3).read()"] # 检测后端健康接口
|
||||||
|
interval: 15s # 每 15 秒检查一次
|
||||||
|
timeout: 5s # 单次检查超时 5 秒
|
||||||
|
retries: 5 # 连续失败 5 次判定不健康
|
||||||
|
start_period: 20s # 启动后预留 20 秒缓冲时间
|
||||||
|
logging: # 容器日志策略
|
||||||
|
driver: json-file # 使用 Docker 默认 json-file 日志驱动
|
||||||
|
options: # 日志滚动配置
|
||||||
|
max-size: "20m" # 单个日志文件最大 20MB
|
||||||
|
max-file: "3" # 最多保留 3 个日志文件
|
||||||
|
|
||||||
networks:
|
nginx: # 前端 Nginx 服务
|
||||||
default:
|
build: # 保留构建信息,离线部署通常直接使用导入镜像
|
||||||
name: ${DOCKER_NETWORK_NAME:-dashboard-nanobot-network}
|
context: ./frontend # 前端构建上下文
|
||||||
driver: bridge
|
dockerfile: Dockerfile # 前端 Dockerfile 路径
|
||||||
ipam:
|
args: # 前端构建参数
|
||||||
config:
|
NODE_BASE_IMAGE: ${NODE_BASE_IMAGE:-node:22-alpine} # Node 基础镜像
|
||||||
- subnet: ${DOCKER_NETWORK_SUBNET:-172.20.0.0/16}
|
NGINX_BASE_IMAGE: ${NGINX_BASE_IMAGE:-nginx:alpine} # Nginx 基础镜像
|
||||||
|
NPM_REGISTRY: ${NPM_REGISTRY:-https://registry.npmjs.org/} # npm 源地址
|
||||||
|
VITE_API_BASE: /api # 前端 API 前缀
|
||||||
|
VITE_WS_BASE: /ws/monitor # 前端 WebSocket 前缀
|
||||||
|
image: dashboard-nanobot/nginx:${FRONTEND_IMAGE_TAG:-latest} # 前端运行镜像名
|
||||||
|
container_name: dashboard-nanobot-nginx # 前端容器固定名称
|
||||||
|
restart: unless-stopped # 异常退出后自动拉起
|
||||||
|
environment: # 前端环境变量
|
||||||
|
UPLOAD_MAX_MB: ${UPLOAD_MAX_MB:-100} # 上传大小限制,传给 Nginx 配置使用
|
||||||
|
depends_on: # 依赖后端健康后再启动
|
||||||
|
backend: # 依赖后端容器
|
||||||
|
condition: service_healthy # 要求后端健康
|
||||||
|
ports: # 对外开放端口
|
||||||
|
- "${NGINX_PORT}:80" # 宿主机端口映射到容器 80 端口
|
||||||
|
healthcheck: # Nginx 健康检查
|
||||||
|
test: ["CMD", "wget", "-q", "-O", "/dev/null", "http://127.0.0.1/"] # 检测首页是否可访问
|
||||||
|
interval: 15s # 每 15 秒检查一次
|
||||||
|
timeout: 5s # 单次检查超时 5 秒
|
||||||
|
retries: 5 # 连续失败 5 次判定不健康
|
||||||
|
start_period: 10s # 启动后预留 10 秒缓冲时间
|
||||||
|
logging: # 容器日志策略
|
||||||
|
driver: json-file # 使用 Docker 默认 json-file 日志驱动
|
||||||
|
options: # 日志滚动配置
|
||||||
|
max-size: "20m" # 单个日志文件最大 20MB
|
||||||
|
max-file: "3" # 最多保留 3 个日志文件
|
||||||
|
|
||||||
|
networks: # 自定义网络配置
|
||||||
|
default: # 默认网络
|
||||||
|
name: ${DOCKER_NETWORK_NAME:-dashboard-nanobot-network} # 网络名称,客户通常无需修改
|
||||||
|
driver: bridge # 使用 bridge 网络驱动
|
||||||
|
ipam: # IP 地址管理配置
|
||||||
|
config: # 网段配置列表
|
||||||
|
- subnet: ${DOCKER_NETWORK_SUBNET:-172.20.0.0/16} # 自定义子网,现场冲突时可修改
|
||||||
|
|
|
||||||
|
|
@ -128,7 +128,7 @@ fi
|
||||||
echo "[deploy-prod-offline] using env: $ENV_FILE"
|
echo "[deploy-prod-offline] using env: $ENV_FILE"
|
||||||
mkdir -p "$DATA_DIR" "$DATA_DIR/model" "$HOST_BOTS_WORKSPACE_ROOT"
|
mkdir -p "$DATA_DIR" "$DATA_DIR/model" "$HOST_BOTS_WORKSPACE_ROOT"
|
||||||
|
|
||||||
echo "[deploy-prod-offline] expecting external PostgreSQL to be pre-initialized with scripts/sql/create-tables.sql and scripts/sql/init-data.sql"
|
echo "[deploy-prod-offline] expecting external PostgreSQL to be pre-initialized with sql/create-tables.sql and sql/init-data.sql, or by running ./init-db.sh"
|
||||||
docker compose --env-file "$ENV_FILE" -f "$COMPOSE_FILE" config -q
|
docker compose --env-file "$ENV_FILE" -f "$COMPOSE_FILE" config -q
|
||||||
docker compose --env-file "$ENV_FILE" -f "$COMPOSE_FILE" up -d
|
docker compose --env-file "$ENV_FILE" -f "$COMPOSE_FILE" up -d
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,213 +0,0 @@
|
||||||
# Dashboard Nanobot 离线部署编排文件(Full 模式)
|
|
||||||
#
|
|
||||||
# 说明:
|
|
||||||
# 1. 当前文件用于“前端 + 后端 + PostgreSQL + Redis”整套部署。
|
|
||||||
# 2. 客户通常只需要修改:
|
|
||||||
# - .env 里的 NGINX_PORT、HOST_BOTS_WORKSPACE_ROOT、数据库密码
|
|
||||||
# - volumes 里的宿主机挂载路径(如果不想用默认值)
|
|
||||||
# 3. HOST_BOTS_WORKSPACE_ROOT 必须是宿主机绝对路径。
|
|
||||||
# 4. /var/run/docker.sock 必须保留挂载,否则后端无法管理 Bot 容器。
|
|
||||||
|
|
||||||
services:
|
|
||||||
# PostgreSQL 数据库服务
|
|
||||||
postgres:
|
|
||||||
image: ${POSTGRES_IMAGE:-postgres:16-alpine}
|
|
||||||
container_name: dashboard-nanobot-postgres
|
|
||||||
restart: unless-stopped
|
|
||||||
|
|
||||||
environment:
|
|
||||||
TZ: ${TZ:-Asia/Shanghai}
|
|
||||||
POSTGRES_USER: ${POSTGRES_SUPERUSER:-postgres}
|
|
||||||
POSTGRES_PASSWORD: ${POSTGRES_SUPERPASSWORD:?POSTGRES_SUPERPASSWORD is required}
|
|
||||||
POSTGRES_DB: ${POSTGRES_BOOTSTRAP_DB:-postgres}
|
|
||||||
|
|
||||||
# 数据库存储目录:客户如需改磁盘路径,可直接改左侧宿主机路径
|
|
||||||
volumes:
|
|
||||||
- ./data/postgres:/var/lib/postgresql/data
|
|
||||||
|
|
||||||
expose:
|
|
||||||
- "5432"
|
|
||||||
|
|
||||||
healthcheck:
|
|
||||||
test: ["CMD-SHELL", "pg_isready -U \"$${POSTGRES_USER}\" -d \"$${POSTGRES_DB}\""]
|
|
||||||
interval: 10s
|
|
||||||
timeout: 5s
|
|
||||||
retries: 10
|
|
||||||
start_period: 20s
|
|
||||||
|
|
||||||
logging:
|
|
||||||
driver: json-file
|
|
||||||
options:
|
|
||||||
max-size: "20m"
|
|
||||||
max-file: "3"
|
|
||||||
|
|
||||||
# Redis 缓存服务
|
|
||||||
redis:
|
|
||||||
image: ${REDIS_IMAGE:-redis:7-alpine}
|
|
||||||
container_name: dashboard-nanobot-redis
|
|
||||||
restart: unless-stopped
|
|
||||||
|
|
||||||
environment:
|
|
||||||
TZ: ${TZ:-Asia/Shanghai}
|
|
||||||
|
|
||||||
command: ["redis-server", "--appendonly", "yes", "--save", "60", "1000"]
|
|
||||||
|
|
||||||
# Redis 数据存储目录
|
|
||||||
volumes:
|
|
||||||
- ./data/redis:/data
|
|
||||||
|
|
||||||
expose:
|
|
||||||
- "6379"
|
|
||||||
|
|
||||||
healthcheck:
|
|
||||||
test: ["CMD", "redis-cli", "ping"]
|
|
||||||
interval: 10s
|
|
||||||
timeout: 5s
|
|
||||||
retries: 10
|
|
||||||
start_period: 10s
|
|
||||||
|
|
||||||
logging:
|
|
||||||
driver: json-file
|
|
||||||
options:
|
|
||||||
max-size: "20m"
|
|
||||||
max-file: "3"
|
|
||||||
|
|
||||||
# 后端服务:Dashboard 主 API 服务
|
|
||||||
backend:
|
|
||||||
build:
|
|
||||||
context: .
|
|
||||||
dockerfile: backend/Dockerfile
|
|
||||||
args:
|
|
||||||
PYTHON_BASE_IMAGE: ${PYTHON_BASE_IMAGE:-python:3.12-slim}
|
|
||||||
PIP_INDEX_URL: ${PIP_INDEX_URL:-https://pypi.org/simple}
|
|
||||||
PIP_TRUSTED_HOST: ${PIP_TRUSTED_HOST:-}
|
|
||||||
|
|
||||||
image: dashboard-nanobot/backend:${BACKEND_IMAGE_TAG:-latest}
|
|
||||||
container_name: dashboard-nanobot-backend
|
|
||||||
restart: unless-stopped
|
|
||||||
|
|
||||||
depends_on:
|
|
||||||
postgres:
|
|
||||||
condition: service_healthy
|
|
||||||
redis:
|
|
||||||
condition: service_healthy
|
|
||||||
|
|
||||||
environment:
|
|
||||||
TZ: ${TZ:-Asia/Shanghai}
|
|
||||||
APP_HOST: 0.0.0.0
|
|
||||||
APP_PORT: 8000
|
|
||||||
APP_RELOAD: "false"
|
|
||||||
DATABASE_ECHO: "false"
|
|
||||||
DATABASE_POOL_SIZE: ${DATABASE_POOL_SIZE:-20}
|
|
||||||
DATABASE_MAX_OVERFLOW: ${DATABASE_MAX_OVERFLOW:-40}
|
|
||||||
DATABASE_POOL_TIMEOUT: ${DATABASE_POOL_TIMEOUT:-30}
|
|
||||||
DATABASE_POOL_RECYCLE: ${DATABASE_POOL_RECYCLE:-1800}
|
|
||||||
DATA_ROOT: /app/data
|
|
||||||
|
|
||||||
# Bot 工作目录:必须和宿主机路径保持一致
|
|
||||||
BOTS_WORKSPACE_ROOT: ${HOST_BOTS_WORKSPACE_ROOT}
|
|
||||||
|
|
||||||
DOCKER_NETWORK_NAME: ${DOCKER_NETWORK_NAME:-dashboard-nanobot-network}
|
|
||||||
|
|
||||||
# Full 模式下数据库固定连容器内 postgres
|
|
||||||
DATABASE_URL: postgresql+psycopg://${POSTGRES_APP_USER}:${POSTGRES_APP_PASSWORD}@postgres:5432/${POSTGRES_APP_DB}
|
|
||||||
|
|
||||||
# Full 模式下 Redis 固定连容器内 redis
|
|
||||||
REDIS_ENABLED: ${REDIS_ENABLED:-true}
|
|
||||||
REDIS_URL: redis://redis:6379/${REDIS_DB:-8}
|
|
||||||
REDIS_PREFIX: ${REDIS_PREFIX:-dashboard_nanobot}
|
|
||||||
REDIS_DEFAULT_TTL: ${REDIS_DEFAULT_TTL:-60}
|
|
||||||
|
|
||||||
DEFAULT_BOT_SYSTEM_TIMEZONE: ${DEFAULT_BOT_SYSTEM_TIMEZONE:-Asia/Shanghai}
|
|
||||||
PANEL_ACCESS_PASSWORD: ${PANEL_ACCESS_PASSWORD:-}
|
|
||||||
WORKSPACE_PREVIEW_SIGNING_SECRET: ${WORKSPACE_PREVIEW_SIGNING_SECRET:-}
|
|
||||||
WORKSPACE_PREVIEW_TOKEN_TTL_SECONDS: ${WORKSPACE_PREVIEW_TOKEN_TTL_SECONDS:-3600}
|
|
||||||
CORS_ALLOWED_ORIGINS: ${CORS_ALLOWED_ORIGINS:-}
|
|
||||||
|
|
||||||
# 语音识别模型配置:如果启用 STT,模型文件需要放到 data/model/
|
|
||||||
STT_ENABLED: ${STT_ENABLED:-true}
|
|
||||||
STT_MODEL: ${STT_MODEL:-ggml-small-q8_0.bin}
|
|
||||||
STT_MODEL_DIR: ${STT_MODEL_DIR:-/app/data/model}
|
|
||||||
STT_DEVICE: ${STT_DEVICE:-cpu}
|
|
||||||
STT_MAX_AUDIO_SECONDS: ${STT_MAX_AUDIO_SECONDS:-20}
|
|
||||||
STT_DEFAULT_LANGUAGE: ${STT_DEFAULT_LANGUAGE:-zh}
|
|
||||||
STT_FORCE_SIMPLIFIED: ${STT_FORCE_SIMPLIFIED:-true}
|
|
||||||
STT_AUDIO_PREPROCESS: ${STT_AUDIO_PREPROCESS:-true}
|
|
||||||
STT_AUDIO_FILTER: ${STT_AUDIO_FILTER:-highpass=f=120,lowpass=f=7600,afftdn=nf=-20}
|
|
||||||
STT_INITIAL_PROMPT: ${STT_INITIAL_PROMPT:-以下内容可能包含简体中文和英文术语。请优先输出简体中文,英文单词、缩写、品牌名和数字保持原文,不要翻译。}
|
|
||||||
|
|
||||||
# 关键挂载:
|
|
||||||
# 1. docker.sock:必须保留
|
|
||||||
# 2. ./data:建议保留在交付目录下
|
|
||||||
# 3. HOST_BOTS_WORKSPACE_ROOT:客户可按现场路径修改
|
|
||||||
volumes:
|
|
||||||
- /var/run/docker.sock:/var/run/docker.sock
|
|
||||||
- ./data:/app/data
|
|
||||||
- ${HOST_BOTS_WORKSPACE_ROOT}:${HOST_BOTS_WORKSPACE_ROOT}
|
|
||||||
|
|
||||||
expose:
|
|
||||||
- "8000"
|
|
||||||
|
|
||||||
healthcheck:
|
|
||||||
test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8000/api/health', timeout=3).read()"]
|
|
||||||
interval: 15s
|
|
||||||
timeout: 5s
|
|
||||||
retries: 5
|
|
||||||
start_period: 20s
|
|
||||||
|
|
||||||
logging:
|
|
||||||
driver: json-file
|
|
||||||
options:
|
|
||||||
max-size: "20m"
|
|
||||||
max-file: "3"
|
|
||||||
|
|
||||||
# 前端服务:Nginx 托管前端并反向代理后端 API
|
|
||||||
nginx:
|
|
||||||
build:
|
|
||||||
context: ./frontend
|
|
||||||
dockerfile: Dockerfile
|
|
||||||
args:
|
|
||||||
NODE_BASE_IMAGE: ${NODE_BASE_IMAGE:-node:22-alpine}
|
|
||||||
NGINX_BASE_IMAGE: ${NGINX_BASE_IMAGE:-nginx:alpine}
|
|
||||||
NPM_REGISTRY: ${NPM_REGISTRY:-https://registry.npmjs.org/}
|
|
||||||
VITE_API_BASE: /api
|
|
||||||
VITE_WS_BASE: /ws/monitor
|
|
||||||
|
|
||||||
image: dashboard-nanobot/nginx:${FRONTEND_IMAGE_TAG:-latest}
|
|
||||||
container_name: dashboard-nanobot-nginx
|
|
||||||
restart: unless-stopped
|
|
||||||
|
|
||||||
environment:
|
|
||||||
TZ: ${TZ:-Asia/Shanghai}
|
|
||||||
# 上传大小限制:只限制 Nginx 入口
|
|
||||||
UPLOAD_MAX_MB: ${UPLOAD_MAX_MB:-100}
|
|
||||||
|
|
||||||
depends_on:
|
|
||||||
backend:
|
|
||||||
condition: service_healthy
|
|
||||||
|
|
||||||
# 对外访问端口:客户通常会改这个
|
|
||||||
ports:
|
|
||||||
- "${NGINX_PORT}:80"
|
|
||||||
|
|
||||||
healthcheck:
|
|
||||||
test: ["CMD", "wget", "-q", "-O", "/dev/null", "http://127.0.0.1/"]
|
|
||||||
interval: 15s
|
|
||||||
timeout: 5s
|
|
||||||
retries: 5
|
|
||||||
start_period: 10s
|
|
||||||
|
|
||||||
logging:
|
|
||||||
driver: json-file
|
|
||||||
options:
|
|
||||||
max-size: "20m"
|
|
||||||
max-file: "3"
|
|
||||||
|
|
||||||
# 自定义 Docker 网络:如果客户现场网段冲突,可以改 subnet
|
|
||||||
networks:
|
|
||||||
default:
|
|
||||||
name: ${DOCKER_NETWORK_NAME:-dashboard-nanobot-network}
|
|
||||||
driver: bridge
|
|
||||||
ipam:
|
|
||||||
config:
|
|
||||||
- subnet: ${DOCKER_NETWORK_SUBNET:-172.20.0.0/16}
|
|
||||||
|
|
@ -1,149 +0,0 @@
|
||||||
# Dashboard Nanobot 离线部署编排文件(Prod 模式)
|
|
||||||
#
|
|
||||||
# 说明:
|
|
||||||
# 1. 当前文件用于“前端 + 后端”部署,数据库和 Redis 由客户外部提供。
|
|
||||||
# 2. 客户通常只需要修改:
|
|
||||||
# - .env 里的 NGINX_PORT、DATABASE_URL、REDIS_URL、HOST_BOTS_WORKSPACE_ROOT
|
|
||||||
# - volumes 里的宿主机挂载路径(如果不想用默认值)
|
|
||||||
# 3. HOST_BOTS_WORKSPACE_ROOT 必须是宿主机绝对路径。
|
|
||||||
# 4. /var/run/docker.sock 必须保留挂载,否则后端无法管理 Bot 容器。
|
|
||||||
|
|
||||||
services:
|
|
||||||
# 后端服务:Dashboard 主 API 服务
|
|
||||||
backend:
|
|
||||||
# 镜像构建配置:正常情况下客户离线部署不需要重新 build,
|
|
||||||
# 但保留 build 信息方便后续有源码时重新构建。
|
|
||||||
build:
|
|
||||||
context: .
|
|
||||||
dockerfile: backend/Dockerfile
|
|
||||||
args:
|
|
||||||
PYTHON_BASE_IMAGE: ${PYTHON_BASE_IMAGE:-python:3.12-slim}
|
|
||||||
PIP_INDEX_URL: ${PIP_INDEX_URL:-https://pypi.org/simple}
|
|
||||||
PIP_TRUSTED_HOST: ${PIP_TRUSTED_HOST:-}
|
|
||||||
|
|
||||||
# 后端镜像名:由离线导入的镜像提供
|
|
||||||
image: dashboard-nanobot/backend:${BACKEND_IMAGE_TAG:-latest}
|
|
||||||
container_name: dashboard-nanobot-backend
|
|
||||||
restart: unless-stopped
|
|
||||||
|
|
||||||
# 运行环境变量:数据库、Redis、语音识别等主要配置都走这里
|
|
||||||
environment:
|
|
||||||
APP_HOST: 0.0.0.0
|
|
||||||
APP_PORT: 8002
|
|
||||||
APP_RELOAD: "false"
|
|
||||||
DATABASE_ECHO: "false"
|
|
||||||
DATABASE_POOL_SIZE: ${DATABASE_POOL_SIZE:-20}
|
|
||||||
DATABASE_MAX_OVERFLOW: ${DATABASE_MAX_OVERFLOW:-40}
|
|
||||||
DATABASE_POOL_TIMEOUT: ${DATABASE_POOL_TIMEOUT:-30}
|
|
||||||
DATABASE_POOL_RECYCLE: ${DATABASE_POOL_RECYCLE:-1800}
|
|
||||||
DATA_ROOT: /app/data
|
|
||||||
|
|
||||||
# Bot 工作目录:必须和宿主机路径保持一致
|
|
||||||
BOTS_WORKSPACE_ROOT: ${HOST_BOTS_WORKSPACE_ROOT}
|
|
||||||
|
|
||||||
# Docker 网络名:通常不用改,除非客户现场网络有冲突
|
|
||||||
DOCKER_NETWORK_NAME: ${DOCKER_NETWORK_NAME:-dashboard-nanobot-network}
|
|
||||||
|
|
||||||
# 外部 PostgreSQL 连接串:Prod 模式客户必须改这里
|
|
||||||
DATABASE_URL: ${DATABASE_URL:-}
|
|
||||||
|
|
||||||
# 外部 Redis 配置:如果不用 Redis,可把 REDIS_ENABLED 改成 false
|
|
||||||
REDIS_ENABLED: ${REDIS_ENABLED:-false}
|
|
||||||
REDIS_URL: ${REDIS_URL:-}
|
|
||||||
REDIS_PREFIX: ${REDIS_PREFIX:-dashboard_nanobot}
|
|
||||||
REDIS_DEFAULT_TTL: ${REDIS_DEFAULT_TTL:-60}
|
|
||||||
|
|
||||||
DEFAULT_BOT_SYSTEM_TIMEZONE: ${DEFAULT_BOT_SYSTEM_TIMEZONE:-Asia/Shanghai}
|
|
||||||
PANEL_ACCESS_PASSWORD: ${PANEL_ACCESS_PASSWORD:-}
|
|
||||||
WORKSPACE_PREVIEW_SIGNING_SECRET: ${WORKSPACE_PREVIEW_SIGNING_SECRET:-}
|
|
||||||
WORKSPACE_PREVIEW_TOKEN_TTL_SECONDS: ${WORKSPACE_PREVIEW_TOKEN_TTL_SECONDS:-3600}
|
|
||||||
CORS_ALLOWED_ORIGINS: ${CORS_ALLOWED_ORIGINS:-}
|
|
||||||
|
|
||||||
# 语音识别模型配置:如果启用 STT,模型文件需要放到 data/model/
|
|
||||||
STT_ENABLED: ${STT_ENABLED:-true}
|
|
||||||
STT_MODEL: ${STT_MODEL:-ggml-small-q8_0.bin}
|
|
||||||
STT_MODEL_DIR: ${STT_MODEL_DIR:-/app/data/model}
|
|
||||||
STT_DEVICE: ${STT_DEVICE:-cpu}
|
|
||||||
STT_MAX_AUDIO_SECONDS: ${STT_MAX_AUDIO_SECONDS:-20}
|
|
||||||
STT_DEFAULT_LANGUAGE: ${STT_DEFAULT_LANGUAGE:-zh}
|
|
||||||
STT_FORCE_SIMPLIFIED: ${STT_FORCE_SIMPLIFIED:-true}
|
|
||||||
STT_AUDIO_PREPROCESS: ${STT_AUDIO_PREPROCESS:-true}
|
|
||||||
STT_AUDIO_FILTER: ${STT_AUDIO_FILTER:-highpass=f=120,lowpass=f=7600,afftdn=nf=-20}
|
|
||||||
STT_INITIAL_PROMPT: ${STT_INITIAL_PROMPT:-以下内容可能包含简体中文和英文术语。请优先输出简体中文,英文单词、缩写、品牌名和数字保持原文,不要翻译。}
|
|
||||||
|
|
||||||
# 关键挂载:
|
|
||||||
# 1. docker.sock:必须保留
|
|
||||||
# 2. ./data:建议保留在交付目录下
|
|
||||||
# 3. HOST_BOTS_WORKSPACE_ROOT:客户可按现场路径修改
|
|
||||||
volumes:
|
|
||||||
- /var/run/docker.sock:/var/run/docker.sock
|
|
||||||
- ./data:/app/data
|
|
||||||
- ${HOST_BOTS_WORKSPACE_ROOT}:${HOST_BOTS_WORKSPACE_ROOT}
|
|
||||||
|
|
||||||
# 仅在内部网络暴露给 nginx,不直接映射到宿主机端口
|
|
||||||
expose:
|
|
||||||
- "8002"
|
|
||||||
|
|
||||||
# 健康检查:用于确保 nginx 只在后端健康后启动
|
|
||||||
healthcheck:
|
|
||||||
test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8002/api/health', timeout=3).read()"]
|
|
||||||
interval: 15s
|
|
||||||
timeout: 5s
|
|
||||||
retries: 5
|
|
||||||
start_period: 20s
|
|
||||||
|
|
||||||
logging:
|
|
||||||
driver: json-file
|
|
||||||
options:
|
|
||||||
max-size: "20m"
|
|
||||||
max-file: "3"
|
|
||||||
|
|
||||||
# 前端服务:Nginx 托管前端并反向代理后端 API
|
|
||||||
nginx:
|
|
||||||
build:
|
|
||||||
context: ./frontend
|
|
||||||
dockerfile: Dockerfile
|
|
||||||
args:
|
|
||||||
NODE_BASE_IMAGE: ${NODE_BASE_IMAGE:-node:22-alpine}
|
|
||||||
NGINX_BASE_IMAGE: ${NGINX_BASE_IMAGE:-nginx:alpine}
|
|
||||||
NPM_REGISTRY: ${NPM_REGISTRY:-https://registry.npmjs.org/}
|
|
||||||
VITE_API_BASE: /api
|
|
||||||
VITE_WS_BASE: /ws/monitor
|
|
||||||
|
|
||||||
image: dashboard-nanobot/nginx:${FRONTEND_IMAGE_TAG:-latest}
|
|
||||||
container_name: dashboard-nanobot-nginx
|
|
||||||
restart: unless-stopped
|
|
||||||
|
|
||||||
environment:
|
|
||||||
# 上传大小限制:只限制 Nginx 入口
|
|
||||||
UPLOAD_MAX_MB: ${UPLOAD_MAX_MB:-100}
|
|
||||||
|
|
||||||
depends_on:
|
|
||||||
backend:
|
|
||||||
condition: service_healthy
|
|
||||||
|
|
||||||
# 对外访问端口:客户通常会改这个
|
|
||||||
ports:
|
|
||||||
- "${NGINX_PORT}:80"
|
|
||||||
|
|
||||||
healthcheck:
|
|
||||||
test: ["CMD", "wget", "-q", "-O", "/dev/null", "http://127.0.0.1/"]
|
|
||||||
interval: 15s
|
|
||||||
timeout: 5s
|
|
||||||
retries: 5
|
|
||||||
start_period: 10s
|
|
||||||
|
|
||||||
logging:
|
|
||||||
driver: json-file
|
|
||||||
options:
|
|
||||||
max-size: "20m"
|
|
||||||
max-file: "3"
|
|
||||||
|
|
||||||
# 自定义 Docker 网络:如果客户现场网段冲突,可以改 subnet
|
|
||||||
networks:
|
|
||||||
default:
|
|
||||||
name: ${DOCKER_NETWORK_NAME:-dashboard-nanobot-network}
|
|
||||||
driver: bridge
|
|
||||||
ipam:
|
|
||||||
config:
|
|
||||||
- subnet: ${DOCKER_NETWORK_SUBNET:-172.20.0.0/16}
|
|
||||||
|
|
@ -119,7 +119,7 @@ copy_into_bundle() {
|
||||||
}
|
}
|
||||||
|
|
||||||
write_bundle_compose() {
|
write_bundle_compose() {
|
||||||
cp "$ROOT_DIR/offline/docker-compose.$MODE.yml" "$BUNDLE_DIR/docker-compose.yml"
|
cp "$ROOT_DIR/docker-compose.$MODE.yml" "$BUNDLE_DIR/docker-compose.yml"
|
||||||
}
|
}
|
||||||
|
|
||||||
copy_sql_bundle() {
|
copy_sql_bundle() {
|
||||||
|
|
|
||||||
|
|
@ -4,10 +4,10 @@ set -euo pipefail
|
||||||
ROOT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
|
ROOT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
|
||||||
ENV_FILE="${1:-$ROOT_DIR/.env}"
|
ENV_FILE="${1:-$ROOT_DIR/.env}"
|
||||||
COMPOSE_FILE="$ROOT_DIR/docker-compose.yml"
|
COMPOSE_FILE="$ROOT_DIR/docker-compose.yml"
|
||||||
BOOTSTRAP_SQL="$ROOT_DIR/scripts/sql/init-postgres-bootstrap.sql"
|
BOOTSTRAP_SQL="$ROOT_DIR/sql/init-postgres-bootstrap.sql"
|
||||||
APP_SQL="$ROOT_DIR/scripts/sql/init-postgres-app.sql"
|
APP_SQL="$ROOT_DIR/sql/init-postgres-app.sql"
|
||||||
SCHEMA_SQL="$ROOT_DIR/scripts/sql/create-tables.sql"
|
SCHEMA_SQL="$ROOT_DIR/sql/create-tables.sql"
|
||||||
SEED_SQL="$ROOT_DIR/scripts/sql/init-data.sql"
|
SEED_SQL="$ROOT_DIR/sql/init-data.sql"
|
||||||
|
|
||||||
if [[ ! -f "$ENV_FILE" && -f "$ROOT_DIR/.env.full" ]]; then
|
if [[ ! -f "$ENV_FILE" && -f "$ROOT_DIR/.env.full" ]]; then
|
||||||
ENV_FILE="$ROOT_DIR/.env.full"
|
ENV_FILE="$ROOT_DIR/.env.full"
|
||||||
|
|
@ -17,6 +17,22 @@ if [[ ! -f "$COMPOSE_FILE" && -f "$ROOT_DIR/docker-compose.full.yml" ]]; then
|
||||||
COMPOSE_FILE="$ROOT_DIR/docker-compose.full.yml"
|
COMPOSE_FILE="$ROOT_DIR/docker-compose.full.yml"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [[ ! -f "$BOOTSTRAP_SQL" && -f "$ROOT_DIR/scripts/sql/init-postgres-bootstrap.sql" ]]; then
|
||||||
|
BOOTSTRAP_SQL="$ROOT_DIR/scripts/sql/init-postgres-bootstrap.sql"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ! -f "$APP_SQL" && -f "$ROOT_DIR/scripts/sql/init-postgres-app.sql" ]]; then
|
||||||
|
APP_SQL="$ROOT_DIR/scripts/sql/init-postgres-app.sql"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ! -f "$SCHEMA_SQL" && -f "$ROOT_DIR/scripts/sql/create-tables.sql" ]]; then
|
||||||
|
SCHEMA_SQL="$ROOT_DIR/scripts/sql/create-tables.sql"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ! -f "$SEED_SQL" && -f "$ROOT_DIR/scripts/sql/init-data.sql" ]]; then
|
||||||
|
SEED_SQL="$ROOT_DIR/scripts/sql/init-data.sql"
|
||||||
|
fi
|
||||||
|
|
||||||
require_file() {
|
require_file() {
|
||||||
local path="$1"
|
local path="$1"
|
||||||
local hint="${2:-}"
|
local hint="${2:-}"
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue