跳转到内容

使用 Docker 部署

Chorus 提供了官方 Docker 镜像 chorusaidlc/chorus-app。本指南展示两种 Compose 形态: 独立(内置数据库)与生产(外部 PostgreSQL + Redis),一个对接现有数据库的 docker run 示例、完整的环境变量参考,以及容器启动时的行为。

先拉取镜像:

Terminal window
docker pull chorusaidlc/chorus-app:latest

关于如何在独立与生产两种形态之间做选择,请参见部署概览。

无需外部数据库。镜像内置了 PGlite(嵌入式 PostgreSQL),并会自动启动 一切。数据保存在 Docker 卷中,可在容器重启后持久保留。

创建 docker-compose.local.yml:

# Standalone Chorus — embedded PGlite, no external PostgreSQL or Redis
services:
app:
image: chorusaidlc/chorus-app:latest
ports:
- "8637:8637"
environment:
# No DATABASE_URL — entrypoint auto-starts embedded PGlite
- REDIS_URL=
# Leave empty: the container generates a random session secret on first
# start and keeps it in the chorus-local-data volume. Set it explicitly
# (openssl rand -base64 32) if you prefer to manage it yourself.
- NEXTAUTH_SECRET=${NEXTAUTH_SECRET:-}
- COOKIE_SECURE=false
- DEFAULT_USER=${DEFAULT_USER:-admin@example.com}
- DEFAULT_PASSWORD=${DEFAULT_PASSWORD:-changeme}
volumes:
- chorus-local-data:/app/data
volumes:
chorus-local-data:

然后运行:

Terminal window
docker compose -f docker-compose.local.yml up -d

打开 http://localhost:8637,使用 admin@example.com / changeme 登录(或通过 DEFAULT_USER / DEFAULT_PASSWORD 环境变量覆盖)。

在独立模式下,容器会:

  • 在内部端口(5433)上启动 PGlite,不对外暴露。
  • 将数据存放在 chorus-local-data Docker 卷中,因此可在重启后持久保留。
  • 当 NEXTAUTH_SECRET 留空时,在首次启动生成一个随机的会话签名密钥并保存在同一个卷中(参见 会话密钥)。
  • 禁用 Redis(回退到内存 EventBus,仅支持单实例)。
  • 在启动时自动执行 Prisma 迁移。

面向生产环境,尤其是多副本部署时,请将应用对接到外部 PostgreSQL 与 Redis。创建 docker-compose.yml:

services:
app:
image: chorusaidlc/chorus-app:latest
ports:
- "8637:8637"
environment:
- DATABASE_URL=postgresql://chorus:chorus@db:5432/chorus
- REDIS_URL=redis://default:chorus-redis@redis:6379
# Session-signing secret. Leave empty and the container generates one on
# first start and persists it in the chorus-app-data volume (single
# replica only). For production, or more than one app container, set it
# explicitly in .env or the environment: openssl rand -base64 32
# Changing the secret invalidates Default Auth and Super Admin sessions.
- NEXTAUTH_SECRET=${NEXTAUTH_SECRET:-}
- COOKIE_SECURE=${COOKIE_SECURE:-false}
- DEFAULT_USER=admin@example.com
- DEFAULT_PASSWORD=your-password
volumes:
- chorus-app-data:/app/data
depends_on:
db:
condition: service_healthy
redis:
condition: service_healthy
redis:
image: redis:7-alpine
command: redis-server --requirepass chorus-redis
volumes:
- redis-data:/data
healthcheck:
test: ["CMD", "redis-cli", "-a", "chorus-redis", "ping"]
interval: 5s
timeout: 3s
retries: 5
db:
image: postgres:16-alpine
environment:
POSTGRES_USER: chorus
POSTGRES_PASSWORD: chorus
POSTGRES_DB: chorus
volumes:
- chorus-data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U chorus -d chorus"]
interval: 5s
timeout: 5s
retries: 5
volumes:
chorus-app-data:
chorus-data:
redis-data:

如果想自己提供会话密钥,请在启动前生成一次,写进 compose 文件旁边的 .env:

Terminal window
echo "NEXTAUTH_SECRET=$(openssl rand -base64 32)" >> .env

然后运行:

Terminal window
docker compose up -d

打开 http://localhost:8637,使用你在 DEFAULT_USER / DEFAULT_PASSWORD 中设置的凭据 登录。

如果你已经有 PostgreSQL 和 Redis 在运行,可直接启动容器:

Terminal window
docker run -d \
-p 8637:8637 \
-e DATABASE_URL=postgresql://user:pass@your-db-host:5432/chorus \
-e REDIS_URL=redis://default:password@your-redis-host:6379 \
-v chorus-app-data:/app/data \
-e COOKIE_SECURE=false \
-e DEFAULT_USER=admin@example.com \
-e DEFAULT_PASSWORD=your-password \
chorusaidlc/chorus-app:latest

此示例将生成的密钥保存在 chorus-app-data 中,容器重建后仍可复用。 若自行管理密钥,请注入持久的 NEXTAUTH_SECRET,并在每次启动时复用同一值。

