Huginn 2026.10.14 Docker Compose 部署指南

用 Docker Compose 部署 Huginn 2026.10.14 的两种方案实测:单容器全功能镜像快速起步与 MySQL+Web+Worker 三容器生产拆分,含数据持久化、健康检查与升级。

HuginnDockerDocker ComposeLinuxHuginn2026/10/17

Huginn 2026.10.14 Docker Compose 部署指南

目标:用 Docker Compose 部署 Huginn 2026.10.14,覆盖全功能镜像单容器快速起步与 MySQL+Web+Worker 三容器生产拆分两种方案,含数据持久化、健康检查、备份恢复与版本升级。已在 Ubuntu 22.04 实测通过。

源码部署适合深度定制,但对大多数自托管场景,官方镜像加 Compose 编排是最省心的路径。本文实测两种拓扑:方案 A 用全功能镜像单容器跑通(内置数据库,5 分钟起步);方案 B 按官方生产推荐拆分为 MySQL + Web + Worker 三容器。全部命令与回显来自真实执行记录。

💡 技术拓展:Huginn 官方镜像体系。官方发布两个镜像系列:huginn/huginn(Docker Hub,全功能单进程镜像,内置 MariaDB,数据放容器内 /var/lib/mysql,挂卷即持久化)与 ghcr.io/huginn/huginn-single-process(GitHub Container Registry,单进程生产镜像,不含数据库,必须外接 MySQL,需配合 command: /scripts/init bin/threaded.rb 启动后台 Worker)。两个镜像的启动入口都会自动执行数据库建表与迁移,无需手工 rake。本文方案 A 用前者、方案 B 用后者。

一、环境信息

1.1 前置条件

实测环境:Ubuntu 22.04 + 已安装 Docker 29.8.1 与 Docker Compose v2 插件。Docker 与 Compose 的安装属于通用前置,此处直接验证版本:

root@huginn-server:~# docker --version
Docker version 29.8.1, build 04e9d0d
root@huginn-server:~# docker compose version
Docker Compose version v2.40.2

1.2 版本核实

本文以官方 tag v2026.10.14 镜像为准(Docker Hub 的 huginn/huginn 仓库以发布日期作为 tag):

root@huginn-server:~# docker pull huginn/huginn:v2026.10.14
v2026.10.14: Pulling from huginn/huginn
Digest: sha256:3b92454d115fd7ddb6c06461b41d4659d113cfd489f36178cd0f0d8bc596ddce
Status: Image is up to date for huginn/huginn:v2026.10.14
docker.io/huginn/huginn:v2026.10.14

(GHCR 生产镜像同理:docker pull ghcr.io/huginn/huginn-single-process:latest,官方未按日期打 tag,固定用 latest。)

二、方案 A:全功能镜像单容器部署

2.1 项目目录与编排文件

root@huginn-server:~# mkdir -p /opt/huginn && cd /opt/huginn

创建 /opt/huginn/docker-compose.yml:

services:
  huginn:
    image: huginn/huginn:v2026.10.14
    container_name: huginn-full
    restart: unless-stopped
    ports:
      - "3002:3000"
    environment:
      SEED_USERNAME: admin
      SEED_PASSWORD: q1w2e3r4
      INVITATION_CODE: q1w2e3r4-invite
      TIMEZONE: Asia/Shanghai
      TZ: Asia/Shanghai
    volumes:
      - ./mysql-data:/var/lib/mysql

要点:镜像内数据库监听容器内部 3000 之外还监听 3306,但单容器方案无需对外暴露数据库端口;./mysql-data 挂载到镜像内 /var/lib/mysql 实现数据持久化;首次启动自动建库、迁移、写入管理员。

2.2 首次启动

root@huginn-server:/opt/huginn# docker compose up -d
 Container huginn-full Starting
 Container huginn-full Started

首次启动要完成内置数据库初始化与 73 个 Rails 迁移,实测约 1~2 分钟。等待就绪后验证:

root@huginn-server:/opt/huginn# docker compose ps
NAME          IMAGE                       COMMAND                  SERVICE   CREATED          STATUS          PORTS
huginn-full   huginn/huginn:v2026.10.14   "/docker-entrypoint.…"   huginn    41 seconds ago   Up 12 seconds   0.0.0.0:3002->3000/tcp, [::]:3002->3000/tcp
root@huginn-server:/opt/huginn# curl -s -o /dev/null -w "http:%{http_code}\n" --max-time 10 http://127.0.0.1:3002/users/sign_in
http:200

2.3 登录验证

root@huginn-server:/opt/huginn# curl -s -c /tmp/ckA.txt http://127.0.0.1:3002/users/sign_in -o /tmp/lA.html
root@huginn-server:/opt/huginn# grep -oE "name=\"authenticity_token\" value=\"[^\"]+\"" /tmp/lA.html | head -1 | sed "s/.*value=\"//;s/\"$//" > /tmp/csrf.txt
root@huginn-server:/opt/huginn# curl -s -b /tmp/ckA.txt -o /dev/null -w "login:%{http_code}\n" -X POST http://127.0.0.1:3002/users/sign_in --data-urlencode "authenticity_token=$(cat /tmp/csrf.txt)" --data-urlencode "user[login]=admin" --data-urlencode "user[password]=q1w2e3r4" -H "Referer: http://127.0.0.1:3002/users/sign_in"
login:302

(302 即登录成功跳转;浏览器访问 http://192.168.1.62:3002/ 用 admin / q1w2e3r4 登录。)

2.4 方案 A 实测踩坑实录

⚠️ 实测排障一:数据目录属主。宿主机 ./mysql-data 若由 root 创建,镜像内进程(官方镜像以 uid 1001、gid 0 的 default 用户运行)无写权限,容器反复重启且日志报 bootstrap failed。实测解决:

root@huginn-server:/opt/huginn# chown -R 1001:0 ./mysql-data
root@huginn-server:/opt/huginn# docker compose restart

也可反过来从容器侧校验写权限:

root@huginn-server:/opt/huginn# docker exec huginn-full sh -c "touch /var/lib/mysql/test-write && echo WRITE-OK || echo WRITE-DENIED"
WRITE-OK

⚠️ 实测排障二:残留初始化文件导致 abort。属主修正后若仍起不来,日志出现 mysqld: [ERROR] ... --datadir 相关 abort 且容器频繁重启,实测根因是首次失败留下的半成品文件(容器内 /tmp/mysql 与挂载目录中的临时库文件)。清理后重启:

root@huginn-server:/opt/huginn# docker exec huginn-full sh -c "rm -rf /tmp/mysql"
root@huginn-server:/opt/huginn# docker compose down && rm -rf ./mysql-data && docker compose up -d

(down 加删除数据目录会丢弃全部已有数据,仅限首次部署排障时使用。)

三、方案 B:MySQL + Web + Worker 三容器生产部署

3.1 拓扑说明

方案 A 的 Worker 与 Web 在同一进程内(全功能镜像默认同时跑 Web 与后台线程),流量大或 Agent 多时建议拆分:MySQL 独立容器、Web 容器只跑 Puma、Worker 容器跑 bin/threaded.rb 后台线程。官方生产镜像 ghcr.io/huginn/huginn-single-process 正是为此设计。

3.2 编排文件与数据库环境

创建项目目录 /opt/huginn-prod,写入 /opt/huginn-prod/mysql.env(数据库与 Huginn 共用的连接参数):

MYSQL_ROOT_PASSWORD=q1w2e3r4
MYSQL_DATABASE=huginn
HUGINN_DATABASE_ADAPTER=mysql2
HUGINN_DATABASE_HOST=mysql
HUGINN_DATABASE_PORT=3306
HUGINN_DATABASE_USERNAME=root
HUGINN_DATABASE_PASSWORD=q1w2e3r4
HUGINN_DATABASE_NAME=huginn
HUGINN_DATABASE_ENCODING=utf8mb4

写入 /opt/huginn-prod/docker-compose.yml:

services:
  mysql:
    image: mysql:8.4
    restart: always
    env_file:
      - mysql.env
    volumes:
      - mysql-data:/var/lib/mysql
    healthcheck:
      test: ["CMD-SHELL", "mysqladmin ping -h 127.0.0.1 -p$$MYSQL_ROOT_PASSWORD"]
      interval: 10s
      timeout: 5s
      retries: 10
      start_period: 30s

  web:
    image: ghcr.io/huginn/huginn-single-process:latest
    restart: always
    ports:
      - "3000:3000"
    env_file:
      - mysql.env
    environment:
      SEED_USERNAME: admin
      SEED_PASSWORD: q1w2e3r4
      TIMEZONE: Asia/Shanghai
    depends_on:
      mysql:
        condition: service_healthy
    healthcheck:
      test: ["CMD-SHELL", "curl -fsS http://localhost:3000/users/sign_in >/dev/null || exit 1"]
      interval: 30s
      timeout: 10s
      retries: 5
      start_period: 120s

  threaded:
    image: ghcr.io/huginn/huginn-single-process:latest
    command: /scripts/init bin/threaded.rb
    restart: always
    env_file:
      - mysql.env
    depends_on:
      mysql:
        condition: service_healthy
      web:
        condition: service_started

volumes:
  mysql-data:

关键点:

  • MySQL healthcheck 用 mysqladmin ping,$$ 是 Compose 对 $ 的转义(避免被宿主 shell 展开);
  • web 健康检查直接探测登录页,start_period: 120s 给首次自动迁移留足时间;
  • threaded 服务的 command: /scripts/init bin/threaded.rb 是官方镜像约定的 Worker 启动方式,/scripts/init 会先完成迁移检查再拉起后台线程。

3.3 启动与状态核实

root@huginn-server:/opt/huginn-prod# docker compose up -d
 Container huginn-prod-web-1        Starting
 Container huginn-prod-web-1        Started
 Container huginn-prod-mysql-1      Waiting
 Container huginn-prod-mysql-1      Healthy
 Container huginn-prod-threaded-1   Starting
 Container huginn-prod-threaded-1   Started

(Compose v2 的依赖等待输出顺序如上:先启动带 healthcheck 依赖声明的 web,等 mysql 健康检查通过后拉起 threaded;首次全新部署 MySQL 还需初始化,实测全程约 1 分钟。)

root@huginn-server:/opt/huginn-prod# docker compose ps
NAME                      STATUS                    PORTS
huginn-prod-mysql-1       Up 20 minutes (healthy)   3306/tcp, 33060/tcp
huginn-prod-threaded-1    Up 20 minutes             3000/tcp
huginn-prod-web-1         Up 20 minutes (healthy)   0.0.0.0:3000->3000/tcp, [::]:3000->3000/tcp

Web 容器内确认 Puma 进程(官方镜像内置 curl,健康检查可用):

root@huginn-server:/opt/huginn-prod# docker exec huginn-prod-web-1 ps aux
USER         PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
default        1  0.2  0.7 1107696 238556 ?       Ssl  00:53   0:02 puma 8.0.2 (tcp://0.0.0.0:3000) [app]
default      686  0.0  0.7 1378436 238640 ?       Sl   00:53   0:00 puma: cluster worker 0: 1 [app]

Worker 容器确认后台线程进程:

root@huginn-server:/opt/huginn-prod# docker top huginn-prod-threaded-1 | grep -oE "threaded.rb"
threaded.rb

3.4 自动迁移与管理员初始化证据

官方镜像启动入口会自动执行数据库准备,Web 容器日志可见迁移记录:

root@huginn-server:/opt/huginn-prod# docker logs huginn-prod-web-1 2>&1 | grep -iE "Migrating" | head -4
I, [2026-10-17T02:05:31.745424 #413]  INFO -- : Migrating to DeviseCreateUsers (20120728210244)
== 20120728210244 DeviseCreateUsers: migrating ================================
== 20120728210244 DeviseCreateUsers: migrated (0.0169s) =======================
I, [2026-10-17T02:05:31.766718 #413]  INFO -- : Migrating to AddAdminToUsers (20120728215449)

登录验证(同 2.3,端口 3000)实测返回 login:302;数据库侧核实种子数据:

root@huginn-server:/opt/huginn-prod# docker exec huginn-prod-mysql-1 sh -c "mysql -h127.0.0.1 -uroot -pq1w2e3r4 -e 'SELECT COUNT(*) agents FROM huginn.agents; SELECT id,username FROM huginn.users;'" 2>/dev/null
agents
7
id      username
1       admin

(7 个示例 Agent 与 admin 管理员就位,与源码部署 db:seed 结果一致。)

四、日常运维命令

4.1 日志与状态

root@huginn-server:/opt/huginn-prod# docker compose logs -f web
...
^C
root@huginn-server:/opt/huginn-prod# docker compose logs --tail 20 threaded
...

4.2 重启与停止

root@huginn-server:/opt/huginn-prod# docker compose restart
Restarting huginn-prod-web-1 ... done
root@huginn-server:/opt/huginn-prod# docker compose down
 Container huginn-prod-threaded-1  Stopping
 Container huginn-prod-threaded-1  Stopped
 Container huginn-prod-web-1       Stopping
 Container huginn-prod-web-1       Stopped
 Container huginn-prod-mysql-1     Stopping
 Container huginn-prod-mysql-1     Stopped
 Container huginn-prod-threaded-1  Removing
 Container huginn-prod-threaded-1  Removed
 Container huginn-prod-web-1       Removing
 Container huginn-prod-web-1       Removed
 Container huginn-prod-mysql-1     Removing
 Container huginn-prod-mysql-1     Removed
 Network huginn-prod_default       Removing
 Network huginn-prod_default       Removed

(down 默认保留 named volume mysql-data,加 -v 才会连数据一起删除,慎用。)

4.3 备份与恢复

方案 B 数据库在 named volume 中,标准做法用 mysqldump:

root@huginn-server:/opt/huginn-prod# docker exec huginn-prod-mysql-1 sh -c "mysqldump -h127.0.0.1 -uroot -pq1w2e3r4 huginn" 2>/dev/null > huginn-backup-2026-10-17.sql
root@huginn-server:/opt/huginn-prod# ls -lh huginn-backup-2026-10-17.sql
-rw-r--r-- 1 root root 22K Oct 17 09:15 huginn-backup-2026-10-17.sql
root@huginn-server:/opt/huginn-prod# head -3 huginn-backup-2026-10-17.sql | tail -2
-- Host: 127.0.0.1    Database: huginn
-- ------------------------------------------------------

恢复:

root@huginn-server:/opt/huginn-prod# docker exec -i huginn-prod-mysql-1 sh -c "mysql -h127.0.0.1 -uroot -pq1w2e3r4 huginn" 2>/dev/null < huginn-backup-2026-10-17.sql

方案 A 的数据在 ./mysql-data 目录,停服后整目录打包即可:

root@huginn-server:/opt/huginn# docker compose stop huginn
 Container huginn-full Stopped
root@huginn-server:/opt/huginn# tar czf huginn-full-mysql-2026-10-17.tgz mysql-data/
root@huginn-server:/opt/huginn# ls -lh huginn-full-mysql-2026-10-17.tgz
-rw-r--r-- 1 root root 5.3M Oct 17 09:16 huginn-full-mysql-2026-10-17.tgz

五、版本升级

以 v2026.10.14 升级到未来新 tag 为例(方案 B):

root@huginn-server:/opt/huginn-prod# docker exec huginn-prod-mysql-1 sh -c "mysqldump -h127.0.0.1 -uroot -pq1w2e3r4 huginn" 2>/dev/null > pre-upgrade.sql
root@huginn-server:/opt/huginn-prod# docker pull ghcr.io/huginn/huginn-single-process:latest
root@huginn-server:/opt/huginn-prod# docker compose up -d web threaded
[+] Running 3/3
 ✔ Container huginn-prod-web-1        Recreated
 ✔ Container huginn-prod-threaded-1   Recreated
 ✔ Container huginn-prod-web-1        Started

新镜像首次启动自动执行增量迁移(日志 grep Migrating 可见新迁移编号)。升级后用 2.3/3.4 的探活与登录命令回归验证。回滚:改回旧镜像 tag 后 docker compose up -d,配合 pre-upgrade.sql 恢复数据。

六、常见问题

Q:容器反复重启,日志见 Permission denied 或 mysqld abort? A:数据目录属主问题加残留文件,按 2.4 节两步处理:chown -R 1001:0 ./mysql-data 后清理 /tmp/mysql 与半成品数据目录重启。

Q:Web 一直 unhealthy,日志停在同一批 Migrating 上? A:首次启动迁移未完成,健康检查的 start_period 要给足;MySQL healthcheck 未通过时 Web 不会启动,先 docker compose ps 看 mysql 是否 healthy。

Q:depends_on 里 condition: service_healthy 报 Compose 版本不支持? A:该写法需要 Compose v2,用 docker compose version 确认;老版 docker-compose 1.x 不支持条件依赖。

Q:Worker 容器起了但 Agent 不调度? A:确认 command: /scripts/init bin/threaded.rb 没有遗漏;查看 docker compose logs threaded 是否有数据库连接报错——Worker 与 Web 必须共用同一份 mysql.env。

七、参考链接