EDA Docker Compose 部署指南

EDA(Edalitics)Docker Compose 部署指南:官方一体化镜像 + MySQL 样例数据源双服务编排、数据目录持久化、首次初始化与代理配置自愈(entrypoint 覆盖)、等价 docker run 与常用运维命令,含登录 400 与 /edapi 404 两大踩坑实录。

EDAEDADocker Compose数据可视化2026/10/30

EDA Docker Compose 部署指南

目标:在一台 Linux 服务器上用 Docker Compose 把 EDA(Edalitics)跑起来并接入一个 MySQL 业务库完成首张报表数据验证,重点沉淀官方一体化镜像在数据目录挂载与首次初始化上的两个实测踩坑及其自愈方案。已在 Debian 12(内核 6.1)、Docker 29.9.2、官方镜像 jortilles/eda:latest(2026-10-30 拉取,前端 3.1.2/后端 API 3.2.0 开发版)、MySQL 8.4 数据源环境下实测通过。

一、环境信息

  • 操作系统:Debian 12(x86_64,内核 6.1.x),4 vCPU / 8 GB 内存实测(官方镜像含 Chromium 与 MongoDB,磁盘占用约 7.4 GB,建议预留 10 GB 以上磁盘)
  • 编排工具:Docker 29.9.2 + Docker Compose v2(docker compose 插件)
  • EDA 服务:官方一体化镜像 jortilles/eda:latest(Docker Hub 官方渠道,内含 Apache 2.4.68 + Node.js 26.7 + MongoDB 8.0 + Playwright Chromium)
  • 数据源服务:mysql:8.4(用于模拟业务库,也可换成已有的外部数据库,非必需)
  • 网络与端口:自定义 bridge 网络 10.89.58.0/24,宿主机 Web 端口 8134(生产按需改为 80/443)
  • 部署目录:/opt/eda/(compose 文件与数据目录所在)
  • 默认管理员:eda@jortilles.com / default(官方默认,登录后应立即修改)

二、镜像选型说明

官方在 Docker Hub 维护两个镜像 tag 系列(仓库 README.md "Run edalitics with Docker" 节):

镜像 tag说明适用
jortilles/eda:latest主线自动构建(对应 master 分支),本次实测前端包版本 3.1.2、后端 API 版本声明 3.2.0 开发版生产建议用 digest 固定版本
jortilles/eda:manual_latest"manual deploy" 变体(仓库另有 Dockerfile_manual),首次启动时在机内现场 npm 构建前端需要自定义前端构建时

两个镜像都是"一体化"打包:Web 静态资源(Apache 托管)、后端 API(PM2 守护、监听内部 8666)、元数据库 MongoDB 8.0(数据目录 /eda/mongo/data)以及用于邮件截图的 Playwright Chromium,全部在同一镜像内。不存在官方的"前端/后端/数据库分离"三容器编排——这是与 Metabase、Redash 等"应用容器 + 外接元库"形态最大的差异,也决定了它的持久化与升级策略(见五、六章)。

⚠️ 注意:GitHub 稳定发布 tag(如 edalitics-3.1.2)与 Docker Hub 镜像 tag 不同步,Docker Hub 没有 edalitics-3.1.2 这样的版本 tag,latest 由 master 分支持续更新。生产环境固定版本的建议:首次拉取后记录镜像 digest(docker images --digests jortilles/eda),升级前备份元数据目录。

三、前置条件

  1. 服务器已安装 Docker 24+ 与 Docker Compose v2 插件(docker compose version 可执行);
  2. 磁盘剩余 ≥10 GB(镜像约 7.4 GB,另有 MongoDB 数据与日志增长空间);
  3. 内存 ≥4 GB(实测空闲态驻留约 2.5 GB,含 MongoDB 与 Chromium 依赖库);
  4. 准备一个供 EDA 分析的数据库(本文用 MySQL 8.4 现建样例库 salesdb;已有库可跳过,直接在第九章连接信息中填外部库地址);
  5. 如服务器在内网,提前确认能访问 Docker Hub(或已配置镜像加速/代理)。

四、部署步骤

4.1 目录与样例数据库脚本

mkdir -p /opt/eda/mysql-init            # 部署目录
cd /opt/eda

写入 MySQL 样例数据初始化脚本 /opt/eda/mysql-init/init.sql(EDA 首次连接验证用,已有业务库可省略):

