拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

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

Ubuntu 上 DataSophon 集成 DolphinScheduler 的安装问题全解析

Ubuntu 上 DataSophon 集成 DolphinScheduler 的安装问题全解析

如果你也是把 DataSophon 1.2.1 跑在 Ubuntu 上做二开的人,大概率经历过这个场景:服务列表里明明加了 DolphinScheduler,前端点“安装”之后,进度条转了几圈,所有角色状态开始飘红,点开详情日志,里面只有两三行“开始执行安装”,然后什么都没了。再刷新一次,状态直接回到未安装。整个过程看起来像“没装上”,但你又说不清楚到底是哪一步挂了。

这篇是二开系列里的第七篇,前几篇翻过注册中心、改过组件元数据,这一篇集中把 DolphinScheduler 在 DataSophon 1.2.1 里的安装问题聊透。我不会只贴一个“能跑的结果”,而是把从 UI 现象到元数据注册、从 Ubuntu 的 shell 差异到数据库初始化、再到启动脚本生命周期对接的完整排查链路都过一遍。适合正在用 DataSophon 做集群平台二开、或者准备把 DolphinScheduler 纳入平台管理然后被安装问题卡住的同学参考。

1. 安装失败的现象:不是服务起不来,而是压根没进入安装流程

1.1 先分清三种“安装失败”

很多人一看到“安装失败”就直奔 DolphinScheduler 的启动日志,这是最大的误区。在 DataSophon 里,一个服务从点击安装到最终跑起来,要经过三个阶段,失败发生在不同阶段,排查入口完全不同。

第一阶段是配置校验。前端提交安装请求时,DataSophon Manager 会校验服务实例参数、节点选择、服务角色定义是否完整。这里挂了,通常 UI 直接弹窗报错,日志在 manager 侧。

第二阶段是安装脚本执行。Agent 收到指令后,按元数据里的 package_name 去下载安装包、解压、执行脚本。这里挂了,大部分情况在页面日志里只能看到“开始安装”,然后没有然后。如果你习惯先看服务日志,这个阶段基本是盲区。

第三阶段才是服务启动与存活检查。安装包就位,control.sh 执行 start,Agent 定期执行 status 检查进程和端口。这里挂了,页面才可能看到“已启动后又变红”。

我在排查这个系列问题时,遇到的大部分“DolphinScheduler 安装失败”,其实连第一阶段都没完整走完,或者卡在第二阶段的中段,根本轮不到 DolphinScheduler 自己的日志出场。

1.2 我在 UI 上看到的表面现象:反复回滚,没有实质错误

把 DolphinScheduler 注册进 DataSophon 1.2.1 之后,第一次点“安装”,UI 显示任务正常下发。大约两分钟后,Master 节点状态变成红色。点开日志,内容大概是“download package start”、“download package succeed”、“start install”,然后中断。再刷新,服务实例直接消失或者变回未安装状态。

这种“回滚式失败”特别有迷惑性。它像是安装脚本本身出错了,但实际原因很可能是:Agent 下载安装包时用的软件源地址不可达,或者包名跟元数据对不上。DataSophon 1.2.1 的处理逻辑就是:下载失败就走失败回滚,UI 不展示底层 wget/curl 的报错,只展示业务层那几个步骤。

所以我在做二开的时候,遇到这种“没头没尾”的失败,第一反应不是去看服务日志,而是先确认安装包到底有没有落到 Agent 节点上。检查路径通常是:

ls -lh /opt/datasophon/DDP/ ls -lh /opt/datasophon/DDP/dolphinscheduler

如果目录是空的,或者只有一个没解压完的临时文件,基本可以断定是下载源或包名的问题,跟 DolphinScheduler 本身没有任何关系。

1.3 快速定位当前卡在哪一层的检查路径

我给自己总结了一套固定的排查顺序,遇到安装问题直接按这个走,能省掉大量无效时间:

  • 查安装包是否已下载并解压到预期目录。
  • 查 Agent 日志里有没有执行 control.sh 的记录。
  • 手动在 Agent 节点上执行control.sh status,看返回码和输出。
  • 手动执行control.sh start,前台跑一次,看是否报错。
  • 最后才去看 DolphinScheduler 自己的 logs 目录和系统进程。

一套走下来,绝大多数问题都能定位到具体环节。下面几个章节,就是我在走这套流程时踩过的几个具体坑。

2. 元数据注册的前置修复:DML 里的小细节决定成败

2.1 DataSophon 怎么知道“服务是谁、怎么装”

