Dittofeed v0.24.0-alpha.21 Docker Compose 部署指南
在 Ubuntu 上以官方 lite Compose 栈部署 Dittofeed v0.24.0-alpha.21:Postgres 15 + ClickHouse 24.12 + Temporal 1.22 依赖顺序、健康检查、Nginx 反代、控制台登录与创建 Journey 实测、升级回滚与排障实录。
Dittofeed v0.24.0-alpha.21 Docker Compose 部署指南
目标:在一台 Linux 服务器上用官方 lite Compose 栈部署 Dittofeed v0.24.0-alpha.21,并完成「控制台登录 → 创建 Journey → API 回读」的闭环验证。文中命令与输出均为本机实跑回显(2026-10-27),已脱敏口令与密钥。
一、环境信息
| 项目 | 实测值 |
|---|---|
| 操作系统 | Ubuntu 26.04.1 LTS,内核 7.0.0-38-generic(步骤同样适用于 Ubuntu 22.04) |
| Docker | 29.9.2(build a82e528) |
| Docker Compose | v5.6.1(Compose V2 插件) |
| 主机资源 | 6 vCPU / 18 GiB 内存 / 195 GiB 可用磁盘 |
| 部署目录 | /opt/data/quzuo/tmp/dittofeed |
| 应用版本 | v0.24.0-alpha.21(GitHub 最新 tag,2026-10-04 发布) |
| 访问地址 | http://192.168.146.131:8137(宿主机 8137 → 容器 3000) |
本轮实测各组件镜像与摘要:
| 组件 | 镜像 | 镜像大小 | Digest |
|---|---|---|---|
| 应用(lite) | dittofeed/dittofeed-lite:v0.24.0-alpha.21 | 3.42 GB | sha256:2d181902591a185ff43e0a18989f02b7325a302e5802882eb12bd0079d6e2424 |
| 业务库 | postgres:15 | 633 MB | sha256:baa22e6286bf832cb147b8bb5aa9d8bc999846d69c21d11bf63f58fbeed1fa48 |
| 事件库 | clickhouse/clickhouse-server:24.12.6.70-alpine | 718 MB | sha256:cd450891db46cc6ffe313ca2b0fb7dbfb897a6873ca74a724cbe050a2cf62621 |
| 工作流 | temporalio/auto-setup:1.22.4 | 520 MB | sha256:b8bdd2208877ba6178bd9e46e162590965b170577659f4b1add95d9f1a69a5c2 |
二、前置条件与资源评估
- 端口:应用容器内监听
3000;依赖端口5432(Postgres)、8123(ClickHouse HTTP)、7233(Temporal gRPC)只在 Compose 内部网络暴露,不映射到宿主机。 - 磁盘:四个镜像合计约 5.3 GB,另需为 Postgres、ClickHouse 数据卷预留空间(实测空载数据卷 < 100 MB,按事件量增长)。
- 内存:官方 lite 栈给应用进程限 1024 MB、ClickHouse 限 2048 MB。实测空载占用:lite 462 MiB、ClickHouse 400 MiB、Postgres 113 MiB、Temporal 82 MiB,合计约 1.06 GiB。最低 2 vCPU / 4 GiB 可跑通,生产建议 4 vCPU / 8 GiB 起。
- 内核参数:ClickHouse 建议
vm.max_map_count >= 262144;本机已满足,未额外调整。 - 网络:Compose 需自建 bridge 网络,避免与其他栈网段冲突(本轮使用
10.89.59.0/24)。
三、版本与镜像选型说明
- 官方
docker-compose.lite.yaml中 lite 镜像的默认 tag 是v0.23.0,IMAGE_TAG默认值同样滞后。必须显式把 tag 覆盖为v0.24.0-alpha.21,否则部署到的不是本文基线版本。 - 官方仓库同时提供
docker-compose.yaml(dashboard/api/worker 三进程 + 可选 Kafka + MinIO + MailHog,面向开发)与docker-compose.lite.yaml(单进程 + Postgres/ClickHouse/Temporal,面向上线)。本文选 lite,理由是部署面最小、控制台与 API 同端口、适合单机。 - 由于所有 Release 均为
-alpha.N,升级前必须固定 digest 并准备回滚 tag。
四、部署步骤
4.1 拉取源码(用于 Temporal 动态配置挂载)
cd /opt/data/quzuo/tmp/dittofeed
git clone --depth 1 --branch v0.24.0-alpha.21 https://github.com/dittofeed/dittofeed.git repo
回显节选:
Note: switching to 'v0.24.0-alpha.21'.
4.2 准备 .env
cat > .env <<'EOF'
DATABASE_USER=postgres
DATABASE_PASSWORD=Dit2feedPg2026
CLICKHOUSE_USER=dittofeed
CLICKHOUSE_PASSWORD=Dit2feedCh2026
PASSWORD=q1w2e3r4
SECRET_KEY=<openssl rand -base64 32 生成>
DASHBOARD_URL=http://192.168.146.131:8137
DASHBOARD_API_BASE=http://192.168.146.131:8137
EOF
要点:
SECRET_KEY必须是 32 字节随机串的 base64(44 字符),否则 single-tenant 会话无法解密;PASSWORD是控制台共享登录口令,本文按规范使用q1w2e3r4;DASHBOARD_URL用于生成退订链接等外链,DASHBOARD_API_BASE供前端调用 API,二者都不带/dashboard、/api后缀。
4.3 编写 Compose(基于官方 lite 改编)
name: dittofeed-v0.24.0-alpha.21-stack
x-database-credentials: &database-credentials
DATABASE_USER: ${DATABASE_USER:-postgres}
DATABASE_PASSWORD: ${DATABASE_PASSWORD:-password}
x-clickhouse-credentials: &clickhouse-credentials
CLICKHOUSE_USER: ${CLICKHOUSE_USER:-dittofeed}
CLICKHOUSE_PASSWORD: ${CLICKHOUSE_PASSWORD:-password}
x-backend-app-env: &backend-app-env
<<: [*clickhouse-credentials, *database-credentials]
NODE_ENV: production
DATABASE_HOST: postgres
DATABASE_PORT: 5432
CLICKHOUSE_HOST: http://clickhouse-server:8123
TEMPORAL_ADDRESS: temporal:7233
WORKSPACE_NAME: Default
AUTH_MODE: single-tenant
SECRET_KEY: ${SECRET_KEY}
PASSWORD: ${PASSWORD}
DASHBOARD_URL: ${DASHBOARD_URL}
DASHBOARD_API_BASE: ${DASHBOARD_API_BASE}
services:
lite:
image: dittofeed/dittofeed-lite:v0.24.0-alpha.21
container_name: dittofeed-v0.24.0-alpha.21-lite
restart: unless-stopped
command: node --max-old-space-size=824 ./packages/lite/dist/scripts/startLite.js --workspace-name=Default
deploy:
resources:
limits:
memory: 1024m
ports:
- "8137:3000"
healthcheck:
test: ["CMD-SHELL", "node -e \"fetch('http://127.0.0.1:3000/').then(r=>process.exit(r.status < 500 ? 0 : 1)).catch(()=>process.exit(1))\""]
interval: 30s
timeout: 5s
retries: 3
start_period: 120s
depends_on:
postgres:
condition: service_healthy
temporal:
condition: service_started
clickhouse-server:
condition: service_healthy
environment:
<<: *backend-app-env
BOOTSTRAP: "true"
LOG_CONFIG: "true"
networks:
- dittofeed-net
postgres:
image: postgres:15
container_name: dittofeed-v0.24.0-alpha.21-postgres
restart: unless-stopped
environment:
POSTGRES_PASSWORD: ${DATABASE_PASSWORD}
POSTGRES_USER: ${DATABASE_USER}
POSTGRES_DB: dittofeed
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${DATABASE_USER} -d dittofeed"]
interval: 10s
timeout: 5s
retries: 10
volumes:
- postgres:/var/lib/postgresql/data
networks:
- dittofeed-net
temporal:
image: temporalio/auto-setup:1.22.4
container_name: dittofeed-v0.24.0-alpha.21-temporal
restart: unless-stopped
depends_on:
postgres:
condition: service_healthy
environment:
DB: postgresql
DB_PORT: 5432
POSTGRES_USER: ${DATABASE_USER}
POSTGRES_PWD: ${DATABASE_PASSWORD}
POSTGRES_SEEDS: postgres
DYNAMIC_CONFIG_FILE_PATH: config/dynamicconfig/prod.yaml
volumes:
- ./repo/packages/backend-lib/temporal-dynamicconfig:/etc/temporal/config/dynamicconfig:ro
networks:
- dittofeed-net
clickhouse-server:
image: clickhouse/clickhouse-server:24.12.6.70-alpine
container_name: dittofeed-v0.24.0-alpha.21-clickhouse
restart: unless-stopped
deploy:
resources:
limits:
memory: 2048m
environment:
<<: *clickhouse-credentials
healthcheck:
test: ["CMD-SHELL", "wget -q -O /dev/null http://127.0.0.1:8123/ping || exit 1"]
interval: 10s
timeout: 5s
retries: 12
volumes:
- clickhouse_lib:/var/lib/clickhouse
- clickhouse_log:/var/log/clickhouse-server
networks:
- dittofeed-net
volumes:
postgres:
clickhouse_lib:
clickhouse_log:
networks:
dittofeed-net:
name: dittofeed-v0.24.0-alpha.21-net
driver: bridge
ipam:
config:
- subnet: 10.89.59.0/24
与官方 lite 的差异:显式项目名与容器名、显式网段、去掉依赖组件的宿主端口映射、为应用与 ClickHouse 增加健康检查。其它环境变量语义与官方一致。
4.4 启动
docker compose --env-file .env config --quiet # 校验通过则无输出
docker compose up -d
启动回显节选:
Container dittofeed-v0.24.0-alpha.21-postgres Started
Container dittofeed-v0.24.0-alpha.21-postgres Healthy
Container dittofeed-v0.24.0-alpha.21-clickhouse Healthy
Container dittofeed-v0.24.0-alpha.21-lite Started
应用日志关键行:
{"msg":"Creating ClickHouse database"}
{"msg":"Database already exists"}
{"msg":"Running migrations"}
{"msg":"Server listening at http://0.0.0.0:3000"}
{"msg":"Bootstrapping"}
首次启动会自动建库、跑 Drizzle 迁移并创建 Default 工作区,约 40–60 秒后控制台可用。
五、验证控制台登录与创建 Journey
5.1 容器与健康状态
docker compose ps
NAME IMAGE STATUS PORTS
dittofeed-v0.24.0-alpha.21-clickhouse clickhouse/clickhouse-server:24.12.6.70-alpine Up (healthy) 8123/tcp, 9000/tcp, 9009/tcp
dittofeed-v0.24.0-alpha.21-lite dittofeed/dittofeed-lite:v0.24.0-alpha.21 Up (healthy) 0.0.0.0:8137->3000/tcp
dittofeed-v0.24.0-alpha.21-postgres postgres:15 Up (healthy) 5432/tcp
dittofeed-v0.24.0-alpha.21-temporal temporalio/auto-setup:1.22.4 Up 7233/tcp 等
5.2 登录
curl -s -o /dev/null -w '%{http_code} %{redirect_url}\n' http://127.0.0.1:8137/
307 http://127.0.0.1:8137/dashboard
登录页路径是 /dashboard/auth/single-tenant(不是 /dashboard/login):
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:8137/dashboard/auth/single-tenant
200
页面会列出安全告警;实测仅提示「Bootstrap is enabled」和「cookie is not secure」,说明自定义 PASSWORD/DATABASE_PASSWORD/CLICKHOUSE_PASSWORD/SECRET_KEY 均已生效(若沿用默认值,会额外出现四条默认口令告警)。
用口令换会话:
curl -s -i -c cookies.txt -H 'Content-Type: application/json' \
-d '{"password":"q1w2e3r4"}' \
http://127.0.0.1:8137/api/public/single-tenant/login
HTTP/1.1 200 OK
set-cookie: session=8M%2BrZrM67dAO1ISk6eGyjlj5DdThyHn55XSKmgklyVlhhOmza5Je%3BOmqm5jrN1hOBYNAvMCHDRtEwjlw9Lvb0; Max-Age=1209600; Path=/; HttpOnly
访问受保护页面:
curl -s -b cookies.txt -o /dev/null -w '%{http_code}\n' http://127.0.0.1:8137/dashboard/journeys
200
5.3 创建 Journey(API 实测)
先查工作区 ID:
docker exec dittofeed-v0.24.0-alpha.21-postgres \
psql -U postgres -d dittofeed -c 'select id,name,status from "Workspace";'
id | name | status
--------------------------------------+---------+--------
64a328ce-7c53-426a-8733-57207dc474a5 | Default | Active
创建 Admin API Key(用登录会话调用):
curl -s -b cookies.txt -H 'Content-Type: application/json' \
-d '{"workspaceId":"64a328ce-7c53-426a-8733-57207dc474a5","name":"doc-test-key"}' \
http://127.0.0.1:8137/api/admin-keys
{"workspaceId":"64a328ce-7c53-426a-8733-57207dc474a5","id":"03b4a00a-a7b0-40ee-9cc8-70517c0486c2","name":"doc-test-key","createdAt":1793104629179,"apiKey":"82445a1f...f750"}
用 API Key 创建「事件触发 → 退出」的最小 Journey:
curl -s -X PUT -H "Authorization: Bearer $API_KEY" -H 'Content-Type: application/json' \
--data '{"id":"f7439626-48e5-4e77-a180-6aa5325e7402","workspaceId":"64a328ce-7c53-426a-8733-57207dc474a5","name":"文档验证 Journey","status":"NotStarted","updatedAt":1793104700000,"definition":{"entryNode":{"type":"EventEntryNode","event":"doc.test","child":"ExitNode"},"nodes":[],"exitNode":{"type":"ExitNode"}}}' \
"http://127.0.0.1:8137/api/admin/journeys/?workspaceId=64a328ce-7c53-426a-8733-57207dc474a5"
回显:
{"id":"f7439626-48e5-4e77-a180-6aa5325e7402","workspaceId":"64a328ce-7c53-426a-8733-57207dc474a5","name":"文档验证 Journey","updatedAt":1793104697568,"status":"NotStarted","createdAt":1793104697568,"definition":{"entryNode":{"type":"EventEntryNode","event":"doc.test","child":"ExitNode"},"exitNode":{"type":"ExitNode"},"nodes":[]}}
回读确认已落库(控制台 Journey 列表走同一份数据):
curl -s -b cookies.txt "http://127.0.0.1:8137/api/journeys?workspaceId=64a328ce-7c53-426a-8733-57207dc474a5"
{"journeys":[{"id":"f7439626-48e5-4e77-a180-6aa5325e7402","name":"文档验证 Journey","status":"NotStarted","canRunMultiple":false,...}]}
至此「登录成功 + Journey 创建成功 + 列表回读成功」闭环完成。
六、反向代理与健康检查
Nginx 反代示例(SESSION_COOKIE_SECURE=true 时建议启用 HTTPS):
server {
listen 443 ssl;
server_name dittofeed.example.com;
ssl_certificate /etc/nginx/certs/fullchain.pem;
ssl_certificate_key /etc/nginx/certs/privkey.pem;
location / {
proxy_pass http://127.0.0.1:8137;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 300s;
client_max_body_size 20m;
}
}
反代后必须同步修改 DASHBOARD_URL 与 DASHBOARD_API_BASE 为外部域名,否则邮件里的退订链接、前端 API 请求会指向旧地址。
健康检查有两层:
- 容器级:Compose 内 lite 的
healthcheck用 Node 原生fetch探测http://127.0.0.1:3000/,非 5xx 即健康(start_period: 120s避免启动期误判);ClickHouse 用/ping,Postgres 用pg_isready; - 外部级:反代或拨测直接请求
/dashboard/auth/single-tenant,期望 200;请求/期望 307 到/dashboard。
七、升级与回滚
升级前:
docker exec dittofeed-v0.24.0-alpha.21-postgres pg_dump -U postgres -d dittofeed -Fc > backup-$(date +%F).dump
docker run --rm -v dittofeed-v0.24.0-alpha.21-stack_clickhouse_lib:/data -v $PWD:/backup alpine \
tar czf /backup/clickhouse-$(date +%F).tgz -C /data .
升级:
# 1. 修改 compose 中 lite 的 image tag(先改成目标版本)
docker compose pull lite
docker compose up -d lite
# 2. 观察迁移日志,确认无 error
docker logs -f dittofeed-v0.24.0-alpha.21-lite
注意:lite 启动时会自动执行 Postgres 迁移,迁移通常不可逆;跨大版本(如 v0.23 → v0.24)前应先读官方 upgrade-guide。
回滚:
# 把 image 改回上一 tag,重建应用容器(数据卷不动)
docker compose up -d --force-recreate lite
若新版本已执行不兼容迁移,仅回滚镜像可能无法启动,此时需从升级前的 pg_dump 恢复数据库。
八、排障实录
| 现象 | 原因 | 处理 |
|---|---|---|
Bind for :::8129 failed: port is already allocated | 宿主机 8129 被其他容器占用(ss -ltn 当时未显示,实际由 Docker 端口池占用) | 换用 8137,并同步改 DASHBOARD_URL/DASHBOARD_API_BASE;部署前用 docker ps --format '{{.Ports}}' 与 ss -ltn 双重确认 |
访问 /dashboard/login 返回 404 | 版本路由变更,登录页在 /dashboard/auth/single-tenant | 以 /dashboard/auth/single-tenant 为准;可从 packages/dashboard/src/pages/auth/ 目录确认路由 |
GET /api/admin/journeys/ 返回 400 querystring must have required property 'workspaceId' | Admin API 强制要求工作区 ID | 从 Workspace 表读取 ID,作为 query 参数传入 |
Admin API 返回 {"message":"No authorization header"} | Admin API 不走控制台会话,必须用 Admin API Key | 先 POST /api/admin-keys 创建 Key,再带 Authorization: Bearer <key> |
PUT /api/admin/journeys/ 返回 Invalid journey id, must be a valid v4 UUID | Journey 主键必须是 v4 UUID,不能用自定义字符串 | 用 uuidgen/Python uuid.uuid4() 生成 |
| 控制台页面能开但接口 401 | SECRET_KEY 变更导致旧 Cookie 失效 | 重新登录;多副本部署必须共享同一 SECRET_KEY |
九、参考链接
- 官方自托管总览:https://docs.dittofeed.com/deployment/self-hosted
- 官方 Docker Compose 文档:https://docs.dittofeed.com/deployment/self-hosted/docker-compose
- 官方 lite Compose:https://github.com/dittofeed/dittofeed/blob/v0.24.0-alpha.21/docker-compose.lite.yaml
- 鉴权模式:https://docs.dittofeed.com/deployment/self-hosted/auth-modes
- Admin API 访问方式:https://docs.dittofeed.com/guide/accessing-admin-api
- Release 页面:https://github.com/dittofeed/dittofeed/releases/tag/v0.24.0-alpha.21