变量说明
DATABASE_URLPostgreSQL 连接字符串。格式:postgresql://user:password@host:port/dbname。也可以改为设置单独的 DB_* 变量(见下文)。若省略,入口脚本会自动启动一个嵌入式 PGlite 实例。
NEXTAUTH_SECRET用于签发会话令牌的密钥。请使用随机字符串(例如 openssl rand -base64 32)。在 Docker 中可以留空:容器会在首次启动时生成一个并保存在 /app/data/.secret。运行多个应用容器时,必须在每个副本上显式设置同一个值。参见会话密钥。

数据库(DATABASE_URL 的替代方案)

Section titled “数据库(DATABASE_URL 的替代方案)”

若未设置 DATABASE_URL,入口脚本会用以下单独变量拼装它:

变量说明
DB_HOSTPostgreSQL 主机
DB_PORTPostgreSQL 端口(默认:5432)
DB_USERNAMEPostgreSQL 用户名
DB_PASSWORDPostgreSQL 密码
DB_NAME数据库名
变量说明
REDIS_URL完整的 Redis 连接字符串。格式:redis://username:password@host:port。优先级高于以下单独变量。
REDIS_HOSTRedis 主机(在未设置 REDIS_URL 时使用)
REDIS_PORTRedis 端口(默认:6379)
REDIS_USERNAMERedis 用户名(默认:default)
REDIS_PASSWORDRedis 密码
变量说明
DEFAULT_USER内置登录的邮箱地址(绕过 OIDC)。首次登录时自动创建该用户及公司。
DEFAULT_PASSWORD默认用户的密码(明文,运行时通过 bcrypt 比对)。
NEXTAUTH_URL应用对外的基础 URL(默认:http://localhost:8637)。在反向代理后运行时请设置此项。
COOKIE_SECURE设为 "false" 可为纯 HTTP 部署禁用安全 Cookie(docker-compose 中默认为 "false")。以 HTTPS 部署到生产环境时设为 "true"。
变量默认值说明
LOG_LEVELinfo(生产)/ debug(开发)服务端最低日志级别。可选:trace、debug、info、warn、error、fatal、silent。设为 info 可抑制 Prisma 查询日志。
NEXT_PUBLIC_LOG_LEVELwarn(生产)/ debug(开发)浏览器端最低日志级别。可选:debug、info、warn、error。

生产 Docker 镜像始终将 JSON 输出到 stdout(可直接对接 CloudWatch / ELK)。彩色美化输出仅在 本地开发时可用。

变量说明
SUPER_ADMIN_EMAIL超级管理员账号的邮箱(可访问 /admin 面板)。
SUPER_ADMIN_PASSWORD_HASH超级管理员密码的 bcrypt 哈希。生成方式:node -e "console.log(require('bcryptjs').hashSync('your-password', 10))"

容器的入口脚本每次启动都会执行相同的流程:

  1. 检查 NEXTAUTH_SECRET。若为空,或等于以前示例文件中出现过的占位值,容器会在 /app/data/.secret 中读取或生成密钥,并在日志中说明做了什么(但绝不打印密钥本身)。你自己 显式设置的密钥会原样使用。
  2. 若未设置 DATABASE_URL 且未提供任何 DB_* 变量,入口脚本会在内部端口(5433)上启动 一个嵌入式 PGlite 实例。当已配置外部数据库时,不会启动 PGlite。
  3. 执行 prisma migrate deploy,应用任何待处理的数据库迁移。
  4. 若数据库尚未就绪,每 10 秒重试一次(最多 30 次,约五分钟)。
  5. 迁移成功后,Next.js 服务在 8637 端口启动。

NEXTAUTH_SECRET 签发 Chorus 自己的 user_session(内置登录)和 admin_session(超级管理员)JWT。 OIDC token 由身份提供方签名,Agent API key 也单独校验。轮换此密钥会使 Chorus 自签名会话失效, 不会轮换 API key,也不会使身份提供方的 OIDC token 失效。

  • 显式设置非占位值:直接使用,不读写密钥文件。
  • 未设置、为空或使用已知公开占位值:复用 /app/data/.secret;文件不存在或为空时, 生成 32 个随机字节,编码为 64 个十六进制字符,以 0600 权限保存。环境变量中的占位值还会触发警告。
  • 持久化密钥不可用:文件不是普通文件、不可读、保存了公开占位值,或生成、写入失败时, 容器会在迁移前停止。已保存的公开占位值不会被悄悄接受或替换。

日志不会打印密钥值。要保留自动生成的密钥,请把 /app/data 放在持久卷上。多副本部署必须向每个实例显式注入 同一个密钥;AWS CDK 栈已通过 Secrets Manager 共享该值。

用 openssl rand -base64 32 生成一次,存入部署的密钥库或受保护的 .env,后续启动复用。 有效密钥改变后,内置登录用户和超级管理员需要重新登录。删除 .secret 只会影响自动生成的密钥; 已显式配置密钥时,删除该文件不会轮换密钥。

Docker 入口脚本和 npm chorus 启动器会自动处理密钥。直接用 next start 或 node server.js 启动时不会自动生成,需自行配置安全密钥。应用发现已知占位值会记录错误,但警告本身不会替换该值; 未设置密钥时,无法签发 Chorus 自签名会话。

  • 基础镜像: node:22-alpine
  • 内部端口: 8637
  • 架构: linux/amd64、linux/arm64
  • 生产部署:从全局 npm 包运行,以及完整的 AWS CDK 演练。
  • 运维:首次登录引导、部署侧身份认证,以及升级前的 备份。