二开的人最容易忽略一个点:DataSophon 里的服务定义不是只存在于安装目录里,而是由后端元数据和前端展示共同维护的。以 1.2.1 为例,Manager 后端启动时会加载t_ddh_service_*系列元数据表,里面记录了服务名称、版本、安装包名、服务角色、配置参数模板。前端服务列表的展示和安装向导,也是基于这份数据渲染出来的。

当你手动往系统里塞一个新服务,比如 DolphinScheduler,只改前端页面的菜单是没有用的。安装任务下发到 Agent 时,Agent 只认元数据里写好的 package_name 和执行脚本路径。两边一旦不一致,就会出现前面说的那种“看似开始安装,实则根本没跑”的情况。

这一点在二开场景里尤其明显。从其他发行版拷贝过来的 DML 脚本,常常带着对方环境里的包名、版本号、路径,直接搬到 Ubuntu 节点上,几乎必然对不上。

2.2 最常见的元数据坑:安装包名与解压目录强绑定

DataSophon 在安装阶段的大致行为是:拿到服务实例的 package_name,去软件源下载对应文件,解压到固定目录,然后执行目录里的启动控制脚本。这里的一个隐性约束是:包名、解压后的目录名、control.sh 路径,这三者必须和元数据里配置的完全一致。

我实际遇到的情况是,从某个离线仓库拷贝 DolphinScheduler 安装包时,文件名带了-ubuntu后缀。元数据里写的是dolphinscheduler.tar.gz,Agent 下载时拿这个文件名去源站找,返回 404。表面上报的是“安装包下载失败”,但页面日志只显示“开始安装”就没有后续了。

排查方法很简单:去 Agent 日志里搜 package_name 或者 download 关键字。

grep -i "download" /var/log/datasophon/agent/*.log

看到实际请求的 URL,立刻就能发现是包名不一致,还是源地址失效。

2.3 修改元数据的正确姿势

这里我强烈建议优先用 DataSophon 自己的服务管理功能去调整,而不是直接改数据库。原因有两个:一是直接 UPDATE 元数据表很容易漏掉关联表,比如服务角色定义、配置模板、告警规则这些分散在不同表里;二是 Manager 有缓存,改完库不重启服务,前端还拿旧数据渲染,容易造成“改了个寂寞”的错觉。

如果确实需要手工调整,我建议的操作顺序是:

  • 备份相关元数据表。
  • 在服务管理页面里找到 DolphinScheduler 服务定义,核对版本号、包名、服务角色列表。
  • 保存后重启datasophon-manager服务,强制刷新缓存。
  • 在 Agent 节点手动rm -rf残留的安装目录,避免旧包干扰。
  • 重新发起安装,观察是否进入真正的解压和脚本执行阶段。

很多安装问题,根源就是元数据里的包名和实际安装包差了那么几个字符。修完这个,后面 DolphinScheduler 的真实启动问题才暴露出来。

3. Ubuntu 环境下的脚本兼容性:dash 与 bash 的差异是第一个坑

3.1 为什么 Ubuntu 上的启动脚本更容易翻车

把 DolphinScheduler 装到 CentOS 上一般没什么噪音,但换到 Ubuntu,第一个拦路虎不是 Java,也不是数据库,而是 Ubuntu 的/bin/sh默认指向dash,不是bash。

DolphinScheduler 自带的脚本里,大量使用了 bash 特有语法,包括但不限于[[ ]]判断、数组、source关键字、function定义。这些语法在 bash 下没问题,一旦被 dash 解析,直接报语法错误。特别是那些没有显式写#!/usr/bin/env bash、反而用sh xxx.sh方式调用的脚本,最容易踩中。

DataSophon 的 Agent 在执行控制脚本时,很多时候是走/bin/sh -c方式调用的。这意味着即便你的 control.sh 首行写了#!/bin/bash,如果内部再调用sh start-all.sh,那个子进程还是会用 dash 跑。

我在最初排查时,看到一个报错是Syntax error: "(" unexpected,这几乎是标准 dash 不认数组语法才会出现的提示。当时第一反应是脚本被改坏了,后来才发现是 shell 解释器的问题。

3.2 把默认 shell 切回 bash,一劳永逸

最省事的解决方式是把 Ubuntu 的默认/bin/sh切回 bash。执行:

sudo dpkg-reconfigure dash

弹窗里选“No”,也就是不把/bin/sh链接到 dash。从此系统级脚本只要写sh就会走 bash。这个操作在 Ubuntu Server 18.04、20.04、22.04 上都适用,且对系统本身没什么副作用。唯一需要注意的是,某些依赖 POSIX shell 行为的精简脚本理论上可能受影响,但我在实际二开过程中没有碰到。

如果不想全局改,也可以直接在 DolphinScheduler 安装目录下,把所有.sh脚本的首行确认一遍,确保是#!/usr/bin/env bash,并且内部调用子脚本时显式写成bash xxx.sh。这个工作量略大,但对于只需要管理单个服务场景来说,完全可控。

3.3 另一个 Ubuntu 专属坑:JAVA_HOME 没进 Agent 环境

这个问题比 shell 差异还隐蔽。DataSophon 的 Agent 通过 SSH 远程执行命令时,默认是 non-interactive non-login shell。此类 shell 不会读取~/.bashrc,也不会读取~/.bash_profile。很多同学在 Ubuntu 上配置 JAVA_HOME 时习惯写在用户家目录的.bashrc里,手动登录没问题,Agent 远程执行时却拿不到。

结果是:control.sh 启动 DolphinScheduler 时,脚本里$JAVA_HOME为空,Java 进程根本没起来,但安装步骤显示已经成功执行。页面状态全红,实际原因是环境变量缺失。

解决方案是把 JAVA_HOME 写到全局环境文件里,比如/etc/environment,或者直接写进 DolphinScheduler 自带的conf/dolphinscheduler_env.sh。后一种方式在二开场景里更推荐,因为不会影响系统其他用户,也不会因为改了全局环境导致别的服务行为变化。

export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64 export PATH=$JAVA_HOME/bin:$PATH

Ubuntu 上 OpenJDK 8 的默认安装路径通常是/usr/lib/jvm/java-8-openjdk-amd64,确认一下再写,别照抄。

4. 数据库初始化与 JDBC 驱动的隐性依赖

4.1 “安装了却起不来”和数据库有什么关系

DolphinScheduler 的 Master、Worker、API、Alert 四个角色,启动后都要连元数据库。API 服务还要额外连 ZooKeeper。如果数据库初始化有问题,最典型的表现是:安装步骤全部成功,进程也起来了,但几秒后进程主动退出,状态从“已启动”迅速变回“已停止”。

我之前在一个 Ubuntu 节点上遇到的就是这种。手动执行control.sh start,进程能起来,但 ps 观察 20 秒左右,Java 进程消失。打开logs/dolphinscheduler-api-server.log,看到的是数据库连接超时。这个阶段已经不再是安装问题,而是“初始化脚本和驱动”的问题。

4.2 初始化脚本失败的三个常见原因

DolphinScheduler 安装包内通常提供了数据库初始化脚本。不同大版本的脚本位置不同,1.x 系列一般在script/create-dolphinscheduler.sh,3.x 系列一般在tools/bin下找upgrade-schema.sh或类似入口。这些脚本本质上都是读取同一目录下的建表语句,然后按参数连接 MySQL 执行。

我实际遇到的初始化失败原因,基本就三类。

第一类是连接数据库失败。Ubuntu 上如果 MySQL 只监听了本地 socket 而没有监听 3306 端口,脚本用 IP 连接就会超时。检查方式:

netstat -lnp | grep 3306 mysql -h127.0.0.1 -uroot -p -e "select 1"

第二类是缺少 JDBC 驱动。初始化脚本要连 MySQL,必须依赖mysql-connector-java的 jar 包。很多精简过的 DolphinScheduler 安装包里没有自带这个驱动,或者版本和 MySQL 服务端不匹配。报错往往是ClassNotFoundException或者Communications link failure。

第三类是字符集和时区参数问题。MySQL 8.0 默认字符集是 utf8mb4,但如果初始化脚本里连接串写的是characterEncoding=utf8,并且库里已经有以 utf8mb3 创建的旧表,某些字段比如任务定义名,长度换算后可能超限,直接报 “Data too long for column”。时区问题更常见,Ubuntu 服务器如果初始化为 UTC 时区,连接串又没写serverTimezone,连接池初始化时就会抛异常。

4.3 在 Ubuntu 下把初始化跑通的方案

我的做法是绕开 DataSophon 的自动初始化,先手动把数据库和账号准备好,再让服务启动时直接用。具体步骤如下。

先建库建用户:

mysql -uroot -p -e "CREATE DATABASE IF NOT EXISTS dolphinscheduler DEFAULT CHARACTER SET utf8mb4;" mysql -uroot -p -e "CREATE USER IF NOT EXISTS 'dolphinscheduler'@'%' IDENTIFIED BY 'ds_passwd';" mysql -uroot -p -e "GRANT ALL PRIVILEGES ON dolphinscheduler.* TO 'dolphinscheduler'@'%';"

然后确认 JDBC 驱动 jar 是否存在于安装包的 lib 目录里。如果没有,从 Maven 仓库下载mysql-connector-java-8.0.31.jar,放到对应目录。这一步别偷懒,很多初始化问题的根因就是驱动版本太老,不支持 MySQL 8 的默认认证插件。

接着执行初始化脚本。以 3.x 版本为例,命令大致是这样:

bash tools/bin/upgrade-schema.sh \ --username "dolphinscheduler" \ --password "ds_passwd" \ --host "127.0.0.1" \ --port "3306" \ --database "dolphinscheduler"

如果安装包里没有这个脚本,去script或bin目录找名字里带create或schema的脚本,逻辑都一样。脚本执行完成后,验证表数量:

mysql -h127.0.0.1 -udolphinscheduler -pds_passwd \ -e "select count(*) from information_schema.tables where table_schema='dolphinscheduler';"

正常会有几十张表,具体数量跟版本有关。如果一张表都没建出来,说明初始化脚本根本没有真正执行,回到上一步查驱动和连接串。

4.4 连接串参数的一处细节

如果 DolphinScheduler 的数据库连接配置允许手动修改,我建议把application.yaml或common.properties里的 JDBC URL 写成这样:

jdbc:mysql://127.0.0.1:3306/dolphinscheduler?useUnicode=true&characterEncoding=utf8mb4&serverTimezone=Asia/Shanghai&useSSL=false&allowPublicKeyRetrieval=true

allowPublicKeyRetrieval=true不是所有场景都需要,但 Ubuntu 上默认开 MySQL 8 的 caching_sha2_password 认证时,有时候连接工具第一次请求公钥会被拒绝,加上这个参数能省掉很多莫名奇妙的连接失败。

5. 启动脚本改造与 DataSophon 生命周期方法的对接

5.1 DataSophon 对服务生命周期脚本的约束

DataSophon 管理服务的机制很简单:Agent 节点围绕一个control.sh做文章。这个脚本至少要实现 start、stop、status、restart 四个动作,并且通过退出码告诉 Agent 当前状态。status 返回 0 表示服务正常,非 0 表示异常或未知。

DolphinScheduler 原生提供的是bin/start-all.sh和bin/stop-all.sh,这两个脚本的问题在于:命令执行完就返回了,不表示服务真的起来了,也不报告精确的返回码。DataSophon 拿到这种脚本直接用,会出现一个经典现象:服务列表显示“启动成功”,几十秒后变成“失败”,因为 Agent 后续执行 status 时发现进程并不存在。

所以二开 DolphinScheduler 集成到 DataSophon,必须写一层自己的控制脚本,把原生脚本包起来,做进程检查和状态翻译。

5.2 一份可用的 control.sh 要点

我没有把实际脚本全文贴出来,因为不同 DolphinScheduler 版本的目录和进程名有差异,贴出来反而容易误导。但关键逻辑是固定的,你照着这几个要点写,基本不会出错。

start 动作:调用原生 start-all.sh 之后,不要立刻退出。循环检查 DolphinScheduler 各角色的主进程是否存在,比如 MasterServer、WorkerServer、ApiApplicationServer、AlertServer。用 ps 加 grep 的时候,记得把 grep 自身排除掉,否则永远“检测到进程”,这就是个典型的自欺欺人写法。

stop 动作:调用原生 stop-all.sh 之后,轮询进程数,确认全部退出再返回。如果等不到进程退出,再考虑 kill。

status 动作:直接检查进程数。全部存在返回 0;部分存在返回 2;一个都没有返回 1。注意 Agent 对返回码的解释在不同版本里有点差异,1.2.1 里遇到非 0 就标记为状态异常,所以返回值别乱写。

restart 动作:先 stop 后 start,中间做一次短暂 sleep,避免端口 TIME_WAIT 导致起不来。

5.3 我踩过的“状态回写”坑

有一个坑特别值得说。我第一次写完 control.sh,手工在节点上执行 status,返回 0,输出也正常。但在 DataSophon 页面上,服务状态一直显示“正在启动”,最后变红。后来才发现,status 脚本里我用了一个grep去匹配进程名,结果 Agent 调用脚本时的子进程自身也带着相同的命令行参数,被 grep 匹配进去了,导致永远检测到“进程存活”。

解决办法是在 grep 时排除自身:

ps -ef | grep "MasterServer" | grep -v grep | wc -l

这行看起来很基础,但很多人写脚本时顺手就漏了。还有一个更隐蔽的问题:Agent 有时会在 status 脚本执行时把当前 shell 的进程名覆盖成脚本名,单纯 grep 脚本名也会误判,所以匹配进程时尽量用 Java 类名,别用脚本文件名。

5.4 环境变量:手工执行和 Agent 执行结果不一致的根源

如果你的 control.sh 在终端手工执行一切正常,但从 DataSophon 页面触发后状态异常,几乎可以断定是环境变量差异。

我在第 3 章提过,Agent 的 SSH 会话是非交互式 shell,不读用户家目录的配置文件。手工执行时你当然带着完整的环境变量,Agent 执行时却是“干净环境”。所以二开 DolphinScheduler 的 control.sh 时,我强烈建议在脚本开头显式 export 关键环境变量,包括 JAVA_HOME、DOLPHIN_SCHEDULER_HOME、PATH 等。不要依赖系统 profile 帮你加载。

这一步做完,很多“UI 操作失败、手工操作能过”的诡异现象会一次性消失。

6. 从日志反推的排查链路:一步步找到真正的启动障碍

6.1 别急着看 UI,日志优先级有讲究

遇到安装或启动失败,我建议按下面的优先级排查,而不是盯着 DataSophon 的 UI 日志看个不停。UI 日志是经过采集和缓冲的,延迟十几秒到几十秒都很正常,而且经常只展示业务层结果,不展示底层细节。

我的优先级顺序是:

  • 直接登录 Agent 节点,执行ps -ef | grep java,看进程是否存在。
  • 执行netstat -lnp | grep <服务端口>,看端口是否监听。
  • 看 DolphinScheduler 自己的logs/*.log文件,找异常栈。
  • 看 DataSophon Agent 日志里关于该服务的执行记录。
  • 最后才回 UI 看展示层结果。

顺序打乱很容易浪费时间。比如进程本身根本没起来,你却在 UI 日志里找端口冲突,找了半天压根没有这方面的记录。

6.2 一个典型的 api-server 启动失败案例

分享一个真实案例。当时 DolphinScheduler 安装流程已经跑通,Master 和 Worker 也正常,唯独 API 服务状态是红的。ps 能看到 ApiApplicationServer 进程存在,但用 netstat 查端口,始终查不到监听。

打开logs/dolphinscheduler-api-server.log,发现报错信息指向 HikariPool 初始化超时。连接池连不上数据库,API 进程起不来,但进程本身没有立即退出,所以 ps 还能看到。

进一步排查数据库连接配置,发现application.yaml里连接串缺少serverTimezone参数,而 Ubuntu 服务器的系统时区是 UTC。MySQL 驱动在这个参数缺失时,会有兼容性检测,导致连接池建立连接失败。补上serverTimezone=Asia/Shanghai之后,API 服务正常起来,页面状态马上变绿。

这个案例给我的启发很大:进程在、端口不在,先考虑外部依赖,不要急着改代码。DolphinScheduler 的启动依赖数据库和 ZooKeeper,这两个链路任何一个不通,服务都起不来,而很多服务卡在“进程存在但功能不可用”的状态,恰恰是初始化连接阶段的问题。

6.3 把“手动能跑通”变成“UI 也能跑通”的最后一公里

我在二开过程中总结出一条经验:如果 control.sh 在节点上手动能跑通,但 UI 触发后失败,问题基本出在 Agent 执行环境而非 DolphinScheduler 本身。

这时候去做两件事。第一,检查 Agent 进程的运行用户。如果 Agent 是以普通用户跑的,而安装目录的属主是 root,那脚本执行时没有写权限,解压和写日志都会失败。Ubuntu 上很多人图省事直接用 root 登录安装,Agent 却默认以普通用户注册,最容易出现这种权限错位。

第二,检查/etc/environment里是否真的包含 JAVA_HOME 和 PATH。DataSophon 1.2.1 的 Agent 以及其他一些子进程,在非交互式执行脚本时会读取/etc/environment,但不会读取/etc/profile.d下的脚本。这一步配置对了,90% 的环境变量类问题都能解决。

最后说一点个人体会。在 Ubuntu 上做 DataSophon 二开,最容易翻车的地方永远不是组件本身,而是环境差异。CentOS 上验证过一百遍的流程,换到 Ubuntu 上可能第一步就挂。我甚至在排查一个 DolphinScheduler 安装问题时,折腾半天发现自己改错了 MySQL 的 bind-address,跟 DataSophon 一点关系都没有。所以如果你也遇到类似问题,别急着怀疑代码逻辑,先按文中的顺序,从元数据校验、shell 兼容性、数据库连接、启动脚本生命周期这条链路,逐层走一遍。大部分“安装失败”,其实离成功就差一个环境变量或一个脚本区别。

返回列表