-- 样例销售库:3 表 20 行
USE salesdb;
CREATE TABLE regions (
  region_id INT PRIMARY KEY,
  region_name VARCHAR(50) NOT NULL
);
CREATE TABLE products (
  product_id INT PRIMARY KEY,
  product_name VARCHAR(100) NOT NULL,
  category VARCHAR(50) NOT NULL,
  unit_price DECIMAL(10,2) NOT NULL
);
CREATE TABLE sales (
  sale_id INT AUTO_INCREMENT PRIMARY KEY,
  sale_date DATE NOT NULL,
  region_id INT NOT NULL,
  product_id INT NOT NULL,
  quantity INT NOT NULL,
  amount DECIMAL(12,2) NOT NULL,
  FOREIGN KEY (region_id) REFERENCES regions(region_id),
  FOREIGN KEY (product_id) REFERENCES products(product_id)
);
INSERT INTO regions VALUES (1,'华东'),(2,'华北'),(3,'华南'),(4,'西南');
INSERT INTO products VALUES
 (1,'机械键盘','外设',329.00),(2,'无线鼠标','外设',159.00),
 (3,'27寸显示器','显示设备',1899.00),(4,'USB-C 扩展坞','配件',399.00),
 (5,'降噪耳机','音频',1299.00);
INSERT INTO sales (sale_date, region_id, product_id, quantity, amount) VALUES
 ('2026-07-01',1,1,12,3948.00),('2026-07-03',2,3,5,9495.00),
 ('2026-07-08',1,2,30,4770.00),('2026-07-15',3,5,8,10392.00),
 ('2026-07-22',4,4,15,5985.00),('2026-08-02',1,5,6,7794.00),
 ('2026-08-05',2,1,20,6580.00),('2026-08-11',3,3,7,13293.00),
 ('2026-08-18',2,2,25,3975.00),('2026-08-25',4,1,10,3290.00),
 ('2026-09-01',1,4,22,8778.00),('2026-09-06',3,2,40,6360.00),
 ('2026-09-12',2,5,9,11691.00),('2026-09-20',1,3,4,7596.00),
 ('2026-09-28',4,2,18,2862.00),('2026-10-03',3,1,14,4606.00),
 ('2026-10-08',1,5,5,6495.00),('2026-10-15',2,4,12,4788.00),
 ('2026-10-21',3,3,6,11394.00),('2026-10-27',4,5,7,9093.00);

4.2 编排文件

写入 /opt/eda/docker-compose.yml:

name: eda-stack

services:
  eda:
    image: jortilles/eda:latest
    container_name: eda-app
    restart: unless-stopped
    # 关键:每次启动先恢复 Apache 反代配置,再进入官方启动脚本
    entrypoint: ["/bin/bash","-c","cp /eda/000-default.conf /etc/apache2/sites-available/ && a2enmod proxy proxy_http >/dev/null 2>&1; exec /eda/docker_run.sh"]
    ports:
      - "8134:80"                      # 生产可改 "80:80" 或前置 Nginx/Caddy
    volumes:
      - ./eda-data:/eda/mongo/data     # 元数据持久化(必需)
    networks:
      eda-net:
        ipv4_address: 10.89.58.10

  mysql:
    image: mysql:8.4
    container_name: eda-mysql
    restart: unless-stopped
    environment:
      MYSQL_ROOT_PASSWORD: q1w2e3r4
      MYSQL_DATABASE: salesdb
      MYSQL_USER: edauser
      MYSQL_PASSWORD: q1w2e3r4
    volumes:
      - ./mysql-init:/docker-entrypoint-initdb.d:ro
      - ./mysql-data:/var/lib/mysql
    networks:
      eda-net:
        ipv4_address: 10.89.58.20

networks:
  eda-net:
    driver: bridge
    name: eda-net
    ipam:
      config:
        - subnet: 10.89.58.0/24

💡 说明:entrypoint 覆盖不是可选美化,而是必需的自愈配置,原因见第七章踩坑一——官方启动脚本只在"首次初始化"分支里安装 Apache 反代配置,一旦数据目录以挂载方式存在(或容器重建过),这段配置就会被跳过,导致登录接口 404。上面的写法每次启动先补配置再走官方脚本,幂等且不改动官方逻辑。

⚠️ 注意:10.89.58.0/24 为自定义网段示例,部署前先 docker network ls 确认该段未被其他编排占用;宿主端口 8134 同理(ss -ltnp | grep 8134 确认空闲)。MySQL 仅在 EDA 与 MySQL 之间通信,无需向宿主机映射端口。

4.3 启动与初始化验证

cd /opt/eda && docker compose up -d

实测启动输出:

 Container eda-mysql  Healthy
 Container eda-app  Started

等待 30~60 秒(首次启动要拉起 MongoDB、执行 PM2 构建),验证 Web 就绪:

curl -s -o /dev/null -w "%{http_code}\n" http://localhost:8134/

实测回显:

200

4.4 登录验证(API 实测)

浏览器打开 http://<服务器IP>:8134,使用默认账号 eda@jortilles.com / default 登录。命令行等价验证(登录接口返回 JWT):

curl -s -X POST http://localhost:8134/edapi/admin/user/login \
  -H "Content-Type: application/json" \
  -d '{"email":"eda@jortilles.com","password":"default"}'

实测回显(节选):

{"user":{"_id":"135792467811111111111111","role":["135792467811111111111110"],"name":"EDA","email":"eda@jortilles.com",...},"token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9....","id":"135792467811111111111111"}

⚠️ 注意:登录请求体字段是 email,不是 user——传 user 会得到 {"status":400,"message":"Incorrect user"}。登录后第一时间在界面右上角用户菜单修改默认密码。

4.5 连接 MySQL 数据源并验证查询

登录界面后进入「数据源」→ 新建数据源,类型选 MySQL,连接信息填:

  • 主机:eda-mysql(同编排网络内的服务名;外部库填 IP 或域名)
  • 端口:3306,数据库:salesdb,用户:edauser,密码:q1w2e3r4

保存后 EDA 会自动读取库结构生成数据模型。命令行等价验证(先登录拿 token,再建数据源、直查 SQL):

TOKEN=$(curl -s -X POST http://localhost:8134/edapi/admin/user/login \
  -H "Content-Type: application/json" \
  -d '{"email":"eda@jortilles.com","password":"default"}' | python3 -c "import json,sys;print(json.load(sys.stdin)['token'])")

curl -s -X POST "http://localhost:8134/edapi/datasource/add-data-source/?token=$TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name":"salesdb-mysql","type":"mysql","host":"eda-mysql","database":"salesdb","port":3306,"user":"edauser","password":"q1w2e3r4","warehouse":null,"schema":null,"poolLimit":10,"sid":1,"optimize":0,"allowCache":1,"ssl":false,"filter":null,"external":{}}'

实测回显(HTTP 201):

{"ok": true, "data_source_id": "6ae3ffe5ddadf93009f1d2e5"}

用刚生成的数据源 ID 直查一条聚合 SQL 验证链路:

DS=6ae3ffe5ddadf93009f1d2e5
curl -s -X POST "http://localhost:8134/edapi/dashboard/sql-query?token=$TOKEN" \
  -H "Content-Type: application/json" \
  -d "{\"model_id\":\"$DS\",\"query\":{\"SQLexpression\":\"SELECT r.region_name AS region, SUM(s.amount) AS total FROM sales s JOIN regions r ON s.region_id = r.region_id GROUP BY r.region_name ORDER BY total DESC\",\"filters\":[],\"queryMode\":\"sql\"}}"

实测回显:

[["region","total"],[["华南",46045],["华东",39381],["华北",36529],["西南",21230]]]

四区域合计 143185,与 init.sql 中 20 行 amount 之和一致,链路验证通过。更多 API 端点(用户管理、仪表盘 CRUD、查询约定)见《EDA API 使用详解》。

五、数据持久化说明

EDA 需要持久化的只有一处:元数据目录 /eda/mongo/data(MongoDB 数据文件,含全部用户、数据源、数据模型与仪表盘定义)。编排文件用 ./eda-data:/eda/mongo/data bind mount 落在部署目录,便于随目录整体备份。业务数据永远不存 EDA——查询实时下推到源库,因此源库的备份策略独立于 EDA。

持久化的实测行为:

  • docker compose restart 或宿主机重启(restart: unless-stopped 生效)后数据完整保留,实测重启后登录与已建数据源均正常;
  • docker compose down 后 up 重建服务实例,元数据保留(在挂载目录中),但需靠 4.2 的 entrypoint 自愈恢复 Web 反代配置,实测重建后登录与数据源均正常;
  • 升级镜像(拉新 tag 后重建)同样只动程序不动数据;升级前建议对 eda-data 目录做冷备(先 docker compose stop eda 再打包目录)。

六、常用环境变量表

官方镜像的环境变量面很窄——一体化单元的行为基本由初始化脚本与 MongoDB 内的配置集合决定,可调项如下:

环境变量默认值说明
DEBIAN_FRONTENDnoninteractive镜像构建期 apt 行为,运行时无需设置
LD_LIBRARY_PATH/eda/oracle/instantclientOracle 即时客户端库路径(启动脚本内置导出;如需连 Oracle,把 instantclient 放到该路径)
TZ(建议自行注入)UTC容器内时区;KPI 定时邮件等计划任务按此时区调度,建议 - TZ=Asia/Shanghai

除此之外的可配置行为(MongoDB 连接串、后端监听端口、前端 API 地址)都固化在镜像内配置文件中,见第七章与《EDA 配置参数详解》。

七、常见问题(FAQ)

Q1:登录报 {"status":400,"message":"Incorrect user"}?

这是本次部署实测踩到的第一大坑。根因:官方启动脚本 docker_run.sh 以"/eda/mongo/data 目录是否存在"判定是否首次安装——当该路径被编排挂载(挂载点必然存在)时,脚本判定"已安装",跳过了管理员账号与角色组的初始化写入,元数据库里没有用户,任何账号都登不上。

实测修复(进入服务单元补执行一次初始化,之后再重启也不再需要):

docker exec -it eda-app bash
mongosh --eval 'db.users.insertOne( { "_id" : ObjectId("135792467811111111111111"), "role" : [ ObjectId("135792467811111111111110") ], "name" : "EDA", "email" : "eda@jortilles.com", "password" : "$2a$10$J48xu5KAqobLzvD8FX1LOem7NZUMuXPHID1uSHzbzTbM.wGFPXjb2" } )' EDA
mongosh --eval 'db.groups.insertOne( { "_id": ObjectId("135792467811111111111110"), "role": "EDA_ADMIN_ROLE", "name" : "EDA_ADMIN", "users":[ ObjectId("135792467811111111111111") ] } )' EDA
exit

更省事的做法是采用 4.2 编排文件的 entrypoint 自愈方案从源头规避(该方案同时解决 Q2)。Q1 与 Q2 是同一根因的两个症状:初始化分支被跳过时,管理员写入与 Apache 反代配置同时丢失。

Q2:页面能打开,但所有 /edapi/... 接口都 404(Apache 默认页)?

同一根因的第二个症状:反代配置 /eda/000-default.conf(内含 ProxyPass /edapi/ http://localhost:8666/)只在首次初始化分支被安装。判断方法:页面正常但接口 404,且 docker exec eda-app grep -c ProxyPass /etc/apache2/sites-enabled/000-default.conf 输出 0。修复即 4.2 的 entrypoint 覆盖,或手工补一次配置后重启服务内的 Apache:

docker exec eda-app bash -c "cp /eda/000-default.conf /etc/apache2/sites-available/ && a2enmod proxy proxy_http >/dev/null 2>&1 && service apache2 restart"

Q3:docker compose down 再 up 后登录 404,但重启(restart)就没事?

restart 保留服务单元可写层(Apache 配置文件改动还在);down 删除单元重建,可写层清空、配置回到镜像原始状态(无反代),而数据目录挂载点又让初始化分支被跳过——正是 Q2 的复现路径。自愈 entrypoint 可彻底规避。

Q4:数据源连接测试失败?

按顺序排查:服务名是否写对(同编排网络内用服务名 eda-mysql,不是 localhost);MySQL 是否只允许内网访问(bind-address);账号密码与 salesdb 库权限(GRANT 是否授予)。可用 API 的连接测试端点复核(见《EDA API 使用详解》连接测试节)。

Q5:镜像拉取慢或超时?

镜像约 7.4 GB,海外直连慢时配置 Docker 镜像加速器或拉取代理(HTTPS_PROXY=http://<proxy>:7897 docker pull jortilles/eda:latest)。

八、等价 docker run 运行方式

不用编排的单命令等价形态(官方 README 推荐写法):

docker run -d --name eda-app -p 8134:80 -v /opt/eda/eda-data:/eda/mongo/data jortilles/eda:latest

注意:单命令形态没有 entrypoint 自愈,等于默认接受第七章两个踩坑行为——纯体验无妨,生产不建议。编排方式与单命令的差异对照:

维度Docker Compose(本篇)单命令 docker run
数据持久化bind mount 显式声明,目录随部署仓管理需手写 -v,易遗漏
初始化/反代自愈entrypoint 覆盖,重建服务实例后自愈无,重建后踩 Q1/Q2
与数据源组网同一自定义网络,服务名互访需手动 --network
开机自启restart: unless-stopped 统一声明需手写 --restart

九、常用运维命令

# 状态与日志
docker compose ps                          # 双服务运行状态
docker compose logs -f eda                 # 跟踪 EDA 启动与 API 日志(PM2/MongoDB/Apache 混合输出)
docker compose logs eda 2>&1 | grep -i error

# 生命周期
docker compose restart eda                 # 重启 EDA(数据与配置均保留)
docker compose stop && docker compose up -d   # 变更编排文件后的常规生效方式

# 备份元数据(冷备)
docker compose stop eda
tar czf eda-data-$(date +%F).tgz eda-data/
docker compose start eda

# 镜像升级
docker pull jortilles/eda:latest
docker compose up -d eda                   # 重建服务实例挂新镜像,元数据保留

十、参考链接