Apache DolphinScheduler 单机部署实战 | Docker 一把梭,10分钟搞定!
📝 摘要:DolphinScheduler 单机模式(Standalone)Docker 部署实战:先对比单机、伪集群、集群三种模式的取舍,再手把手四步搭建——部署 MySQL 并用它替换默认 H2、初始化官方建表 SQL、挂载 MySQL 驱动、docker Compose 启动容器。
三个必踩的坑:容器内连宿主机数据库不能用 127.0.0.1、换 MySQL 后不会自动建表、不配 TZ 定时任务整整错开 8 小时。改用 MySQL 持久化后,可随时重建、零数据迁移、平滑升级到集群。适合中小团队离线数仓调度。你的离线数仓还在用 crontab 调度?每次任务挂了靠同事喊你才知道?是时候上一个正经的调度平台了。本文手把手带你用 Docker 单机模式部署 DolphinScheduler,10 分钟搞定,轻量够用,附赠监控方案。
DolphinScheduler 部署模式,选哪个?
DolphinScheduler 提供三种部署模式,先花 30 秒搞清楚区别,免得选错了回头重来(别问我怎么知道的 🥲):
| 模式 | 特点 | 适合场景 |
|---|---|---|
| 单机模式(Standalone) | 所有服务跑在一个进程里,内置 ZooKeeper + H2 数据库,开箱即用 | 快速体验、测试环境、中小团队 |
| 伪集群模式(Pseudo-Cluster) | 单台机器部署所有服务(Master、Worker、API Server 等),但各服务独立进程 | 需要更细粒度控制的单机场景 |
| 集群模式(Cluster) | 多台机器部署,Master/Worker 可多节点水平扩展 | 大规模生产环境 |
一句话总结:小团队用单机模式就够了——而且只要按本文的方式换掉默认数据库,将来升级集群是零数据迁移的(§六 会展开)。
二、为什么选单机模式?
网上铺天盖地的集群部署教程,看着就头大——3 台机器起步、ZooKeeper 集群、MySQL 主从……
打住! 你确定你的场景需要这么重?
以我的实际业务为例:
- 🔢 25 个工作流,每天产生不到 300 个工作流实例
- 📊 每天任务实例不到 1500 个
- ✅ 单机模式稳定运行,毫无压力
更关键的是——离线数仓场景下,即使 DolphinScheduler 短暂挂掉,对线上业务零影响。任务晚跑几分钟,数据不会丢,天不会塌。
💡 核心思路:在单机模式基础上,用 MySQL 替换默认的 H2 数据库。注意 standalone 默认那个 H2 走的是 jdbc:h2:mem: ——纯内存,不是「可能丢数据」,是容器一重启工作流定义、调度记录全部归零。拿它跑生产,等于把家当放在断电就清空的柜子里。换成 MySQL,数据持久化才谈得上安心。
另一个好处是:数据存在 MySQL 后,DolphinScheduler 本身可以随时重建。后续如果需要集成插件、自定义镜像,直接重新部署容器,连上同一个 MySQL 即可恢复所有配置,零成本重来。
三、实战部署(四步搞定)
第一步:部署 MySQL
如果你已经有现成的 MySQL 实例,可以跳过这一步,直接建库授权即可。
docker run --name dolphin-mysql \ -e MYSQL_ROOT_PASSWORD='YourRootPass@2025' \ -e MYSQL_DATABASE=ds_scheduler \ -e MYSQL_USER=ds_admin \ -e MYSQL_PASSWORD='DsPass@2025' \ -p 13306:3306 \ -v /data/dolphin-mysql/data:/var/lib/mysql \ --restart unless-stopped \ -d mysql:8.0.42 \ --default-authentication-plugin=mysql_native_password \ --character-set-server=utf8mb4 \ --collation-server=utf8mb4_unicode_ci
几个注意点:
- 端口映射用了
13306而非默认3306,避免和宿主机已有的 MySQL 冲突 mysql_native_password省掉caching_sha2_password在非 SSL 连接下要走 RSA 公钥交换的那一套麻烦。⚠️ 注意版本:这个参数在 MySQL 8.0.34 起已标记废弃(启动会打 deprecation 警告,但仍能用),8.4 直接移除了该插件——如果你用的是 8.4+,这行要删掉,改用caching_sha2_password(8.x 的 JDBC 驱动本身是支持的)- 密码请务必修改为你自己的强密码,别学我之前用
123456(真实故事,不展开说了)
第二步:初始化数据库表结构
MySQL 容器启动后只会创建一个空库,DolphinScheduler 需要的几十张表并不会自动生成。我们需要手动执行官方提供的初始化 SQL:
# 下载 DolphinScheduler 3.2.0 的 MySQL 初始化脚本wget -O /tmp/dolphinscheduler_mysql.sql \ https://raw.githubusercontent.com/apache/dolphinscheduler/3.2.0/dolphinscheduler-dao/src/main/resources/sql/dolphinscheduler_mysql.sql# 将 SQL 文件拷贝到 MySQL 容器内docker cp /tmp/dolphinscheduler_mysql.sql dolphin-mysql:/tmp/# 执行初始化(注意替换为你自己的密码)docker exec -i dolphin-mysql mysql -uds_admin -p'DsPass@2025' ds_scheduler < /tmp/dolphinscheduler_mysql.sql
执行完后可以验证一下表是否创建成功:
docker exec dolphin-mysql mysql -uds_admin -p'DsPass@2025' ds_scheduler -e "SHOW TABLES;" | head -20
正常情况下应该能看到 t_ds_process_definition、t_ds_worker_group 等一系列表。如果输出为空,检查上一步 SQL 执行有没有报错。
⚡ 这一步别跳过! 换成 MySQL 之后没有任何自动建表——H2 模式下开箱即用的那套初始化不会发生。跳过的后果就是启动后喜提 Table 'xxx' doesn't exist。
第三步:下载 MySQL 驱动
DolphinScheduler 的 Docker 镜像默认不带 MySQL 驱动(毕竟人家也不知道你用哪个数据库),需要手动下载并挂载进容器:
mkdir -p /data/dolphin/lib/wget -P /data/dolphin/lib/ \ https://repo1.maven.org/maven2/mysql/mysql-connector-java/8.0.30/mysql-connector-java-8.0.30.jar
🤔 为什么不用最新版驱动?一是 8.0.30 经过验证是兼容的,版本这东西——能跑的不要动,这是运维第一定律;二是从 8.0.31 开始官方把 artifact 改名成了 mysql-connector-j(坐标从 mysql:mysql-connector-java 变成 com.mysql:mysql-connector-j),你照着「找最新版」去翻老路径只会 404。要用新版就得连下载地址和挂载文件名一起换。
第四步:部署 DolphinScheduler
创建 /data/dolphin/docker-compose.yml:
services: dolphinscheduler-standalone: image: apache/dolphinscheduler-standalone-server:3.2.0 container_name: dolphinscheduler-standalone # network_mode: "host" # 放开这行的同时,必须把下面的 extra_hosts 和 ports 一起注释掉 extra_hosts: - "host.docker.internal:host-gateway" # Linux 必须加这行,否则容器内无法解析该域名 ports: - "12345:12345" # Web UI + API 端口(唯一必须映射的) - "25333:25333" # Python 网关端口,只有用 PyDolphinScheduler 写工作流才需要,否则可删 environment: - TZ=Asia/Shanghai # 时区,见下方说明 - DATABASE_TYPE=mysql # 显式声明驱动类名,避免自动推断失败 - SPRING_DATASOURCE_DRIVER_CLASS_NAME=com.mysql.cj.jdbc.Driver # ⚠️ 注意:这里的 IP 要填宿主机的实际 IP 或 host.docker.internal,不能用 127.0.0.1 - SPRING_DATASOURCE_URL=jdbc:mysql://host.docker.internal:13306/ds_scheduler?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true - SPRING_DATASOURCE_USERNAME=ds_admin - SPRING_DATASOURCE_PASSWORD=DsPass@2025 volumes: - /data/dolphin/logs:/opt/dolphinscheduler/logs # 关键:挂载 MySQL 驱动到容器的 libs 目录 - /data/dolphin/lib/mysql-connector-java-8.0.30.jar:/opt/dolphinscheduler/libs/standalone-server/mysql-connector-java-8.0.30.jar restart: always
⏰ TZ 这行别省。 调度平台跑的全是定时任务:容器默认 UTC,你按北京时间配了「每天凌晨 2 点」,实际会在上午 10 点触发。这种 bug 不报错、不崩溃,只会让数仓数据莫名其妙晚 8 小时——比连不上数据库难查多了。
配好后进容器 date 一下确认:显示 CST 才算生效。
启动:
docker compose up -d
⚠️ 踩坑提醒:
数据源 URL 中的地址,千万不能填 127.0.0.1。在容器内部,127.0.0.1 指的是容器自己,不是宿主机。正确做法:
| 方案 | 写法 | 说明 |
|---|---|---|
| 使用宿主机 IP | jdbc:mysql://192.168.1.100:13306/ds_scheduler |
最通用,Linux/Mac 都行 |
| Docker 特殊域名 | jdbc:mysql://host.docker.internal:13306/ds_scheduler |
Mac/Windows Docker Desktop 原生支持;Linux 需要在 docker-compose.yml 中添加 extra_hosts: ["host.docker.internal:host-gateway"] |
| 宿主机网络模式 | 放开 network_mode: "host",URL 直接写 127.0.0.1:13306 |
最省事,但必须把 ports 和 extra_hosts 两段一起注释掉——host 模式下容器与宿主机共用网络栈,端口映射不再生效,host.docker.internal 也不需要了 |
四、验证部署
启动后等待约 30 秒(容器要拉起内置 ZooKeeper 和各个服务),然后浏览器访问:
http://<你的服务器IP>:12345/dolphinscheduler/ui
使用默认账号登录:
| 用户名 | 密码 |
|---|---|
admin |
dolphinscheduler123 |
看到登录页面,说明服务已经起来了:

🔐 登录后第一件事:改密码! 默认密码就像没锁的门,别等被人进来了才后悔。
登录成功后看到首页仪表盘,就说明部署大功告成:

可以试着创建一个简单的 Shell 任务跑个 echo "Hello DolphinScheduler",验证任务调度是否正常。
五、别忘了监控!
单机部署最怕的不是「挂了」,而是「挂了没人知道」。
强烈建议配套部署 Prometheus + Grafana 监控方案,做到:
- 📈 实时掌握任务执行状态
- 🚨 异常时自动告警(飞书/钉钉/邮件都行)
- 📊 可视化大盘,随时查看调度平台健康状况
六、后期升级:无缝切换集群模式
可能有同学会担心:「先用单机模式,以后扛不住了怎么办?迁移成本大不大?」
放心,因为我们一开始就选择了 MySQL 而非默认的 H2,所有的工作流定义、任务配置、调度记录、租户信息等数据都持久化在 MySQL 中。后续升级到伪集群或集群模式时:
- 数据完全复用:新集群的 Master、Worker、API Server 只需指向同一个 MySQL 实例,即可读取到所有历史数据,工作流、定时任务无需重新配置
- ZooKeeper 换新无影响:单机模式内置的 ZooKeeper 只负责运行时协调(服务注册发现、Master/Worker 心跳、分布式锁),存的都是临时节点(ephemeral node),不存任何业务数据。切换到外部独立的 ZooKeeper 集群后,各服务启动时会自动重新注册,对工作流和历史数据零影响——相当于换了个新「会议室」,大家重新签个到就行
- 部署流程:停掉单机容器 → 部署独立 ZooKeeper 集群 → 按集群模式部署多个服务组件 → 连接同一个 MySQL + 新 ZooKeeper → 启动即可
- 零数据迁移:不需要导出导入,不需要跑迁移脚本,MySQL 里的表结构和数据是通用的
💡 一句话记住这个分工:MySQL 存的是「记忆」,ZooKeeper 存的是「状态」。换 ZooKeeper 只是重新握个手,记忆不会丢——这才是本文坚持用 MySQL 替换 H2 的深层原因:不只为数据安全,更为将来的架构升级留好退路。
七、总结
| 项目 | 说明 |
|---|---|
| 部署模式 | Docker 单机模式(Standalone) |
| 数据库 | MySQL 8.0 替换默认 H2 |
| 适用场景 | 测试环境、中小团队、任务量 < 2000/天 |
| 部署耗时 | 约 10 分钟(不含摸鱼时间) |
| 核心踩坑 1 | 容器内不能用 127.0.0.1 连宿主机 MySQL |
| 核心踩坑 2 | 换 MySQL 后不会自动建表,必须先跑官方初始化 SQL |
| 核心踩坑 3 | 不配 TZ,定时任务会按 UTC 触发、整整错开 8 小时 |
一句话:别过度设计。中小团队的离线调度,单机模式 + MySQL + 监控告警,就是性价比最高的方案。等真到了需要集群的那天,再升级也来得及。
📌 如果这篇文章帮你少踩了一个坑,欢迎点赞收藏。毕竟,程序员最大的善良,就是把踩过的坑写成文档。
浙公网安备 33010602011771号