使用 Docker 部署智能体
将 Flue Node.js 构建打包为容器镜像,可在任何接受容器的平台上运行。有关底层构建和运行时行为,请参见在 Node.js 上部署智能体。
Flue 的 Node 目标是一个长期运行的 HTTP 服务器,而非函数。容器必须保持运行以持有智能体会话并提供流式响应;将其部署为服务,而不是缩放至零的调用。
Dockerfile
多阶段构建保持运行时镜像精简:在第一阶段编译 Node 目标,在第二阶段只包含生产依赖和 dist/。
# syntax=docker/dockerfile:1
FROM node:22-slim AS build
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
RUN npx vite build
FROM node:22-slim AS runtime
WORKDIR /app
ENV NODE_ENV=production
COPY package.json package-lock.json ./
RUN npm ci --omit=dev
COPY --from=build /app/dist ./dist
USER node
ENV PORT=8080
EXPOSE 8080
CMD ["node", "dist/server.mjs"]构建外部化你的应用依赖而不是打包它们,因此运行时阶段安装生产依赖(vite 和 @flue/vite 保持为仅构建的 devDependencies,被 --omit=dev 丢弃)。添加一个 .dockerignore 排除 node_modules、dist、.git 和 .env,这样本地制品和密钥永远不会进入镜像。
官方 node 镜像附带一个非 root 的 node 用户(uid 1000);USER node 在运行的容器中放弃超级用户权限。Node 不是为作为 PID 1 运行而设计的,不会干净地回收子进程或转发信号,因此使用 init 运行容器 — docker run --init(如下所示)或内置的 tini/dumb-init — 这样 SIGTERM 可以到达服务器以优雅地关闭进行中的流。
服务器绑定 PORT(默认 3000;此镜像设置为 8080)。将其与你的平台期望匹配。
构建和运行
docker build -t flue-agents .
docker run --init -p 8080:8080 -e ANTHROPIC_API_KEY=sk-... flue-agents
环境变量和密钥
构建后的服务器只读取容器启动时提供的环境变量 — 它不会加载 .env。在运行时传递你的模型 provider key(ANTHROPIC_API_KEY、OPENAI_API_KEY、…)和可选的 MODEL_SPECIFIER,并通过平台的密钥存储注入它们,而不是将它们烘焙到镜像中:
docker run --init -p 8080:8080 \
-e MODEL_SPECIFIER=anthropic/claude-sonnet-4-6 \
-e ANTHROPIC_API_KEY=sk-... \
flue-agents
持久化
没有 db.ts 适配器时,服务器将规范智能体对话、附件和已接受的提交保存在进程本地内存中,因此重启或重新部署会丢失它们。添加 Postgres 支持的 PersistenceAdapter 以实现替换恢复。多个副本仍必须将每个智能体实例路由到一个活动所有者;共享存储不会启用同一实例的多活执行:
import { postgres } from '@flue/postgres';
import { Pool } from 'pg';
// 使用 DATABASE_URL 连接字符串创建连接池
const pool = new Pool({ connectionString: process.env.DATABASE_URL });
export default postgres({
query: async (text, params) => (await pool.query(text, params)).rows,
transaction: async (fn) => {
/* 每个事务一个检出的客户端;参见 Postgres 指南 */
},
close: () => pool.end(),
});Flue 在构建时发现 db.ts 并将其连接到生成的服务器中。像其他密钥一样提供 DATABASE_URL 作为环境变量。参见 Postgres 了解完整的自带驱动运行器。
健康检查和流式传输
Flue 不会生成健康检查端点。如果你的平台对容器进行健康检查,在你的 app.ts 中定义它期望的路由(通常是 /health)。
智能体对话使用在对话 URL 上的长期 GET 读取(长轮询/SSE)。确保平台的请求和空闲连接超时允许它们。消息准入返回 streamUrl、offset 和 submissionId;客户端可以从偏移量重新连接并恢复对话流。参见流式协议。
参考资料
- Docker — 容器化 Node.js 应用(官方):多阶段构建、
.dockerignore、EXPOSE/PORT。 - Node.js Docker — 最佳实践(官方):
NODE_ENV=production、非 rootnode用户、--init/tini 用于 PID-1 信号处理。 - Docker run 参考 — init 进程(官方):
--init标志。 - Snyk — 使用 Docker 容器化 Node.js 的 10 个最佳实践:非 root
USER、exec 形式的CMD、优雅关闭。