资讯详情

资讯详情

K8s 离线部署 DolphinScheduler 与 SeaTunnel 全流程实战

做数据平台的同学应该都有过这种经历生产环境在一个完全隔离的网段里外部网络连不进去机器上连个镜像都拉不了一行docker pull都会卡半天直到超时。这时候如果还要在 k8s 上部署 DolphinScheduler 和 SeaTunnel 这套“调度数据集成”的组合很多标配操作就全都失效了Helm 在线仓库拉不下来、镜像仓库连不上、初始化脚本没网络跑不了每一步都像是戴着镣铐跳舞。我最近正好在某个客户的离线项目里把这一整套流程完整走了一遍从物料准备、镜像搬运、Helm 离线安装到 DolphinScheduler 接入 SeaTunnel、实际跑通一条数据同步任务前前后后踩了不少坑也沉淀了一些可以复用的经验。这篇文章就把整个离线的部署链路、关键配置和排查思路整理出来给后面要搞同样架构的同学留一份参考。适合正要接手离线集群、或者已经把 DS 装好但不知道怎么和 SeaTunnel 打通的人看。1. 离线部署的整体思路与架构取舍1.1 先理清 DolphinScheduler 和 SeaTunnel 各自承担什么角色很多人上来就装装完才发现这两个东西的关系没搞清楚后面配置全乱了。简单说DolphinScheduler 是总调度负责编排工作流、管理任务实例、展示 DAG、做告警SeaTunnel 是真正的数据搬运工负责把源端的数据拉出来、做必要的转换、再写到目标端。DS 通过自带的 SeaTunnel 任务节点把作业脚本提交给 SeaTunnel 的常驻集群去执行。打个比方DS 是工厂里的生产计划科SeaTunnel 是厂区里的运输队计划科把运输单子派给运输队运输队才真正开着车把货从 A 仓拉到 B 仓。正因为这个依赖关系部署顺序应该是先部署一个能用的 DolphinScheduler再让 SeaTunnel 集群就位最后在 DS 里配置任务节点去对接 SeaTunnel。如果反过来你先装 SeaTunnel 再装 DS中间还得反复回头确认 IP、端口、服务名很容易搞乱。这个组合里真正复杂的地方在离线本身。离线的意思不只是“没有外网”很多时候是连软件源、apt/yum 源都没有只有一台跳板机或者一台能联网的开发机能帮你把物料准备好。所以整个项目的第一步其实是在有网的环境里把所有需要的东西打成“包裹”再运到离线环境里拆开。这不是多装几个软件的问题而是整个工作方式都变了。1.2 方案选型Helm、镜像仓库、外部数据库怎么取舍在 k8s 上部署 DolphinScheduler 有几种方式纯手工写 YAML、用官方 Helm chart、或者用一些定制化的 Operator。在这次离线场景里我强烈建议用官方 Helm chart然后离线把 chart 包下载下来改成离线 values 再安装。原因很简单DolphinScheduler 在 k8s 上要部署的可不只一个镜像api-server、master、worker、alert 每个角色都是独立的 Deployment 或 StatefulSet手工写 YAML 不仅量大而且很容易漏掉环境变量、健康检查、服务端口这些细节。Helm chart 把这些都打包好了你要改的核心参数基本都收敛在 values.yaml 里离线部署时工作量会小很多。SeaTunnel 就不太一样。SeaTunnel 在 k8s 上更常见的是部署一个常驻的 Zeta 集群用几个 StatefulSet 节点组一个小集群由 DolphinScheduler 把作业提交过来执行。当然 SeaTunnel 也能以“每任务拉起临时 Pod”的方式跑但那种模式下每个任务都要重新初始化容器、拉插件、建集群在离线环境里资源开销太大而且容器拉起速度慢完全没有常驻集群划算。所以我这边采用的方式是Zeta 集群常驻DS 只负责提交作业和跟踪状态。镜像仓库这块离线 k8s 集群内部一般会有一个私有 Registry比如 Harbor 或者最简单的registry:2。如果你连私有仓库都没有只在一台机器上做实验那可以用docker save和docker load的方式把镜像直接导入到每个节点但如果是一个正经的多节点集群强烈建议还是搞一个私有仓库。原因不难理解镜像不推到仓库里每个节点都得手动 load 一遍节点多了就变成了灾难而且后续升级镜像、加节点都非常痛苦。数据库这里也要提前想好。DolphinScheduler 的元数据默认可以存在它自己 chart 里自带的 PostgreSQL 里但生产环境我一般会用外部的 MySQL 或者已有的数据库实例。离线环境里通常有现成的 MySQL 在跑直接复用是性价比最高的做法。如果让 chart 自己再拉起一个 PostgreSQL不仅多了一套要维护的中间件而且它的数据卷如果不持久化Pod 一旦重建整个调度系统的元数据可能就没了这个风险在离线环境里更难接受。存储和网络方面存储类要看集群有没有提供默认 StorageClass没有的话得在 values 里指定一个可用的存储类否则 Pod 一直 Pending 起不来。网络暴露我一般直接用 NodePort因为离线环境大多在局域网内Ingress 不是一定有的NodePort 最省事改一下 service type 就能访问到 Web UI 和 API。2. 离线环境前置准备与镜像物料清单2.1 离线物料清单除了镜像你还得带这些先把需要准备的物料列出来别到了现场才发现少了东西。有些人只拉了两个主镜像就过去了结果部署时发现 chart 里还依赖一堆 init 容器、busybox、甚至数据库客户端镜像全部卡在 ImagePullBackOff。物料说明备注DolphinScheduler 各角色镜像api-server、master、worker、alert 对应镜像同一个版本 tag官方 chart 会自动拼接SeaTunnel 镜像用于常驻 Zeta 集群需要包含常用 connector 插件DolphinScheduler Helm chart 包.tgz文件在有网环境用 helm pull 获取SeaTunnel 部署模板chart 或自写 YAML根据你对 helm 的熟悉程度选MySQL 客户端工具初始化/检查数据库用离线机器的 yum 源未必有kubectl、helm 二进制离线机器不一定自带提前拷贝好对应版本常用 linux 工具包可选tar、vim、telnet、curl排查网络问题时必须用这里有个小经验DolphinScheduler 官方 chart 包的 values 里通常会有一个image.repository和image.tag它会用同一个 tag 去拉所有角色的镜像。所以你需要把该版本涉及的每个角色镜像都推到私有仓库里不能只推一个dolphinscheduler-api。检查办法很简单用helm install之前先helm template渲染一下把 pod 里的 image 全部列出来看看有哪些镜像没准备。2.2 在有网环境准备镜像并同步到离线仓库在有网的开发机上准备工作其实就两个动作拉镜像、推镜像。假设我这边用 Harbor 作为私有仓库地址是192.168.x.x:5000。先把镜像拉下来docker pull apache/dolphinscheduler:3.2.1 docker pull apache/seatunnel:2.3.8注意版本号不要乱搭配。DolphinScheduler 和 SeaTunnel 的兼容关系在官方的文档里有对应表如果 DS 某个版本要求的 SeaTunnel 接口和你装的 SeaTunnel 版本对不上后面提交作业时会报各种奇怪的客户端错误。所以下镜像前先去看一眼兼容性说明用推荐的组合版本。拉完给镜像打上和私有仓库匹配的 tag然后推送docker tag apache/dolphinscheduler:3.2.1 192.168.x.x:5000/library/dolphinscheduler:3.2.1 docker push 192.168.x.x:5000/library/dolphinscheduler:3.2.1 docker tag apache/seatunnel:2.3.8 192.168.x.x:5000/library/seatunnel:2.3.8 docker push 192.168.x.x:5000/library/seatunnel:2.3.8如果你没有私有仓库只能往离线机器上拷镜像那就用docker save打成 tar 包到目标机器上再docker load。这个办法适合单机或者节点很少的场景但别忘了每个节点都要 load。我曾经在一个三节点集群上这么干过忘了其中一台结果那个节点上的 Pod 死活起不来查了半天才发现是镜像缺失。后来我还是坚持先搭一个简单的 Registry一劳永逸。2.3 Chart 包和依赖的离线搬运方式在线环境安装多用helm repo add然后helm install但离线环境最重要的变化是你必须在有网的那台机器上先把 chart 下载下来再把.tgz文件带到内网。命令很简单helm repo add apache https://dolphinscheduler.apache.org helm repo update helm pull apache/dolphinscheduler --version 3.2.1这样你就得到一个类似dolphinscheduler-3.2.1.tgz的文件。把这个文件拷贝到离线环境后安装时直接指向本地文件即可。要注意的是如果 chart 本身有依赖其他子 chart比如旧版 DS chart 会依赖 zookeeper、postgresql 这些那helm pull下来的时候依赖不一定完整。稳妥的做法是先解压 tgz检查charts/目录里有没有对应的依赖包没有的话要在有网环境手动helm dependency update把依赖子 chart 也下载下来一起带过去。SeaTunnel 这边如果官方没有合适的 helm chart你可以自己写一套 StatefulSet Service 的 YAML要注意的配置其实也不多后面第 4 章会详细说。但如果你看到某个第三方 chart第一件事是把它的 values 完整看一遍搞清楚它到底创建了几个StatefulSet挂载了哪些存储卷有没有额外的initContainers避免最后部署了一堆你不知道是干嘛的 Pod离线查起来非常费劲。3. DolphinScheduler 在 k8s 上的离线部署实操3.1 修改 values.yaml 里的离线核心参数用 Helm 部署时我习惯先把 chart 的 values 全部过一遍看清楚了再改。不要把官方默认配置直接拿来用因为你离线环境没有外网仓库默认值一定会去docker.io拉镜像。我这里以某个 3.2.x 版本为例把 values 里几个核心部分这样改image: registry: 192.168.x.x:5000 repository: library/dolphinscheduler tag: 3.2.1 postgresql: enabled: false externalDatabase: type: mysql driver: com.mysql.cj.jdbc.Driver host: 192.168.x.x port: 3306 database: dolphinscheduler username: ds password: ds123456 params: characterEncodingutf8mb4useSSLfalseserverTimezoneAsia/Shanghai zookeeper: enabled: true master: replicas: 2 storage: persistence: enabled: true storageClass: accessModes: - ReadWriteOnce worker: replicas: 2 storage: persistence: enabled: true storageClass: accessModes: - ReadWriteOnce alert: replicas: 1这里有几个容易忽略的点。第一postgresql.enabled: false和externalDatabase是配套的只改一个会导致 chart 仍然去拉 postgres 镜像或者连不上数据库一直等。第二params一定要把它加上特别是useSSLfalse和characterEncodingutf8mb4不然 MySQL 的 SSL 握手在某些环境会失败或者中文数据写入后乱码。第三master.replicas和worker.replicas如果设了大于 1要确保你有对应的存储能力虽然 DS 的日志存储不是必须持久的但生产上最好还是挂到 PVC 上不然 Pod 一重建历史运行日志全丢了。还有一点提醒一下不同版本之间 values 字段名可能有差异比如有些版本把alert.replicas叫做alertServer.replicas。拿到 chart 包后先看默认 values 的注释对照你的版本做调整别套用网上随便搜到的老旧配置。3.2 执行 Helm 安装并完成基本验证物料都齐了之后安装命令其实非常短。可以直接用本地 chart 文件也可以先把 tgz 解压到目录下再指定目录安装helm install dolphinscheduler ./dolphinscheduler-3.2.1.tgz \ -n>kubectl get pods -n>kubectl describe pod dolphinscheduler-master-0 -n>kubectl create secret docker-registry regcred \ --docker-server192.168.x.x:5000 \ --docker-usernameadmin \ --docker-passwordxxx \ --docker-emailadminexample.com然后在 chart values 里配上imagePullSecrets或者直接给 serviceaccount 关联 secret。这个位置特别容易踩坑的是很多人记了 docker 的登录态却不创建 k8s secretPod 每次都因为认证失败被拒绝拉取镜像。在离线环境里这种错特别隐蔽因为组件本身没问题只是仓库不认你。5.2 DolphinScheduler 一直连不上数据库DS 的 master/worker 在启动时会拼命尝试连接配置的数据库。如果数据库连接不上Pod 表现就是 CrashLoopBackOff日志里可能有communications link failure、Access denied、Unknown database这类信息。排查要点第一MySQL 是否允许来自 k8s 节点网段的连接。MySQL 默认绑定 127.0.0.1如果只监听本地那必须改配置绑定0.0.0.0或者业务网卡地址否则别的机器就连不上。第二账号权限要给足。DS 需要建表、改表账号不能只给 SELECT至少要给GRANT ALL ON dolphinscheduler.* TO ds%。第三数据库字符集建库时用 utf8mb4CREATE DATABASE dolphinscheduler DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;如果表已经建坏了最简单的做法是删掉库重建然后重启 DS Pod让初始化逻辑重新执行。离线环境里没有外网的“重试一下就好了”这种好事所以数据库初始化阶段的耐心检查很重要。5.3 SeaTunnel 任务一直 Pending 或提交超时如果你在 DS 里运行 SeaTunnel 任务发现任务实例一直处于提交中或执行中怎么等都等不到结果优先怀疑两个地方一个是 SeaTunnel 集群地址配置错误DS 发出去的请求 Zeta 集群根本没收到另一个是 Zeta 集群内部成员状态异常收到请求但任务无法调度执行。排查第一个去 Zeta 集群 Pod 上看日志看有没有接收到 DS 的 job 提交请求。排查第二个看 Zeta 集群的节点数量是不是少于期望值比如配置了 3 个副本但只有一个 Running那任务大概率会 Pending。一个很有效的自测方法是手动进入 SeaTunnel 容器把 DS 上配置的那段任务脚本保存为文件然后用 SeaTunnel 的启动命令直接跑一次作业。如果直接在集群内部能跑通说明引擎侧没问题问题出在 DS 和 SeaTunnel 的通信链路上如果手动跑也报错就直接在容器日志里定位具体报错信息比如缺少 connector、源库连不上、SQL 语法不兼容等等。这种方式能帮你快速把“DS 问题”和“SeaTunnel 问题”切分清楚。5.4 时间同步、日志持久化和 DNS 解析几个容易漏的坑离线环境里节点时间不同步是特别容易忽视但破坏力很大的问题。DolphinScheduler 的 master 在调度任务时非常依赖时间判断如果不同节点间时间差过大工作流可能不触发任务实例可能一直处于等待状态。所以部署前先把每台机器的时间统一好用 chrony 搭一个内网时间源或者至少手动校准一次。日志持久化是另一个容易被跳过但建议尽早做好的事。SeaTunnel 的作业日志在容器里DS 的 worker 日志也在容器里如果 Pod 被重新调度这些日志就全没了。排查历史问题时没有日志非常痛苦。生产部署时宁可多配几块 PVC也要把日志目录挂出来这是性价比很高的投资。DNS 解析也要多看两眼。k8s 集群内 Pod 之间访问如果你在 DS 的配置里写的是 SeaTunnel 的短服务名而两个 Pod 在不同 namespace 下那服务名必须是完整的 FQDN 格式类似seatunnel-zeta-svc.data-platform.svc.cluster.local。我遇到过不止一次因为短域名没解析导致 DS 怎么也提交不到 SeaTunnel而两边单独测试都正常的情况。最后再说一句离线部署这件事本身并不可怕真正耗时间的是你没有预料到离线会切断那么多“隐性依赖”。镜像依赖、Helm 依赖、时间同步、DNS 解析每一样都可能在关键时刻给你一个下马威。我现在的习惯是把所有物料预先列成清单每一项都打钩确认后才进场。按照这条路子把 DS 和 SeaTunnel 搭起来之后后续再扩充新的数据源、新的工作流就顺多了整套体系也经得起上生产后的折腾。
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →