baodan/docker-compose.dify.yml
2026-08-05 17:51:16 +08:00

416 lines
17 KiB
YAML
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.

# BaoDan 开发环境 - 使用独立的 PostgreSQL 和 Redis
# 用法: docker compose -f docker-compose.baodan.yml up -d
services:
# ---- PostgreSQL ----
db:
image: pgvector/pgvector:pg15
environment:
POSTGRES_DB: ${POSTGRES_DB:-baodan}
POSTGRES_USER: ${POSTGRES_USER:-postgres}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?请在 .env 文件中设置 POSTGRES_PASSWORD}
volumes:
- baodan_pg_data:/var/lib/postgresql/data
- ./deploy/sql/init.sql:/docker-entrypoint-initdb.d/01-init.sql
- ./deploy/sql/init-plugin-db.sql:/docker-entrypoint-initdb.d/02-init-plugin-db.sql
ports:
- "5433:5432"
restart: unless-stopped
# ---- Redis ----
redis:
image: redis:7-alpine
volumes:
- baodan_redis_data:/data
ports:
- "6380:6379"
restart: unless-stopped
# ---- BaoDan API自定义镜像含 insurance Blueprint----
baodan-api:
build:
context: .
dockerfile: Dockerfile.dify-custom
image: baodanagent-api:local
user: root
command:
- gunicorn
- --bind
- 0.0.0.0:5001
- --workers
- ${INSURANCE_API_WORKERS:-4}
- --worker-class
- geventwebsocket.gunicorn.workers.GeventWebSocketWorker
- --worker-connections
- ${INSURANCE_API_WORKER_CONNECTIONS:-1000}
- --timeout
- "300"
- --graceful-timeout
- "30"
- --keep-alive
- "5"
- app:flask_app
environment: &baodan_api_environment
DB_TYPE: postgresql
DB_USERNAME: ${POSTGRES_USER:-postgres}
DB_PASSWORD: ${POSTGRES_PASSWORD:?请在 .env 文件中设置 POSTGRES_PASSWORD}
DB_HOST: db
DB_PORT: 5432
DB_DATABASE: ${POSTGRES_DB:-baodan}
SQLALCHEMY_POOL_PRE_PING: ${SQLALCHEMY_POOL_PRE_PING:-true}
SQLALCHEMY_POOL_RECYCLE: ${SQLALCHEMY_POOL_RECYCLE:-300}
REDIS_HOST: redis
REDIS_PORT: 6379
REDIS_PASSWORD: ""
REDIS_DB: 0
CONSOLE_API_URL: ${CONSOLE_API_URL:-http://localhost:5001}
CONSOLE_WEB_URL: ${CONSOLE_WEB_URL:-http://localhost:3000}
SERVICE_API_URL: ${SERVICE_API_URL:-http://localhost:5001}
APP_WEB_URL: ${APP_WEB_URL:-http://localhost:3000}
FILES_URL: ${FILES_URL:-http://localhost:5001}
SECRET_KEY: ${SECRET_KEY:?请在 .env 文件中设置 SECRET_KEY}
INIT_PASSWORD: ${INIT_PASSWORD:?请在 .env 文件中设置 INIT_PASSWORD}
LOG_LEVEL: ${LOG_LEVEL:-INFO}
INSURANCE_STORAGE_ROOT: ${INSURANCE_STORAGE_ROOT:-/app/api/storage/insurance}
POSTER_USER_MANUAL_UPLOAD_ENABLED: ${POSTER_USER_MANUAL_UPLOAD_ENABLED:-true}
MAIL_TYPE: ${MAIL_TYPE:-}
MAIL_DEFAULT_SEND_FROM: ${MAIL_DEFAULT_SEND_FROM:-}
SMTP_SERVER: ${SMTP_SERVER:-}
SMTP_PORT: ${SMTP_PORT:-587}
SMTP_USERNAME: ${SMTP_USERNAME:-}
SMTP_PASSWORD: ${SMTP_PASSWORD:-}
SMTP_USE_TLS: ${SMTP_USE_TLS:-false}
SMTP_OPPORTUNISTIC_TLS: ${SMTP_OPPORTUNISTIC_TLS:-false}
RESEND_API_KEY: ${RESEND_API_KEY:-}
RESEND_API_URL: ${RESEND_API_URL:-}
SENDGRID_API_KEY: ${SENDGRID_API_KEY:-}
MIGRATION_ENABLED: "true"
CELERY_BROKER_URL: redis://redis:6379/1
# 文件上传限制(取消限制)
UPLOAD_FILE_BATCH_LIMIT: "99999"
BATCH_UPLOAD_LIMIT: "99999"
# 向量数据库配置 - 使用 pgvector复用 PostgreSQL
VECTOR_STORE: pgvector
PGVECTOR_HOST: db
PGVECTOR_PORT: 5432
PGVECTOR_USER: ${POSTGRES_USER:-postgres}
PGVECTOR_PASSWORD: ${POSTGRES_PASSWORD:?请在 .env 文件中设置 POSTGRES_PASSWORD}
PGVECTOR_DATABASE: ${POSTGRES_DB:-baodan}
# 代码执行沙箱
CODE_EXECUTION_ENDPOINT: http://sandbox:8194
CODE_EXECUTION_API_KEY: ${CODE_EXECUTION_API_KEY:?请在 .env 文件中设置 CODE_EXECUTION_API_KEY}
# SSRF 代理
SSRF_PROXY_HTTP_URL: ""
SSRF_PROXY_HTTPS_URL: ""
# 保险模块配置(需在后台创建应用后填入真实 API Key
BAODAN_CHAT_API_KEY: ${BAODAN_CHAT_API_KEY:?请在 .env 文件中设置 BAODAN_CHAT_API_KEY}
BAODAN_WORKFLOW_API_KEY: ${BAODAN_WORKFLOW_API_KEY:?请在 .env 文件中设置 BAODAN_WORKFLOW_API_KEY}
BAODAN_KB_API_KEY: ${BAODAN_KB_API_KEY:?请在 .env 文件中设置 BAODAN_KB_API_KEY}
BAODAN_API_URL: "http://baodan-core-api:5001"
# 智能问答原子准入(灰度开启前先将 MAX_ACTIVE 配为不高于 Dify 有效上限)
CHAT_GATEWAY_ADMISSION_V1: ${CHAT_GATEWAY_ADMISSION_V1:-false}
CHAT_GATEWAY_MAX_ACTIVE: ${CHAT_GATEWAY_MAX_ACTIVE:-}
CHAT_GATEWAY_USER_MAX_ACTIVE: ${CHAT_GATEWAY_USER_MAX_ACTIVE:-1}
CHAT_GATEWAY_ACQUIRE_TIMEOUT_MS: ${CHAT_GATEWAY_ACQUIRE_TIMEOUT_MS:-3000}
CHAT_GATEWAY_LEASE_SECONDS: ${CHAT_GATEWAY_LEASE_SECONDS:-180}
CHAT_GATEWAY_RENEW_SECONDS: ${CHAT_GATEWAY_RENEW_SECONDS:-30}
CHAT_GATEWAY_RETRY_AFTER: ${CHAT_GATEWAY_RETRY_AFTER:-3}
CHAT_AGENT_ACCESS_V1: ${CHAT_AGENT_ACCESS_V1:-false}
CHAT_AGENT_ACCESS_DEFAULT_ALLOW: ${CHAT_AGENT_ACCESS_DEFAULT_ALLOW:-false}
# 后台生成链路灰度开关
GENERATION_OUTBOX_V1: ${GENERATION_OUTBOX_V1:-false}
GENERATION_OUTBOX_PUBLISH_V1: ${GENERATION_OUTBOX_PUBLISH_V1:-false}
GENERATION_SPLIT_QUEUES_V1: ${GENERATION_SPLIT_QUEUES_V1:-false}
POSTER_COPY_ASYNC_V1: ${POSTER_COPY_ASYNC_V1:-false}
MODEL_POOL_V1: ${MODEL_POOL_V1:-false}
GENERATION_USER_MAX_RUNNING: ${GENERATION_USER_MAX_RUNNING:-2}
GENERATION_USER_MAX_QUEUED: ${GENERATION_USER_MAX_QUEUED:-20}
GENERATION_HEARTBEAT_SECONDS: ${GENERATION_HEARTBEAT_SECONDS:-30}
INSURANCE_CREDENTIAL_MASTER_KEY: ${INSURANCE_CREDENTIAL_MASTER_KEY:-}
INSURANCE_CREDENTIAL_KEY_VERSION: ${INSURANCE_CREDENTIAL_KEY_VERSION:-1}
INSURANCE_CREDENTIAL_MASTER_KEYS: ${INSURANCE_CREDENTIAL_MASTER_KEYS:-}
INSURANCE_METRICS_TOKEN: ${INSURANCE_METRICS_TOKEN:-}
# 访客模式true=免登录使用false=需要登录
GUEST_MODE: ${GUEST_MODE:-false}
# 插件服务配置
PLUGIN_DAEMON_URL: http://plugin_daemon:5002
PLUGIN_DAEMON_KEY: ${PLUGIN_DAEMON_KEY:?请在 .env 文件中设置 PLUGIN_DAEMON_KEY}
PLUGIN_DAEMON_TIMEOUT: "600.0"
# 启用市场(用于安装模型供应商插件)
MARKETPLACE_ENABLED: "true"
EXPLORER_ENABLED: "false"
# CORS 配置(不能用 * 配合 credentials必须明确列出 origin
CONSOLE_CORS_ALLOW_ORIGINS: ${CONSOLE_CORS_ALLOW_ORIGINS:-http://localhost:3000}
WEB_API_CORS_ALLOW_ORIGINS: ${WEB_API_CORS_ALLOW_ORIGINS:-http://localhost:3000}
# 自动初始化管理员配置
ADMIN_EMAIL: ${ADMIN_EMAIL:-admin@example.com}
ADMIN_NAME: ${ADMIN_NAME:-admin}
ADMIN_PASSWORD: ${ADMIN_PASSWORD:?请在 .env 文件中设置 ADMIN_PASSWORD}
ADMIN_WORKSPACE: ${ADMIN_WORKSPACE:-BaoDan Workspace}
# JWT 配置
JWT_SECRET: ${JWT_SECRET:?请在 .env 文件中设置 JWT_SECRET}
JWT_EXPIRE_SECONDS: ${JWT_EXPIRE_SECONDS:-7200}
# 企微配置(生产环境需替换为真实值)
# 在企微后台 → 应用管理 → 接收消息 → 设置接收消息服务器 中获取
WECOM_CORP_ID: ${WECOM_CORP_ID:-} # 企业ID
WECOM_SECRET: ${WECOM_SECRET:-} # 应用Secret
WECOM_TOKEN: ${WECOM_TOKEN:-} # 回调Token自定义
WECOM_AES_KEY: ${WECOM_AES_KEY:-} # 消息加密密钥43位字符
# OAuth 回调基础地址企微后台「网页授权及JS回调域」需与此一致
BASE_URL: ${BASE_URL:-http://localhost:5001}
# 前端地址OAuth 成功后重定向到前端)
FRONTEND_URL: ${FRONTEND_URL:-http://localhost:9080}
# 群机器人 Webhook用于群聊消息回复必须配置才能在群里回复消息
# 在企微群聊中添加群机器人,获取 Webhook 地址后填入
WECOM_GROUP_WEBHOOK: ${WECOM_GROUP_WEBHOOK:-} # 群机器人Webhook必须配置
ports:
- "5001:5001"
depends_on:
- db
- redis
extra_hosts:
- "host.docker.internal:host-gateway"
volumes:
- baodan_api_storage:/app/api/storage # 持久化 RSA 私钥和上传文件
- ./api/insurance:/app/api/insurance # 挂载自研代码(开发用,改代码即时生效)
restart: unless-stopped
# ---- BaoDan Core APIDify /v1 独立进程池,避免与 Insurance SSE 争用 Worker----
baodan-core-api:
build:
context: .
dockerfile: Dockerfile.dify-custom
image: baodanagent-api:local
user: root
command:
- gunicorn
- --bind
- 0.0.0.0:5001
- --workers
- ${CORE_API_WORKERS:-4}
- --worker-class
- geventwebsocket.gunicorn.workers.GeventWebSocketWorker
- --worker-connections
- ${CORE_API_WORKER_CONNECTIONS:-1000}
- --timeout
- "300"
- --graceful-timeout
- "30"
- --keep-alive
- "5"
- app:flask_app
environment:
<<: *baodan_api_environment
MIGRATION_ENABLED: "false"
BAODAN_API_URL: "http://baodan-core-api:5001"
depends_on:
- db
- redis
extra_hosts:
- "host.docker.internal:host-gateway"
volumes:
- baodan_api_storage:/app/api/storage
- ./api/insurance:/app/api/insurance
restart: unless-stopped
# ---- BaoDan Web ----
baodan-web:
build:
context: .
dockerfile: Dockerfile.web-custom
environment:
CONSOLE_API_URL: http://localhost:5001
CONSOLE_WEB_URL: http://localhost:3000
SERVICE_API_URL: http://localhost:5001
APP_API_URL: http://localhost:5001
APP_WEB_URL: http://localhost:3000
NEXT_PUBLIC_ALLOW_EMBED: "true"
NEXT_PUBLIC_APP_URL: http://localhost:3000
MARKETPLACE_ENABLED: "true"
MARKETPLACE_URL: https://marketplace.dify.ai
MARKETPLACE_API_URL: https://marketplace.dify.ai
ports:
- "3000:3000"
depends_on:
- baodan-api
restart: unless-stopped
# ---- Plugin Daemon ----
plugin_daemon:
image: langgenius/dify-plugin-daemon:0.6.1-local
environment:
DB_TYPE: postgresql
DB_USERNAME: ${POSTGRES_USER:-postgres}
DB_PASSWORD: ${POSTGRES_PASSWORD:?请在 .env 文件中设置 POSTGRES_PASSWORD}
DB_HOST: db
DB_PORT: 5432
DB_DATABASE: dify_plugin
REDIS_HOST: redis
REDIS_PORT: 6379
REDIS_PASSWORD: ""
REDIS_DB: 0
SERVER_PORT: 5002
SERVER_KEY: ${PLUGIN_DAEMON_KEY:?请在 .env 文件中设置 PLUGIN_DAEMON_KEY}
MAX_PLUGIN_PACKAGE_SIZE: 52428800
PPROF_ENABLED: "false"
DIFY_INNER_API_URL: "http://baodan-api:5001"
DIFY_INNER_API_KEY: ${DIFY_INNER_API_KEY:?请在 .env 文件中设置 DIFY_INNER_API_KEY}
PLUGIN_REMOTE_INSTALLING_HOST: "0.0.0.0"
PLUGIN_REMOTE_INSTALLING_PORT: 5003
PLUGIN_WORKING_PATH: "/app/storage/cwd"
FORCE_VERIFYING_SIGNATURE: "false"
PYTHON_ENV_INIT_TIMEOUT: 120
PLUGIN_MAX_EXECUTION_TIMEOUT: 600
PLUGIN_STORAGE_TYPE: local
PLUGIN_STORAGE_LOCAL_ROOT: "/app/storage"
PLUGIN_INSTALLED_PATH: plugin
PLUGIN_PACKAGE_CACHE_PATH: plugin_packages
PLUGIN_MEDIA_CACHE_PATH: assets
ports:
- "5002:5002"
- "5003:5003"
depends_on:
- db
- redis
volumes:
- baodan_plugin_data:/app/storage
restart: unless-stopped
# ---- Sandbox (代码执行沙箱,仅供内部 API 调用) ----
sandbox:
image: langgenius/dify-sandbox:0.2.15
restart: always
environment:
API_KEY: ${CODE_EXECUTION_API_KEY:?请在 .env 文件中设置 CODE_EXECUTION_API_KEY}
GIN_MODE: release
WORKER_TIMEOUT: 15
ENABLE_NETWORK: "true"
SANDBOX_PORT: 8194
volumes:
- baodan_sandbox_data:/app/storage
extra_hosts:
- "host.docker.internal:host-gateway"
# ---- BaoDan Worker ----
baodan-worker:
build:
context: .
dockerfile: Dockerfile.dify-custom
user: root
command: celery -A app.celery worker -P gevent -c 1 --loglevel INFO -Q dataset,dataset_summary,priority_dataset,priority_pipeline,pipeline,mail,ops_trace,app_deletion,plugin,workflow_storage,conversation,workflow,schedule_poller,schedule_executor,triggered_workflow_dispatcher,trigger_refresh_executor,retention,workflow_based_app_execution,insurance
environment:
MODE: worker
DB_TYPE: postgresql
DB_USERNAME: ${POSTGRES_USER:-postgres}
DB_PASSWORD: ${POSTGRES_PASSWORD:?请在 .env 文件中设置 POSTGRES_PASSWORD}
DB_HOST: db
DB_PORT: 5432
DB_DATABASE: ${POSTGRES_DB:-baodan}
SQLALCHEMY_POOL_PRE_PING: ${SQLALCHEMY_POOL_PRE_PING:-true}
SQLALCHEMY_POOL_RECYCLE: ${SQLALCHEMY_POOL_RECYCLE:-300}
REDIS_HOST: redis
REDIS_PORT: 6379
REDIS_PASSWORD: ""
REDIS_DB: 0
SECRET_KEY: ${SECRET_KEY:?请在 .env 文件中设置 SECRET_KEY}
MIGRATION_ENABLED: "false"
LOG_LEVEL: INFO
INSURANCE_STORAGE_ROOT: ${INSURANCE_STORAGE_ROOT:-/app/api/storage/insurance}
POSTER_USER_MANUAL_UPLOAD_ENABLED: ${POSTER_USER_MANUAL_UPLOAD_ENABLED:-true}
MAIL_TYPE: ${MAIL_TYPE:-}
MAIL_DEFAULT_SEND_FROM: ${MAIL_DEFAULT_SEND_FROM:-}
SMTP_SERVER: ${SMTP_SERVER:-}
SMTP_PORT: ${SMTP_PORT:-587}
SMTP_USERNAME: ${SMTP_USERNAME:-}
SMTP_PASSWORD: ${SMTP_PASSWORD:-}
SMTP_USE_TLS: ${SMTP_USE_TLS:-false}
SMTP_OPPORTUNISTIC_TLS: ${SMTP_OPPORTUNISTIC_TLS:-false}
RESEND_API_KEY: ${RESEND_API_KEY:-}
RESEND_API_URL: ${RESEND_API_URL:-}
SENDGRID_API_KEY: ${SENDGRID_API_KEY:-}
GENERATION_OUTBOX_V1: ${GENERATION_OUTBOX_V1:-false}
GENERATION_OUTBOX_PUBLISH_V1: ${GENERATION_OUTBOX_PUBLISH_V1:-false}
GENERATION_SPLIT_QUEUES_V1: ${GENERATION_SPLIT_QUEUES_V1:-false}
POSTER_COPY_ASYNC_V1: ${POSTER_COPY_ASYNC_V1:-false}
MODEL_POOL_V1: ${MODEL_POOL_V1:-false}
GENERATION_USER_MAX_RUNNING: ${GENERATION_USER_MAX_RUNNING:-2}
GENERATION_USER_MAX_QUEUED: ${GENERATION_USER_MAX_QUEUED:-20}
GENERATION_HEARTBEAT_SECONDS: ${GENERATION_HEARTBEAT_SECONDS:-30}
INSURANCE_CREDENTIAL_MASTER_KEY: ${INSURANCE_CREDENTIAL_MASTER_KEY:-}
INSURANCE_CREDENTIAL_KEY_VERSION: ${INSURANCE_CREDENTIAL_KEY_VERSION:-1}
INSURANCE_CREDENTIAL_MASTER_KEYS: ${INSURANCE_CREDENTIAL_MASTER_KEYS:-}
CELERY_BROKER_URL: redis://redis:6379/1
SSRF_PROXY_HTTP_URL: ""
SSRF_PROXY_HTTPS_URL: ""
PLUGIN_DAEMON_URL: http://plugin_daemon:5002
PLUGIN_DAEMON_KEY: ${PLUGIN_DAEMON_KEY:?请在 .env 文件中设置 PLUGIN_DAEMON_KEY}
PLUGIN_DAEMON_TIMEOUT: "600.0"
# 向量数据库配置 - 使用 pgvector
VECTOR_STORE: pgvector
PGVECTOR_HOST: db
PGVECTOR_PORT: 5432
PGVECTOR_USER: ${POSTGRES_USER:-postgres}
PGVECTOR_PASSWORD: ${POSTGRES_PASSWORD:?请在 .env 文件中设置 POSTGRES_PASSWORD}
PGVECTOR_DATABASE: ${POSTGRES_DB:-baodan}
depends_on:
- db
- redis
extra_hosts:
- "host.docker.internal:host-gateway"
volumes:
- baodan_api_storage:/app/api/storage # 共享 API 存储RSA 私钥和上传文件)
- ./api/insurance:/app/api/insurance # 挂载自研代码(开发用)
restart: unless-stopped
# ---- Insurance 分类 Worker灰度关闭时空闲开启后消费新队列----
insurance-parse-worker:
extends:
service: baodan-worker
command: celery -A app.celery worker --pool=prefork --concurrency=${INSURANCE_PARSE_CONCURRENCY:-4} --prefetch-multiplier=1 --max-tasks-per-child=100 --loglevel=INFO -Q insurance_parse
insurance-copy-worker:
extends:
service: baodan-worker
command: celery -A app.celery worker --pool=prefork --concurrency=${INSURANCE_COPY_CONCURRENCY:-4} --prefetch-multiplier=1 --max-tasks-per-child=100 --loglevel=INFO -Q insurance_copy
insurance-image-worker:
extends:
service: baodan-worker
command: celery -A app.celery worker --pool=prefork --concurrency=${INSURANCE_IMAGE_CONCURRENCY:-2} --prefetch-multiplier=1 --max-tasks-per-child=100 --loglevel=INFO -Q insurance_image
insurance-render-worker:
extends:
service: baodan-worker
command: celery -A app.celery worker --pool=prefork --concurrency=${INSURANCE_RENDER_CONCURRENCY:-2} --prefetch-multiplier=1 --max-tasks-per-child=100 --loglevel=INFO -Q insurance_render
# Outbox 发布器只负责数据库领取和 Broker 发布,不执行重任务。
insurance-outbox-dispatcher:
extends:
service: baodan-worker
command: python -m insurance.generation.outbox_dispatcher
# ---- 保险前端 ----
baodanagent-web:
build:
context: .
dockerfile: Dockerfile.frontend
ports:
- "9080:80"
ulimits:
nofile:
soft: 65535
hard: 65535
volumes:
- ./frontend/dist:/usr/share/nginx/html:ro
depends_on:
- baodan-api
- baodan-core-api
restart: unless-stopped
volumes:
baodan_pg_data:
baodan_redis_data:
baodan_plugin_data:
baodan_api_storage:
baodan_sandbox_data: