Automatisch Docker Compose 部署实战
Automatisch v0.15.0 官方 Docker Compose 部署实战:官方镜像与仓库源码两条路径差异辨析、三把安全密钥初始化、main/worker 双进程编排与启动验证、WEBHOOK_URL 外部可达性修正实录、升级回滚与卸载清理。
Automatisch Docker Compose 部署实战
目标:在一台 Linux 服务器上以官方 Docker Compose 方式完成 Automatisch v0.15.0 的生产化部署,覆盖官方两条部署路径的差异辨析、三把安全密钥的初始化、main/worker 双进程编排、外部可达性修正(WEBHOOK_URL)与升级回滚。本文全部命令与回显均在 2026-10-28 于 Docker 环境模拟真实服务器实测通过。
一、环境信息
| 项目 | 实测值 |
|---|---|
| 操作系统 | Linux(Docker 宿主,内核 5.x/6.x 均可) |
| Automatisch 版本 | 0.15.0(官方最新稳定版,Docker Hub tag 发布于 2025-08-08) |
| 依赖组件版本 | PostgreSQL 14.5、Redis 7.0.4(与官方仓库 docker-compose.yml 指定版本一致) |
| 实测宿主地址 | 192.168.146.128(内网 IP,下文 webhook 回调地址以此为基准) |
| Web 服务端口 | 宿主 8140 → 服务 3000(Automatisch 默认监听 3000) |
| 专用网络 | 10.89.56.0/24(自建 bridge 网络,避开默认网段与他栈冲突) |
| Compose 项目名 | automatisch-0.15.0-stack |
Automatisch 官方技术栈为 Node.js + PostgreSQL + Redis,进程分 main 与 worker 两个角色(同一镜像、同一环境变量,worker 侧多一个 WORKER=true),因此编排文件共 4 个服务:main、worker、postgres、redis。
二、前置条件与版本选型
- Docker 与 Compose 插件:实测环境 Docker 27.x、Compose v2(
docker compose子命令形式)。版本查询:
$ docker compose version
Docker Compose version v2.39.2
- 镜像准备:三个镜像一次拉齐(Automatisch 官方镜像 + 官方编排锁定的 PostgreSQL/Redis 版本):
$ docker pull automatischio/automatisch:0.15.0
Digest: sha256:3bace7a12d5fb3f5b1305a6a52232270e0e0abd8465a8b78baacb07f6ea89594
Status: Downloaded newer image for automatischio/automatisch:0.15.0
$ docker pull postgres:14.5
docker.io/library/postgres:14.5
$ docker pull redis:7.0.4
docker.io/library/redis:7.0.4
国内网络拉取 Docker Hub 缓慢或超时时,可为 dockerd 配置 HTTP 代理(本次实测经代理 192.168.1.62:7897 完成,全部拉取成功;该代理为实测环境内网代理,读者请替换为自己的可用渠道)。
- 版本选型说明:官方仓库 docker-compose.yml 锁定
postgres:14.5与redis:7.0.4,生产部署建议严格沿用官方锁定版本,避免跨大版本兼容性问题;Automatisch 本体使用0.15.0固定 tag 而非latest,保证可重现与可回滚。
三、方案 A:官方镜像 Compose 部署(生产推荐)
本方案使用 Docker Hub 官方镜像 automatischio/automatisch:0.15.0 + 自备编排文件,是官方文档「Docker」一节的生产化落地形态:main/worker 共用镜像、环境变量显式注入、版本钉死、启动即迁移建库。
3.1 生成三把安全密钥
Automatisch 的凭据加密与 Webhook 验签依赖三把密钥,官方文档建议用 openssl rand -base64 36 生成(automatisch.io/docs/guide/installation,查询日期 2026-10-28)。实测生成(输出即真实密钥样例,生产环境请自行重新生成并妥善保管,勿照抄本文值):
$ echo "ENCRYPTION_KEY=$(openssl rand -base64 36)"
ENCRYPTION_KEY=18hhdCO6CwRZMTx5uw6WguO78THNb7tqK/NNddXFiIvVjtUd
$ echo "WEBHOOK_SECRET_KEY=$(openssl rand -base64 36)"
WEBHOOK_SECRET_KEY=kDxuA81RZUcYMWOnSEnvzHTxuqVaQsQipTqmcmCX1OLb5BT4
$ echo "APP_SECRET_KEY=$(openssl rand -base64 36)"
APP_SECRET_KEY=QSiIX2+Fvu5FBXaWOvlDSYKdixxpufvUQv5wWGmBEvrV+coz
三把密钥的职责(官方配置文档口径):ENCRYPTION_KEY 加密第三方连接凭据、WEBHOOK_SECRET_KEY 校验 webhook 请求、APP_SECRET_KEY 用于用户认证签名。官方以 DANGER 级别警示:密钥一经使用不可更换,否则既有连接与 flow 全部失效。
3.2 编排文件
落盘为 /opt/automatisch/docker-compose.yml(本次实测路径为 /opt/data/quzuo/tmp/automatisch/stack/docker-compose.yml,读者按自己目录习惯放置即可):
name: automatisch-0.15.0-stack
services:
main:
image: automatischio/automatisch:0.15.0
container_name: automatisch-0.15.0-main
ports:
- '8140:3000'
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_started
environment:
- APP_ENV=production
- HOST=localhost
- PROTOCOL=http
- PORT=3000
- WEB_APP_URL=http://192.168.146.128:8140
- WEBHOOK_URL=http://192.168.146.128:8140
- REDIS_HOST=redis
- POSTGRES_HOST=postgres
- POSTGRES_DATABASE=automatisch
- POSTGRES_USERNAME=automatisch_user
- POSTGRES_PASSWORD=automatisch_password
- ENCRYPTION_KEY=18hhdCO6CwRZMTx5uw6WguO78THNb7tqK/NNddXFiIvVjtUd
- WEBHOOK_SECRET_KEY=kDxuA81RZUcYMWOnSEnvzHTxuqVaQsQipTqmcmCX1OLb5BT4
- APP_SECRET_KEY=QSiIX2+Fvu5FBXaWOvlDSYKdixxpufvUQv5wWGmBEvrV+coz
- ENABLE_BULLMQ_DASHBOARD=true
- BULLMQ_DASHBOARD_USERNAME=admin
- BULLMQ_DASHBOARD_PASSWORD=q1w2e3r4
volumes:
- automatisch_storage:/automatisch/storage
networks:
- automatisch_net
worker:
image: automatischio/automatisch:0.15.0
container_name: automatisch-0.15.0-worker
depends_on:
- main
environment:
- APP_ENV=production
- REDIS_HOST=redis
- POSTGRES_HOST=postgres
- POSTGRES_DATABASE=automatisch
- POSTGRES_USERNAME=automatisch_user
- POSTGRES_PASSWORD=automatisch_password
- WEB_APP_URL=http://192.168.146.128:8140
- WEBHOOK_URL=http://192.168.146.128:8140
- ENCRYPTION_KEY=18hhdCO6CwRZMTx5uw6WguO78THNb7tqK/NNddXFiIvVjtUd
- WEBHOOK_SECRET_KEY=kDxuA81RZUcYMWOnSEnvzHTxuqVaQsQipTqmcmCX1OLb5BT4
- APP_SECRET_KEY=QSiIX2+Fvu5FBXaWOvlDSYKdixxpufvUQv5wWGmBEvrV+coz
- WORKER=true
- ENABLE_BULLMQ_DASHBOARD=true
- BULLMQ_DASHBOARD_USERNAME=admin
- BULLMQ_DASHBOARD_PASSWORD=q1w2e3r4
volumes:
- automatisch_storage:/automatisch/storage
networks:
- automatisch_net
postgres:
image: postgres:14.5
container_name: automatisch-0.15.0-postgres
environment:
- POSTGRES_DB=automatisch
- POSTGRES_USER=automatisch_user
- POSTGRES_PASSWORD=automatisch_password
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ['CMD-SHELL', 'pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}']
interval: 10s
timeout: 5s
retries: 5
networks:
- automatisch_net
redis:
image: redis:7.0.4
container_name: automatisch-0.15.0-redis
volumes:
- redis_data:/data
networks:
- automatisch_net
volumes:
automatisch_storage:
postgres_data:
redis_data:
networks:
automatisch_net:
driver: bridge
ipam:
config:
- subnet: 10.89.56.0/24
编排要点逐条说明:
name: automatisch-0.15.0-stack:显式声明 Compose 项目名,多套自动化栈并存时避免同名项目互相覆盖(Compose 默认取目录名);- main 依赖条件:
postgres: service_healthy(等健康检查通过)+redis: service_started,与官方仓库编排一致,保证启动顺序正确; - worker 依赖 main:沿用官方编排的启动次序(worker 等 main 先起);
WORKER=true仅出现在 worker:这是两个进程唯一的镜像行为开关(官方文档明示两服务环境变量应保持一致,仅此一项差异);- 共用
automatisch_storage卷:main 与 worker 挂同一存储卷(/automatisch/storage),这是官方编排的约定,为源码构建方式下的密钥落盘与后续版本扩展保留语义; - BullMQ 仪表盘三变量(
ENABLE_BULLMQ_DASHBOARD+BULLMQ_DASHBOARD_USERNAME/PASSWORD):可选配置,启用后 worker 队列状态可通过/admin/queues查看,三个变量缺一不生效(详见本专栏运维篇); WEB_APP_URL与WEBHOOK_URL:把对外可达地址从默认的http://localhost:3000修正为宿主真实地址,机制与排障过程见第六章;- 健康检查:
pg_isready原样沿用官方定义; - 数据卷三个:应用存储、PostgreSQL 数据、Redis 数据各一,备份盘盘点见运维篇。
3.3 启动与日志验证
$ cd /opt/automatisch && docker compose up -d
Container automatisch-0.15.0-postgres Started
Container automatisch-0.15.0-redis Started
Container automatisch-0.15.0-postgres Waiting
Container automatisch-0.15.0-postgres Healthy
Container automatisch-0.15.0-main Started
Container automatisch-0.15.0-worker Starting
Container automatisch-0.15.0-worker Started
回显次序验证了编排设计的依赖链:postgres/redis 先起 → postgres 健康检查通过 → main 启动 → worker 启动。等待约 30 秒(首次启动需完成数据库迁移与种子用户创建),确认四进程状态:
$ docker compose ps --format 'table {{.Name}}\t{{.Status}}\t{{.Ports}}'
NAME STATUS PORTS
automatisch-0.15.0-main Up 45 seconds 0.0.0.0:8140->3000/tcp, [::]:8140->3000/tcp
automatisch-0.15.0-postgres Up 2 minutes (healthy) 5432/tcp
automatisch-0.15.0-redis Up 2 minutes 6379/tcp
automatisch-0.15.0-worker Up 45 seconds 3000/tcp
main 进程日志(关键段落节选,其中 seed 用户创建与服务监听两行是启动成功的标志):
$ docker logs automatisch-0.15.0-main | tail -15
yarn run v1.22.22
warning package.json: License should be a valid SPDX license expression
$ node --loader ./alias-loader.mjs ./bin/database/seed-user.js
(node:61) ExperimentalWarning: `--experimental-loader` may be removed in the future; instead use `register()`:
--import 'data:text/javascript,import { register } from "node:module"; import { pathToFileURL } from "node:url"; register("./alias-loader.mjs", pathToFileURL("./"));'
(Use `node --trace-warnings ...` to show where the warning was created)
2026-10-28 04:12:10:1210 [info]: User has been saved: user@automatisch.io
Done in 1.12s.
yarn run v1.22.22
warning package.json: License should be a valid SPDX license expression
$ node --loader ./alias-loader.mjs src/server.js
(node:94) ExperimentalWarning: `--experimental-loader` may be removed in the future; instead use `register()`:
--import 'data:text/javascript,import { register } from "node:module"; import { pathToFileURL } from "node:url"; register("./alias-loader.mjs", pathToFileURL("./"));'
(Use `node --trace-warnings ...` to show where the warning was created)
2026-10-28 04:12:11:1211 [info]: Server is listening on http://localhost:3000
从日志可见镜像内置入口的行为:main 进程启动时依次执行 db:migrate(数据库迁移)、db:seed:user(创建种子用户 user@automatisch.io)、start(启动 Web 服务)。
worker 进程日志(节选):
$ docker logs automatisch-0.15.0-worker | tail -5
yarn run v1.22.22
warning package.json: License should be a valid SPDX license expression
$ node --loader ./alias-loader.mjs src/worker.js
(Use `node --trace-warnings ...` to show where the warning was created)
2026-10-28 04:12:10:1210 [info]: Workers are ready!
Workers are ready! 表示 worker 已连上 Redis 队列并就位消费。四进程各就各位后,验证 HTTP 服务:
$ curl -s -o /dev/null -w 'HTTP %{http_code} (%{time_total}s)\n' http://127.0.0.1:8140/
HTTP 200 (0.007357s)
$ curl -s http://127.0.0.1:8140/healthcheck -w 'HTTP %{http_code}\n'
HTTP 200
3.4 登录 Web 界面
浏览器访问 http://192.168.146.128:8140,使用官方内置演示账号登录:邮箱 user@automatisch.io、密码 sample(官方安装文档明示的开箱账号,fullName 为 Initial admin、角色 Admin)。登录后第一件事:在 Settings 页修改邮箱与密码(官方文档提示「Please do not forget to change your email and password from the settings page」)。
一个与直觉不同的行为需要提前知晓:首次安装后无法再通过注册接口创建新用户——Automatisch 0.15.0 的用户创建接口(POST /internal/api/v1/installation/users)只在整个实例零用户时开放,种子用户已占位,再调用注册接口返回 403(实测回显:空响应体 + HTTP 403)。社区版单用户的边界即在于此,多人使用需企业版(见《Automatisch 介绍与选型指南》第八章)。
四、方案 B:官方仓库源码编排部署(体验路径)
官方 README 与安装文档给出的默认路径是克隆仓库直接启动:
$ git clone https://github.com/automatisch/automatisch.git
$ cd automatisch
$ docker compose up
该编排(仓库内 docker-compose.yml)与方案 A 有三处本质差异,选型前必须理解:
| 差异点 | 方案 B(仓库编排) | 方案 A(镜像编排) |
|---|---|---|
| 服务进程来源 | 从源码构建(build: context: ./docker, dockerfile: Dockerfile.compose) | 直接使用 Docker Hub 官方镜像 automatischio/automatisch:0.15.0 |
| 入口脚本 | entrypoint: /compose-entrypoint.sh(仓库镜像内才存在) | 镜像自带 /entrypoint.sh |
| 三把密钥 | 首次启动自动生成并写入存储卷 .env(openssl rand -base64 36) | 部署者显式注入环境变量 |
| 版本控制 | 跟随仓库 main 分支漂移 | tag 钉死,可重现可回滚 |
| 首启耗时 | 需完整构建(Node.js monorepo,分钟级到十分钟级) | 秒级(仅拉镜像) |
踩坑实录(本文实测过程中的真实报错):直接复用仓库编排文件、仅把 build 段替换为 image: automatischio/automatisch:0.15.0 是不可行的——仓库编排里的 entrypoint: /compose-entrypoint.sh 指向的脚本只存在于源码构建产物中,官方镜像内并没有这个文件,启动直接失败:
$ docker compose up -d
Container automatisch-0.15.0-postgres Started
Container automatisch-0.15.0-redis Started
Container automatisch-0.15.0-postgres Waiting
Container automatisch-0.15.0-postgres Healthy
Container automatisch-0.15.0-main Starting
Error response from daemon: failed to create task for container: failed to create shim task:
OCI runtime create failed: runc create failed: unable to start container process:
error during container init: exec: "/compose-entrypoint.sh": stat /compose-entrypoint.sh:
no such file or directory
修正方法:删除编排文件中 main 与 worker 两处的 entrypoint: /compose-entrypoint.sh 行,让镜像使用自带入口 /entrypoint.sh(其逻辑为:main 执行 yarn db:migrate && yarn db:seed:user && yarn start,worker 检测到 WORKER 变量后执行 yarn start:worker)。密钥补偿措施:镜像自带入口不会自动生成三把密钥,必须按 3.1 节显式注入——这正是方案 A 编排文件把三密钥写全的原因。
两个方案的取舍结论:生产环境选方案 A(版本可控、启动快、密钥显式治理);只想快速体验且能接受构建耗时选方案 B(密钥零配置)。本文后续章节均基于方案 A 继续展开。
五、部署形态核对
部署完成后盘点栈的资源 footprint,确认与设计一致:
$ docker volume ls --format '{{.Name}}' | grep automatisch
automatisch-0150-stack_automatisch_storage
automatisch-0150-stack_postgres_data
automatisch-0150-stack_redis_data
$ docker network ls --format '{{.Name}}' | grep automatisch
automatisch-0150-stack_automatisch_net
说明:Compose 项目名中的 . 在资源命名时被规范化为 -(automatisch-0.15.0-stack → automatisch-0150-stack),这是 Compose 的命名约定,脚本化引用卷名/网络名时需注意。三个卷的用途与备份方法(pg_dump 逻辑备份 + 卷快照)在本专栏运维篇完整展开。
检查应用存储卷内容时有一个值得记录的实测事实:镜像方式下 automatisch_storage 卷是空的——只有方案 B 的 compose-entrypoint 才会把 .env 密钥文件写入该卷:
$ docker run --rm -v automatisch-0150-stack_automatisch_storage:/storage alpine ls -la /storage/
total 8
drwxr-xr-x 2 root root 4096 Oct 28 04:10 .
drwxr-xr-x 1 root root 4096 Oct 28 12:18 ..
因此方案 A 的密钥治理责任完全在编排文件与部署者:三把密钥应随编排文件纳入加密管理(vault/密管系统),不要只存在于某台机器的 yml 里。
六、外部可达性修正(WEBHOOK_URL 实测实录)
现象:按官方默认环境变量(HOST=localhost、PORT=3000)部署后,flow 触发器返回的 webhook 地址是 http://localhost:3000/webhooks/flows/<flowId>/sync——在本机 curl 可用,但外部系统回调必然失败。
定位:Automatisch 的 URL 拼装逻辑在服务端配置层(packages/backend/src/config/app.js,源码核实):
const apiUrl = new URL(process.env.API_URL || `${protocol}://${host}:${port}`).toString();
let webAppUrl = apiUrl;
if (process.env.WEB_APP_URL) {
webAppUrl = new URL(process.env.WEB_APP_URL).toString();
}
let webhookUrl = new URL(process.env.WEBHOOK_URL || apiUrl).toString();
三个结论:webAppUrl 优先取 WEB_APP_URL(默认回落 PROTOCOL://HOST:PORT);webhookUrl 只认 WEBHOOK_URL,不受 WEB_APP_URL 影响;两者都缺省时统一回落到 http://localhost:3000。
实测验证:先只加 WEB_APP_URL=http://192.168.146.128:8140(main 与 worker 两服务同步修改,官方文档明确要求「Please do not forget to change in main and worker services of docker-compose since the following variables might be used in both」),重启后查询 flow 详情:
$ docker compose up -d
Container automatisch-0.15.0-main Started
Container automatisch-0.15.0-worker Started
$ curl -s http://127.0.0.1:8140/internal/api/v1/flows/<flowId> -H "Authorization: <token>" \
| python3 -c "import json,sys; print(json.load(sys.stdin)['data']['steps'][0]['webhookUrl'])"
webhookUrl: http://localhost:3000/webhooks/flows/438ba068-5018-49f8-a60e-1018c9450566/sync
WEB_APP_URL 并没有改变 webhookUrl——与源码逻辑一致。补上 WEBHOOK_URL=http://192.168.146.128:8140(同样双服务同步)后重启再查:
webhookUrl: http://192.168.146.128:8140/webhooks/flows/438ba068-5018-49f8-a60e-1018c9450566/sync
修正生效。结论:对外提供 webhook 回调的部署必须设置 WEBHOOK_URL(反代场景同理);WEB_APP_URL 的职责是界面连接地址与 CORS 域,按需配置。全套环境变量的语义与优先级在《Automatisch 配置参数详解》中逐项展开。
七、常见问题(FAQ)
Q1:启动报 exec: "/compose-entrypoint.sh": no such file or directory 怎么处理?
这是把官方仓库编排(方案 B)的 entrypoint 惯例套在官方镜像上导致。删除编排中两处 entrypoint: /compose-entrypoint.sh,改用镜像自带入口,并按 3.1 节显式注入三把密钥(见第四章踩坑实录)。
Q2:main 一直起不来,日志报数据库连接失败?
确认 POSTGRES_HOST=postgres(服务名而非 localhost)、postgres 容器健康(docker compose ps 中 (healthy))、POSTGRES_PASSWORD 三个服务一致。postgres 健康检查未通过前 main 不会启动(depends_on 条件依赖)。
Q3:首次登录用什么账号?
官方内置演示账号 user@automatisch.io / sample(官方文档明示)。种子用户已占位注册接口,实例内无法再自注册(实测 403),改密在 Settings 页完成。
Q4:flow 激活时返回 422 All steps should be completed before updating flow status!?
每条 flow 的所有步骤(trigger + action)必须先通过测试或显式跳过(前端「Continue without test」,接口 POST /internal/api/v1/steps/<stepId>/continue-without-test)把状态从 incomplete 置为 completed,然后才能发布激活。完整操作链见运维篇。
Q5:修改了 ENCRYPTION_KEY 后所有连接报错?
官方 DANGER 警示的直接后果:ENCRYPTION_KEY 加密的凭据无法用新密钥解开。唯一出路是改回原密钥;确需轮换时必须按官方指引先导出重置相关凭据,不能直接换值重启。
Q6:升级怎么做?
方案 B 官方路径:git pull origin main 后 docker compose up --force-recreate --build(官方文档原文)。方案 A(镜像方式,生产推荐):改编排中的镜像 tag 至新版(如 0.15.0 → 后续版本),docker compose up -d 重建;main 进程启动时自动执行数据库迁移。升级前务必完成数据备份(方法见运维篇),并留意跨版本可能引入的迁移不可逆风险。
八、卸载与清理
$ docker compose down # 停止并删除四个服务进程与网络(保留数据卷)
$ docker compose down -v # 连同三个数据卷一起删除(彻底清空数据,慎用)
只卸载 Automatisch 保留数据时用前者;确认不再回迁时用后者。镜像清理:docker rmi automatischio/automatisch:0.15.0 postgres:14.5 redis:7.0.4。
九、参考链接
- 官方安装文档(Docker Compose / Docker 两路径):https://automatisch.io/docs/guide/installation (查询日期 2026-10-28)
- 官方配置文档(环境变量表与 main/worker 同步修改警示):https://automatisch.io/docs/advanced/configuration (查询日期 2026-10-28)
- Docker Hub 官方镜像:https://hub.docker.com/r/automatischio/automatisch (tag 0.15.0,2025-08-08 发布)
- 官方仓库(编排文件与入口脚本源码):https://github.com/automatisch/automatisch