ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

DolphinScheduler 3.1.9本地环境搭建与Minio接入实践

DolphinScheduler 3.1.9本地环境搭建与Minio接入实践 最近在搞 DolphinScheduler 3.1.9 的二次开发必须把整套调度环境在 IDEA 里跑起来同时还要求资源存储走 Minio。我本以为这是件半小时搞定的小事结果硬生生折腾了一周多Maven 依赖下载、数据库初始化、注册中心选型、Minio 的 S3 兼容问题每一步都有意想不到的坑。网上的教程要么是 standalone 模式跑一把要么直接上生产集群很少有人讲如何在 IDEA 里逐个启动核心服务并接上 Minio 做资源中心这件事。这篇文章完完整整记录我的搭建过程包括版本组合、配置修改、IDEA 启动步骤、Minio 接入参数以及我在这个过程中碰到的一堆问题是怎么定位和解决的。如果你正准备对 DolphinScheduler 做二次开发或者想把资源存储切到 Minio这篇内容应该能帮你省掉不少时间。话不多说直接进入正题。1. 为什么非要在 IDEA 里本地跑一套 DolphinScheduler1.1 先看懂这个调度系统跑起来需要哪几个进程DolphinScheduler 3.1.9 已经不是当年单机版那种一个脚本启动全部的结构了。源码拆得非常细核心服务至少包含三个ApiServer、MasterServer、WorkerServer。ApiServer 负责接收前端页面和对外 API 的请求MasterServer 负责任务调度、工作流 DAG 解析、状态机流转WorkerServer 才是真正干活的它去执行任务节点的命令比如跑 Shell、SQL、Python 脚本等。一个最简单的流程是这样的你在 UI 上创建工作流前端把请求打到 ApiServerApiServer 把工作流定义和调度信息写入数据库MasterServer 从数据库里捞到需要调度的实例按 DAG 关系分发到 WorkerServerWorkerServer 再去执行具体任务。如果任务里引用了资源文件——比如你上传了一个测试脚本到资源中心——那 WorkerServer 还得先把资源文件从存储层拉下来放到本地工作目录然后才执行。所以要本地调试这三个服务一个都不能少。只跑一个 ApiServer 或者只跑一个 WorkerServer都会出现日志正常但功能就是不对的诡异情况。这也是我一开始犯的错误我想着先启动 ApiServer 看看登录页结果工作流提交之后一直卡在调度队列里怎么查都查不出问题——因为压根没有 MasterServer 和 WorkerServer 在跑。1.2 本地开发和伪集群、standalone 模式到底差在哪官方提供了一个 standalone-server 模块一条命令就能把三个服务全部拉起来端口和注册中心也都是默认好的很适合快速验证功能。但如果你要改代码比如改 MasterServer 的调度逻辑或者调 ApiServer 的接口鉴权用 standalone 模式就很痛苦。你改一处代码要么重新构建整个 standalone 包要么就得在 IDEA 里想办法对 standalone-server 这个组合模块做热调试鬼知道哪儿改动了会触发什么全量重编译。在 IDEA 里分开启动三个服务就舒服多了。每个服务是一个独立模块可以单独设置 VM 参数、单独跑断点、单独重启。改完 WorkerServer 的代码只需要重启 WorkerServer 进程其他两个服务完全不用动。对于开发调试来说这个体验是 standalone 模式比不了的。同时本地跑和真实集群也更接近。你可以在本机把 ZooKeeper、Minio、MySQL 全部用 Docker 拉起来然后三个服务进程在 IDEA 里连接这些基础组件和线上架构几乎一致。以后从本地环境迁移到生产环境需要改的只是 IP 和账号密码架构层面不存在任何惊讶。2. 版本选型与前置环境准备少走一个月弯路2.1 我最终采用的版本组合DolphinScheduler 是个对版本很敏感的项目不同小版本之间的配置项、启动类、默认端口都有可能变化。我把最终跑通的组合放在下面你照着这个来基本不会踩兼容性问题。组件版本说明DolphinScheduler3.1.9源码从 GitHub 拉取切换 release-3.1.9 分支JDK1.8.0_202官方对 3.1.x 最友好的 JDK 版本高版本编译会有不可控问题Maven3.6.33.9.x 我试过也能用但日志里会有插件告警MySQL8.0.27本地 Docker 启动字符集 utf8mb4MinioRELEASE.2023-04-13T21-18-28Z这个版本比较稳太新的版本偶尔会和 S3 SDK 有兼容差异ZooKeeper3.7.1如果不想装 ZK 可以用 Hazelcast 注册中心下文细说IntelliJ IDEA2023.2社区版就够不依赖旗舰版特性Node.js16.20.0只有启动 dolphinscheduler-ui 开发环境时需要特别提醒一点JDK 版本千万别用 17。DolphinScheduler 3.1.x 的代码用到了大量 JDK 8 的 API 和一些反射魔术在 JDK 17 下运行会出现各种安全权限异常排查起来非常头疼。我一开始图省事直接用本机的 JDK 17ApiServer 启动到一半就报InaccessibleObjectException最后老老实实装回 JDK 8 才消停。2.2 Maven 和 IDEA 的基础配置DolphinScheduler 源码模块非常多第一次拉下来构建时依赖下载量很大。建议先把 Maven 的settings.xml配置好阿里云镜像不然光下载依赖就够你等一上午。Maven 配置主要改两处mirror和jdk编译级别。我把关键片段贴一下mirror idaliyunmaven/id mirrorOfcentral/mirrorOf name阿里云公共仓库/name urlhttps://maven.aliyun.com/repository/public/url /mirror然后确认profiles里有 JDK 8 的内容避免 IDEA 构建时用系统默认 JDK 对代码做编译profile idjdk-8/id activation activeByDefaulttrue/activeByDefault jdk1.8/jdk /activation properties maven.compiler.source1.8/maven.compiler.source maven.compiler.target1.8/maven.compiler.target /properties /profileIDEA 打开源码项目后记得在 Settings 里把 Maven 的 JDK 和 Runner 的 JDK 都指到本地 JDK 8。有一个很隐蔽的坑IDE Settings 里如果只改了 Project SDK没有改 Maven Runner JRE编译时还是会用 IDEA 默认的 JBR导致代码编译报错。这个坑我替你们踩过了改完之后所有模块编译一次通过。数据库初始化这一步很多人会忽略。直接用 Navicat 创建一个名为dolphinscheduler的库字符集选 utf8mb4然后导入源码根目录sql/dolphinscheduler_mysql.sql脚本。执行完之后你会看到几十张表核心的表包括t_ds_user、t_ds_project、t_ds_process_definition等。这里有一个必须注意的点如果你用的是 MySQL 8.0连接参数里一定要带上serverTimezoneAsia/Shanghai和allowPublicKeyRetrievaltrue。前者不带上DolphinScheduler 查询时间字段时直接报时区异常后者不带上首次连接会报Public Key Retrieval is not allowed。这两兄弟在本地开发环境几乎是必现的遇到别慌改 JDBC URL 就好。3. 源码里必须修改的配置文件3.1 全局配置 common.properties改一次影响所有服务DolphinScheduler 3.1.9 的核心全局配置基本都收敛在dolphinscheduler-common/src/main/resources/common.properties这个文件里。资源存储类型、注册中心类型、ZooKeeper 地址、Minio 的 endpoint 全在这一个文件内。我用本地开发模式注册中心选的是 Hazelcast所以配置这样改registry.typehazelcast如果你更习惯用 ZooKeeper也可以改成registry.typezookeeper registry.zookeeper.connect.string127.0.0.1:2181两种方式我都跑通过。ZooKeeper 更接近生产环境但需要本机多跑一个容器Hazelcast 是零依赖三个服务进程启动后自动组成集群开发调试非常方便。我建议个人电脑上用 Hazelcast公司统一环境里如果要求贴近生产再用 ZK。这个文件里还有一个很关键的点resource.storage.type。默认值是HDFS如果你没改就直接启动ApiServer 启动过程中会尝试加载 HDFS 客户端配置虽然不一定会崩但日志里会有一堆无关紧要的 HDFS 告警。本地开发用 Minio 的话这个值要设为S3。为什么是 S3 而不是 Minio 专属选项因为 Minio 协议兼容 AWS S3DolphinScheduler 的代码里把 Minio 当作一个 S3 端点来对接这是一切配置的基础逻辑。3.2 三个服务模块的 application.yaml 各管一段除了 common.properties每个服务模块还有自己的application.yaml。ApiServer、MasterServer、WorkerServer 各自连接同一个数据库但端口和上下文路径完全不同。以 ApiServer 为例dolphinscheduler-api/src/main/resources/application.yaml中的关键配置server: port: 12345 spring: datasource: url: jdbc:mysql://127.0.0.1:3306/dolphinscheduler?useUnicodetruecharacterEncodingUTF-8serverTimezoneAsia/ShanghaiuseSSLfalseallowPublicKeyRetrievaltrue username: root password: root driver-class-name: com.mysql.cj.jdbc.DriverMasterServer 和 WorkerServer 的 application.yaml 结构类似但端口不要搞混。我习惯在三个模块里全部统一用同一个数据库账号本地开发不区分权限效率优先生产环境再按最小权限原则拆开。有一点必须强调DolphinScheduler 3.1.9 里 application.yaml 的spring.datasource配置只是 Spring 层面的连接DolphinScheduler 自己的 DAO 层配置有一部分还会读取common.properties里指定的数据库信息。如果你改了 application.yaml 但发现某些服务还是走旧库检查一下是不是还有一份单独的datasource.properties遗留文件。这个问题在从旧版本升级源码时特别容易出现。3.3 注册中心切换后服务之间怎么互相发现很多第一次接触 DolphinScheduler 的人会有一个疑问三个服务之间到底是怎么找到对方的在 3.1.x 里答案就是注册中心。服务启动后都会把自己注册到注册中心MasterServer 从注册中心发现 WorkerServer 的地址列表然后才能把任务分发过去。如果你用的是 ZooKeeper那服务启动后会创建一层一层的 znode 节点路径结构类似/dolphinscheduler/nodes/master和/dolphinscheduler/nodes/worker。如果你用的是 Hazelcast情况更简单服务间直接内存组网不需要额外的中间件。我强烈建议本地开发用 Hazelcast原因很简单少维护一个基础组件。你不需要知道 Hazelcast 的集群原理只需要知道它让三个本地进程自己组网就够了。切到 Hazelcast 之后启动顺序无所谓任意服务先启动都能在短时间内和其他服务完成心跳握手。4. 在 IDEA 里把三个服务跑起来4.1 先安装基础模块否则运行报 NoClassDefFoundErrorDolphinScheduler 源码是个多模块 Maven 项目ApiServer、MasterServer、WorkerServer 都依赖dolphinscheduler-common、dolphinscheduler-dao、dolphinscheduler-service这些基础模块。直接从 IDEA 里运行 ApiServer 的启动类框架会去加载依赖模块的 class 文件但如果你之前没把这些模块安装到本地 Maven 仓库运行时会报NoClassDefFoundError非常莫名其妙。解决办法是在项目根目录先执行一次安装命令mvn clean install -DskipTests -Dcheckstyle.skiptrue -Dspotless.check.skiptruecheckstyle.skip和spotless.check.skip这两个参数非常关键不加上它们代码风格检查会在安装阶段疯狂报格式错误。DolphinScheduler 的代码风格很严格注释少一行都可能构建失败开发环境完全没必要被这种检查卡住。等基础模块安装完你可以在 IDEA 的 Maven 面板里双击dolphinscheduler-api模块下的dolphinscheduler-api应用也可以直接在源码里找到启动类运行。三个服务对应的启动类如下服务启动类ApiServerorg.apache.dolphinscheduler.api.ApiApplicationServerMasterServerorg.apache.dolphinscheduler.server.master.MasterServerWorkerServerorg.apache.dolphinscheduler.server.worker.WorkerServer4.2 启动参数和工作目录的配置细节直接右键启动往往是不够的因为 DolphinScheduler 的日志路径、配置文件加载路径和工作目录强相关。我的习惯是把每个服务的 IDE Run Configuration 都单独配置好。以 WorkerServer 为例我在 IDEA 里设置的参数是这样的Main class:org.apache.dolphinscheduler.server.worker.WorkerServerWorking directory:$MODULE_WORKING_DIR$Use classpath of module:dolphinscheduler-workerVM options:-Dlogging.configclasspath:logback-worker.xml -Ddolphinscheduler.log.base/tmp/dolphinscheduler-log -Ddolphinscheduler.home/tmp/dolphinscheduler-homelogging.config指向 worker 模块自己的 logback 文件dolphinscheduler.log.base是日志落地目录dolphinscheduler.home是运行时临时文件目录。这三个参数不配好启动时大概率会报找不到日志路径目录的错或者日志全部写到当前 IDE 工作目录里过一阵子简历一样到处是日志文件。ApiServer 和 MasterServer 配置方式一模一样只是换成各自的 logback 文件和 home 目录即可。4.3 启动顺序与验证方法启动顺序上官方建议是先 ApiServer、再 MasterServer、再 WorkerServer。但如果你用了 Hazelcast 注册中心其实顺序没有那么重要任意先启动一个其他两个稍后加入都会被注册中心感知到。每个服务启动后会有大量日志如何快速确认状态我总结了三个关键验证点ApiServer 启动完成日志里能看到ApiApplicationServer started successfully同时监听 12345 端口。MasterServer 启动完成日志里会出现类似MasterServer registry success的内容表示已经成功注册到注册中心。WorkerServer 启动完成日志里出现WorkerServer registry success和WorkerServer started successfully。三个服务都正常后浏览器访问http://localhost:12345/dolphinscheduler能看到一个 Swagger 页面说明 API 层面没问题。如果要看 UI进入dolphinscheduler-ui目录执行npm install npm run dev然后在浏览器访问 Vite 默认端口 5173UI 代理会自动把/dolphinscheduler开头的请求转发到 API 服务默认登录账号是admin密码是dolphinscheduler123。5. 把 Minio 接到 DolphinScheduler 资源存储5.1 为什么选 Minio 而不是其他存储本地开发环境里接云厂商的对象存储有几个实际问题一是需要公网访问权限二是账号密钥管理麻烦三是每次上传下载都走外网调试链路过长。Minio 能在本机用 Docker 起一个兼容 S3 协议的对象存储服务完全模拟线上 OSS 的行为非常适合作为开发环境的资源中心。DolphinScheduler 的资源中心、任务运行时的资源文件拉取、工作流上传的临时附件等都走这一套对象存储抽象。把存储类型配成 S3 再指向 Minio就相当于让 DolphinScheduler 把 Minio 当作一个私有化的 OSS 来用这正是最贴近生产环境的开发配置。5.2 common.properties 里 Minio 的完整配置在common.properties中把资源存储类型和 S3 相关配置写成这样resource.storage.typeS3 resource.upload.path/dolphinscheduler s3.endpointhttp://127.0.0.1:9000 s3.access.key.idminioadmin s3.secret.access.keyminioadmin s3.bucket.namedolphinscheduler s3.regionus-east-1 s3.path.style.accesstrue这里每一行的含义按照我实际踩坑理解来解释resource.storage.typeS3表示资源存储层使用 S3 协议。DolphinScheduler 内部没有专门的 Minio 存储类型Minio 和阿里云 OSS 等只要是 S3 兼容统一走这个入口。resource.upload.path/dolphinscheduler这个很关键它不是本地路径而是对象存储里的路径前缀。Minio 的桶叫dolphinscheduler文件上传后会存在桶下的/dolphinscheduler目录中。这个值如果配成空或根目录后续权限控制会很混乱。s3.endpoint是 Minio 的访问地址。注意Minio 默认有两个端口9000 是 API 端口9001 是控制台端口。这里必须填 9000我见过有人填成 9001 然后怎么都连不上原因就是把控制台端口当成 API 端口了。s3.access.key.id和s3.secret.access.key是 Minio 的账号密码。如果我没改过 Minio 的初始配置就是默认的minioadmin和minioadmin。s3.regionus-east-1是 S3 协议要求的区域参数Minio 不校验这个值但客户端 SDK 需要有一个合法的 region 才能创建。填us-east-1是最保险的默认值。s3.path.style.accesstrue是 Minio 能够正常工作的核心。AWS S3 默认使用虚拟主机风格访问也就是bucket.endpoint这种形式而 Minio 用的是路径风格也就是endpoint/bucket。很多教程里没提这个参数导致上传资源时报 301 永久重定向其实服务器协议之间的差异问题就体现在这里。5.3 本地 Minio 的初始化和建桶动作DolphinScheduler 不会自动创建 Minio 桶第一次把配置切到 S3 后如果没有提前建桶上传资源就会报The specified bucket does not exist。建桶这一步我直接用 Minio 客户端完成。先启动 Minio 服务可以用 Dockerdocker run -d --name minio \ -p 9000:9000 -p 9001:9001 \ -e MINIO_ROOT_USERminioadmin \ -e MINIO_ROOT_PASSWORDminioadmin \ -v /tmp/minio-data:/data \ minio/minio:RELEASE.2023-04-13T21-18-28Z \ server /data --console-address :9001然后下载 Minio 客户端 mc在终端里做配置和建桶mc alias set local http://127.0.0.1:9000 minioadmin minioadmin mc mb local/dolphinscheduler桶建好之后用浏览器打开http://127.0.0.1:9001使用minioadmin/minioadmin登录可以看到dolphinscheduler桶已经存在。从这一刻起DolphinScheduler 的资源中心就有了落脚点。5.4 完整验证链路上传资源到 Worker 执行配置完成后建议按这个路径做一次端到端验证确认整条链路真的通了而不是仅仅登录页面能看见 Minio 文件。第一步在 UI 的资源中心页面点击上传文件随便传一个测试脚本比如hello.sh。此时打开 Minio 控制台在dolphinscheduler桶下应能看见以/dolphinscheduler开头的目录结构。第二步创建一个 Shell 工作流节点内容写echo hello from dolphinscheduler resource这里如果只是为了验证资源拉取可以建一个文件资源比如test.txtShell 节点里用cat test.txt来读取。注意DolphinScheduler 的资源引用有它自己的语法你在 UI 里配置工作流时可以直接在资源下拉框里选择文件它会把资源映射成工作目录下的一个本地文件路径。第三步运行工作流等任务跑到 Worker 节点时查看 WorkerServer 日志和任务日志。正常情况下任务日志会显示资源文件成功下载到本地工作目录然后 Shell 命令执行成功。到这一步可以确认从 UI 到 ApiServer、MasterServer、WorkerServer、Minio 的整条链路已经全部打通。6. 我踩过的坑完整排错链路记录6.1 ApiServer 起不来数据库连接报错第一次启动 ApiServer等了几分钟后直接在日志里看到异常堆栈开头的关键行Caused by: java.sql.SQLException: The server time zone value й is unrecognized这个报错一看就是 JDBC 连接串的时区问题。MySQL 8.0 的驱动要求连接串里显式指定时区否则服务端的时区配置不合法就无法建立连接。解决办法非常简单在application.yaml里的 JDBC URL 中加上serverTimezoneAsia/Shanghai同时加useSSLfalse避免 SSL 握手阶段的额外报错。还有一个容易迷惑的变体如果 MySQL 8.0.27 以上版本连接时有时会出现Public Key Retrieval is not allowed。这个不是 DolphinScheduler 的问题是 MySQL 驱动默认不允许客户端通过 RSA 方式获取公钥解决方案是在连接串里追加allowPublicKeyRetrievaltrue。两个参数一起加一次解决。6.2 资源上传报错从日志到 Minio 逐层排查UI 资源中心上传文件时报错并且 ApiServer 日志里出现AmazonS3Exception: The specified bucket does not exist这个报错信息很直白桶不存在。排查路径如下首先确认 Minio 客户端能否访问这个桶。在终端执行mc ls local/dolphinscheduler如果这里就报Bucket does not exist问题定位在 Minio 侧执行mc mb local/dolphinscheduler建桶即可。如果 mc 命令能访问也就是桶确实存在但 DolphinScheduler 还是报桶不存在那就要看common.properties里的s3.endpoint是否可以被 ApiServer 所在主机访问。我当时犯过一个错误Minio 跑在 Docker 容器里endpoint 写的是容器 IP但 ApiServer 在宿主机 IDEA 里跑访问不到容器内部的 IP。改成http://127.0.0.1:9000就正常了。还有一层可能被忽视的原因S3 客户端访问 Minio 时如果返回 301绝大多数情况是 path style 没有开启。检查配置中是否有s3.path.style.accesstrue。如果没有这个配置项且你的版本里没有对应字段需要在源码中构造AmazonS3Client的位置加入.withPathStyleAccessEnabled(true)然后重新编译模块才能生效。6.3 Worker 执行任务时找不到资源文件这个问题发生在资源上传成功后、工作流运行时。具体现象是 WorkerServer 日志里显示任务启动但紧接着报资源文件不存在或者提示找不到某个本地路径。我先说根因DolphinScheduler 在执行任务前会把任务引用的资源文件从对象存储下载到 Worker 的本地工作目录然后再执行任务命令。如果下载失败通常不是 Minio 挂掉了而是资源在 Minio 里的实际路径和 DolphinScheduler 计算出来的路径不一致。核心排查点在于common.properties中的resource.upload.path。这个值会拼接到资源存储路径前面。比如你的桶叫dolphinscheduler上传的文件叫test.txt那么 Minio 里实际路径是dolphinscheduler桶下的/dolphinscheduler/资源文件目录/test.txt。如果你的resource.upload.path写的是/data/dolphinscheduler就会导致 Worker 下载时请求一个不存在的路径。遇到这类问题的排查顺序我建议这样来先在 Minio 控制台里确认文件真实存储路径。再对比 DolphinScheduler UI 里资源中心显示的路径前缀。最后检查common.properties的resource.upload.path和桶名称配置是否一致。如果这三处对不上改配置后重启 ApiServer 和 WorkerServer 即可。注意这个配置改动只重启 ApiServer 是不够的WorkerServer 执行任务时也会读取同样的配置必须一并重启。6.4 UI 登录后左侧菜单空白环境跑通后我遇到一个前端层面的问题登录进去能看到整体页面框架但左侧菜单一片空白控制台还有一堆网络请求报 404。排查下来发现是前端 Vite 代理转发的问题。DolphinScheduler UI 开发模式下默认把/dolphinscheduler前缀的请求转发到http://localhost:12345如果你后端 API 地址不是 12345或者你改了 API 服务的 context-path前端代理就对不上。解决办法是在dolphinscheduler-ui/.env.development里确认代理目标VITE_APP_DEV_WEB_URL http://localhost:12345同时检查 UI 根目录下的vite.config.ts里的 proxy 配置务必保证/dolphinscheduler代理到真实可用的 API 地址。这个文件在现版本里可能是.env.development也可能直接在 vite.config 里写死看具体拉取的代码为准。还有一个偏门原因如果你登录时用的账号是刚创建的新用户且没有分配任何权限登录后 UI 也会显示空菜单。这不是前端问题而是后端权限模型控制的结果。DolphinScheduler 里菜单的渲染依赖用户拥有的权限项管理员登录是完整的新建的普通用户则可能只有一个空的首页。开发环境下直接用 admin 账号最省心。另外如果 UI 能登录但始终提示当前用户无权限检查一下 MySQL 中t_ds_user表的用户状态和用户是否被关联到了正确的租户。3.1.x 版本里租户和用户的关系非常紧密没有正确设置租户很多页面操作会被拒绝资源中心上传功能也不例外。我当时创建了一个新用户测试结果资源中心一直报无权限后台日志里跟着一串租户信息为空的错误给这个用户绑定租户之后立刻恢复正常。整套环境跑通到现在我日常开发已经稳定使用了两个多月。平时改代码的重启流程很简洁改 Master 相关代码就重启 MasterServer改 Worker 相关代码就重启 WorkerServer前端直接热加载。唯一的经验之谈是改动common.properties和application.yaml这类公共配置时三个服务都必须一起重启否则会出现一个服务认为存储是 Minio另一个服务还认为存储是 HDFS这种诡异的半同步状态。另外如果你也在内网环境下开发Minio 最好固定一个非自动分配的 IPDocker 每次重启后容器 IP 会变你重新跑一遍 mc alias 和三处配置几分钟时间就搭进去了挺不划算的。
返回列表