Azkaban solo-server 单机调度:Docker 安装与工作流实战 简介Azkaban Solo Server 单机版编译包面向需要快速搭建工作流调度环境的大数据开发者、运维人员及个人学习者用于解决 Hadoop 作业与 Shell、Java 任务按依赖顺序自动执行的问题。资源为 azkaban-solo-server-0.1.0-SNAPSHOT.tar.gz压缩包约 42.28MB解压后可直接运行无需自行编译。包内包含 Web 服务、执行器与内嵌 H2 数据库等组件通过 conf 配置与 bin 脚本即可完成初始化、启动与访问适合小型团队或个人在单机上验证任务调度流程。目前已有 256 人学习下载。借助该包读者可快速体验项目创建、作业定义、依赖编排、定时调度及日志监控等完整环节并对照配置项理解单机部署的目录结构与运行机制为后续迁移至集群模式或排查调度异常提供实践基础。1. 从 azkaban-solo-server-0.1.0-SNAPSHOT.tar.gz 说起单机调度器到底能扛多少活手里拿到一个azkaban-solo-server-0.1.0-SNAPSHOT.tar.gz第一反应往往是「这玩意儿解压完能不能直接跑」。能跑而且 solo-server 模式就是 Azkaban 官方给单机场景留的口子它把 Web Server 和 Executor Server 塞进同一个 JVM 进程元数据默认落在本地 H2 文件库不需要 MySQL不需要多节点协调。对于只有几台机器、几十个定时任务、又不想维护一套分布式调度集群的团队来说这个 tar.gz 反而是最省心的起点。它解决的问题很具体把散落在 crontab 里的脚本收拢成有依赖关系、有重试、有日志、有失败告警的工作流。适合谁数据量不大、任务链路不复杂、运维人手紧张的小团队或者你只是想在本机先把 Azkaban 的 job 语法和调度逻辑摸熟。但 solo-server 的边界也很硬——它不适合高并发触发、不适合多执行器横向扩展这一点后面会反复提到。2. 解压即用的 solo-server目录结构、启动链路与 JVM 参数2.1 tar.gz 解开后到底有什么先把包解开别急着启动先看清楚里面装了什么。不同构建来源的目录名可能略有差异但 solo-server 发行包的结构基本固定tar -zxvf azkaban-solo-server-0.1.0-SNAPSHOT.tar.gz cd azkaban-solo-server-0.1.0-SNAPSHOT ls -la典型输出里你会看到这几个关键目录目录/文件作用是否要改bin/启动、停止脚本核心是start-solo.sh/shutdown-solo.sh一般不改conf/azkaban.properties、log4j.properties、global.properties必须改lib/所有依赖 jarsolo 模式已打包齐全不动plugins/job 类型插件如 jobtype、common按需加sql/H2 建库脚本首次启动自动执行不动executions/运行时生成存放执行日志不动解压后先确认conf/azkaban.properties存在这是整个 solo-server 的命门。如果这个文件缺失或路径写错启动脚本会在初始化阶段直接抛异常日志里通常是一句Cannot find azkaban.properties。2.2 启动脚本背后做了什么solo-server 的启动不是简单java -jar它走的是bin/start-solo.sh脚本内部会拼装 classpath、设置-Dazkaban.home和-Dazkaban.conf两个系统属性然后调用azkaban.soloserver.AzkabanSingleServer这个主类。手动模拟一遍能帮你排查启动失败# 进入解压目录后手动拼一条启动命令方便看真实报错 java -Dazkaban.home$(pwd) \ -Dazkaban.conf$(pwd)/conf \ -cp lib/*:plugins/* \ azkaban.soloserver.AzkabanSingleServer逻辑说明azkaban.home告诉程序工作根目录在哪executions/、projects/都会基于它生成azkaban.conf指向配置目录程序会去这里读azkaban.properties。classpath 里lib/*和plugins/*缺一不可少了 plugins 会导致 job 类型注册失败提交任务时报Job type not found。参数说明如果你机器内存小默认 JVM 堆可能偏大可以在start-solo.sh里找到JAVA_OPTS或类似变量改成-Xmx512m。solo 模式单进程堆给 512M 到 1G 足够跑几十个轻量任务给太大反而拖慢 GC。2.3 第一次启动必须改的三个配置打开conf/azkaban.properties下面三项不改大概率出问题# 1. 时区不设会导致调度时间整体偏移 azkaban.default.timezoneAsia/Shanghai # 2. Web 端口默认 8081被占用就换 jetty.port8081 # 3. 元数据落盘位置solo 模式用 H2 本地文件 database.typeh2 h2.path./h2db时区这项是血泪经验不设azkaban.default.timezone容器或服务器 UTC 环境下你配的0 2 * * *会在凌晨 10 点触发排查半天才发现是时区。h2.path用相对路径时基准是azkaban.home所以别在别的目录启动脚本否则 H2 文件会生成到意想不到的地方。启动成功后访问http://localhost:8081默认账号密码通常是azkaban/azkaban首次登录后立刻改掉。3. 用 Docker 安装 azkaban solo-server镜像构建与数据卷挂载3.1 为什么 solo-server 反而适合容器化热搜里docker安装azkaban出现频率很高原因很实在solo-server 单进程、无外部数据库依赖天然适合打成镜像。容器化之后H2 数据、执行日志、项目包都能通过 volume 挂出来升级时换镜像即可不用在宿主机上折腾 Java 环境。但要注意solo-server 是有状态的容器删了 H2 文件就没了所以数据卷必须挂。3.2 写一个能复现的 Dockerfile不要直接找网上来路不明的镜像自己写一个最可控。假设 tar.gz 和 Dockerfile 在同一目录FROM eclipse-temurin:8-jre # solo-server 对 JDK8 兼容最好别盲目上高版本 WORKDIR /opt/azkaban # 拷贝并解压发行包 COPY azkaban-solo-server-0.1.0-SNAPSHOT.tar.gz /tmp/ RUN tar -xzf /tmp/azkaban-solo-server-0.1.0-SNAPSHOT.tar.gz -C /opt/azkaban --strip-components1 \ rm -f /tmp/azkaban-solo-server-0.1.0-SNAPSHOT.tar.gz # 时区避免调度偏移 ENV TZAsia/Shanghai EXPOSE 8081 # 前台启动保证容器不退出 CMD [bin/start-solo.sh, , tail, -f, /dev/null]逻辑说明--strip-components1把解压出来的顶层目录去掉让内容直接落在/opt/azkaban这样azkaban.home就是固定路径。CMD里用start-solo.sh启动后接tail -f是因为启动脚本本身会后台化进程然后退出容器会跟着停必须留一个前台进程撑住。参数说明基础镜像选eclipse-temurin:8-jre而不是latest是因为 Azkaban 0.1.0 这类老版本在高版本 JDK 上可能遇到反射和模块化限制。如果你确实要用 JDK11得额外加--add-opens参数属于自找麻烦。3.3 构建、挂载、启动的完整命令# 构建镜像 docker build -t azkaban-solo:0.1.0 . # 准备宿主机目录用于持久化 mkdir -p /data/azkaban/{h2db,executions,projects,logs} # 启动容器把有状态的目录全部挂出来 docker run -d --name azkaban-solo \ -p 8081:8081 \ -e TZAsia/Shanghai \ -v /data/azkaban/h2db:/opt/azkaban/h2db \ -v /data/azkaban/executions:/opt/azkaban/executions \ -v /data/azkaban/projects:/opt/azkaban/projects \ -v /data/azkaban/logs:/opt/azkaban/logs \ azkaban-solo:0.1.0逻辑说明四个 volume 对应四类状态。h2db是元数据库丢了所有项目和历史都没了executions是执行日志排查失败任务全靠它projects是上传的项目包解压目录logs是服务端日志。只挂h2db不挂executions容器重建后历史执行记录会指向空目录页面点进去看不到日志。参数说明-e TZAsia/Shanghai和配置文件里的时区双保险。端口映射如果宿主机 8081 被占改成-p 18081:8081容器内始终是 8081。3.4 容器里改配置的正确姿势配置文件在镜像里直接docker exec进去改容器一重建就白改。正确做法是构建时用COPY覆盖或者运行时挂载单个配置文件docker run -d --name azkaban-solo \ -p 8081:8081 \ -v /data/azkaban/conf/azkaban.properties:/opt/azkaban/conf/azkaban.properties \ azkaban-solo:0.1.0挂载单个文件前宿主机上那份azkaban.properties必须已经存在且内容完整否则 Docker 会把它当目录创建启动直接失败。这是新手最常翻的车之一。4. 提交第一个工作流job 文件语法、依赖与调度参数4.1 最小可运行 job 长什么样Azkaban 的 job 就是一个.job后缀的 properties 文件。建一个目录放两个有依赖的任务# first.job typecommand commandecho first job at $(date)# second.job typecommand commandecho second job runs after first dependenciesfirst逻辑说明typecommand表示用 shell 执行command字段。dependenciesfirst声明依赖Azkaban 会先跑first成功后才跑second。依赖名是 job 文件名去掉.job不是command内容。参数说明command里可以写多条命令用连接但更推荐把逻辑写进独立脚本再调用job 文件保持干净。$(date)这种变量在 command 里能正常展开因为最终是交给 shell 执行的。4.2 打包上传与触发把两个.job文件打成一个 zip注意是 zip 不是 tar.gzAzkaban 只认 zipzip workflow.zip first.job second.job在 Web 界面Projects里新建项目上传workflow.zip然后点Execute Flow。如果想用命令行触发solo-server 也支持curl -k --data actionexecuteprojectmyprojectflowfirst \ http://localhost:8081/executor逻辑说明actionexecute触发指定 flowproject是项目名flow是 flow 名。solo 模式下 flow 名默认取第一个 job 或显式配置的azkaban.flow。参数说明命令行触发需要先登录拿 session.id上面这条是简化示意实际要带session.id参数。生产里更常用的是 Web 界面或 API 封装别裸调。4.3 调度参数怎么设才不踩时区坑在 flow 配置里设置定时核心是 cron 表达式和时区# 在 flow 的 schedule 配置中 azkaban.schedule.cron0 0 2 * * ? azkaban.schedule.timezoneAsia/Shanghai逻辑说明cron 是 Quartz 风格六位秒 分 时 日 月 周。0 0 2 * * ?表示每天 2 点整。注意 Azkaban 用的是 Quartz cron不是 Linux crontab 的五位格式多一个秒位这是最容易写错的地方。参数说明azkaban.schedule.timezone不写就取azkaban.properties里的全局时区。如果全局和 flow 级都设了flow 级优先。建议全局设一次flow 级不重复设减少不一致。5. solo-server 避坑与排查五个真实翻车现场5.1 启动报 H2 数据库锁现象重启容器后服务起不来日志里Database may be already in use或Lock file exists。原因上一次进程没正常退出H2 的.lock文件残留或者两个进程同时指向同一个h2db目录。解决确认没有残留 Java 进程后删掉h2db目录下的.lock文件再启动。容器场景下docker stop要给足超时时间让 JVM 走完 shutdown hook别直接docker kill。5.2 任务一直处于 Preparing 不执行现象flow 提交后卡在 Preparingexecutor 不接活。原因solo 模式下 Web 和 Executor 同进程如果azkaban.properties里 executor 端口配置和实际不符或者executor.port被防火墙拦内部通信就断了。解决检查executor.port配置solo 模式默认走本地回环一般不会被防火墙影响但如果你改过azkaban.properties里的 host 绑定可能绑到了错误网卡。恢复默认配置对比测试。5.3 中文日志乱码现象job 输出里的中文在 Web 界面显示成问号或方块。原因JVM 默认字符集不是 UTF-8或者 job 脚本输出编码和页面解析编码不一致。解决启动参数加-Dfile.encodingUTF-8同时在azkaban.properties里确认没有覆盖编码相关配置。job 脚本里显式export LANGen_US.UTF-8或zh_CN.UTF-8。5.4 上传 zip 后提示项目为空现象zip 上传成功但项目里看不到任何 flow。原因zip 打包时把.job文件套了一层目录Azkaban 只扫描 zip 根目录下的.job文件。解决打包时进入 job 文件所在目录再执行zip不要在上级目录打包。用unzip -l workflow.zip确认文件在根层。5.5 定时任务不触发现象cron 配好了到点没反应。原因时区偏移、cron 位数写错、或者 flow 没有处于Schedule状态只是保存了。解决先看azkaban.default.timezone再看 cron 是不是六位最后确认 flow 页面上的调度开关是打开状态。三个都对了还不触发去logs目录看 Quartz 相关日志。6. 从 solo 到可维护验证调度是否真的按预期跑solo-server 跑起来容易难的是确认它「按你以为的方式」在跑。我一般会做一个最小验证闭环建一个每分钟触发、只输出当前时间的 job观察一小时内日志时间戳是否连续且间隔稳定。# heartbeat.job typecommand commandecho heartbeat $(date %Y-%m-%d %H:%M:%S)配0 * * * * ?每分钟一次跑一小时后去executions目录翻日志。如果时间戳出现跳变或重复说明调度线程被阻塞或时区有问题。这个笨办法比看任何文档都直接。再进一步把关键 flow 的执行结果通过command里的curl推到一个你自己的接收端形成最简告警。solo-server 没有内置告警但 job 本身就是 shell能做的事很多。我吃过亏的地方在于早期觉得 solo 够用把所有任务堆上去直到某天一个长任务把 executor 线程占满后面所有 flow 全部排队。后来养成习惯给每个 job 加timeout类的前置判断长任务拆细solo 的线程池就那么大别把它当分布式集群使。如果你现在只是想让调度先跑起来、把 crontab 收编solo-server 这个 tar.gz 完全够用但心里要清楚它的天花板在哪等任务量和并发上来迁移到多执行器模式是迟早的事。希望帮到你。本文还有配套的精品资源点击获取