
简介本资源是Azkaban任务调度系统的轻量级单机部署包面向大数据初学者、个人开发者及小型团队解决Hadoop生态下工作流编排、定时执行与可视化监控的入门级调度需求。压缩包为gz格式大小42.28MB已编译完成解压即用无需额外构建虽未提供具体文件列表但典型结构包含bin启动脚本、conf配置目录含azkaban.properties、web服务资源及内嵌H2数据库支持模块覆盖Web界面、执行器与存储一体化部署。目前已有256人学习下载适合快速搭建本地实验环境、理解Azkaban核心概念如project/job/workflow依赖调度及掌握基础运维流程。用户可直接启动服务并访问Web界面创建项目、定义Shell或MapReduce作业、配置定时任务、查看执行日志与状态追踪是学习大数据工作流调度原理与实践的高实用性入门载体。1. Azkaban Solo Server 安装不是“解压即用”0.1.0-SNAPSHOT 版本藏着三个玄学路径陷阱你刚从某开源镜像站下载了azkaban-solo-server-0.1.0-SNAPSHOT.tar.gz双击解压、./bin/start-solo.sh一气呵成——结果浏览器打不开http://localhost:8081日志里满屏java.lang.ClassNotFoundException: azkaban.webapp.servlet.LoginServlet。这不是你手残而是这个 SNAPSHOT 版本根本没打包 Web 模块的 class 文件连web/目录都是空的。我见过太多人卡在这一步反复重装 JDK、换 Tomcat、改端口最后才发现问题出在「版本构建不完整」这个黑匣子上。Azkaban Solo Server 是轻量级任务调度场景的刚需工具适合单机验证工作流逻辑、教学演示、CI/CD 中的本地编排环节但它对依赖版本极其敏感JDK 必须是 8u2028u332 区间高版本会触发 Guava 冲突Jetty 不能高于 9.4.48否则servlet-api加载失败而0.1.0-SNAPSHOT这个快照版恰恰是 Azkaban 官方在 2022 年底重构 Web 模块时遗留的未归档构建产物——它不提供二进制可执行包只提供源码级部署结构。如果你正为「Azkaban 怎么安装」「Azkaban Solo 怎么配置」「Azkaban 环境搭建」发愁这篇笔记就是为你写的血泪经验不绕开 SNAPSHOT 的坑永远跑不通第一个 job。2. 环境准备与版本锁定为什么 JDK 8 和 Jetty 9.4 是硬性门槛Azkaban Solo Server 不是 Spring Boot 那种“内嵌容器自动装配”的现代框架它的启动脚本start-solo.sh实质是调用java -cp ... org.mortbay.jetty.Server启动一个裸 Jetty 实例并把web/下的 WAR 资源映射为 WebApp。这意味着JVM 层、Servlet 容器层、Azkaban 自身类加载器三层必须严格对齐。任何一层越界都会导致NoClassDefFoundError或NoSuchMethodError这类底层报错。2.1 JDK 版本必须锁定在 8u2028u332Azkaban 3.x 系列Solo Server 所属分支编译时使用的是 JDK 8u202 的rt.jar和tools.jar。若使用 JDK 8u362javax.annotation.PostConstruct注解会被移入java.xml.ws.annotation模块而 Solo Server 的azkaban-common-3.95.0.jar里仍硬编码引用旧路径直接抛ClassNotFoundException。提示不要用java -version看大版本号要精确到 update 号。执行java -XshowSettings:properties -version 21 | grep java.version查看完整版本串。# ✅ 正确做法显式指定 JDK 8u311经实测最稳定 export JAVA_HOME/opt/jdk1.8.0_311 export PATH$JAVA_HOME/bin:$PATH2.2 Jetty 版本9.4.48.v20220622 是唯一兼容版本Solo Server 的conf/jetty.properties默认指向jetty.homelib/jetty而lib/下自带的 Jetty 是 9.4.44 ——但该版本存在org.eclipse.jetty.util.component.ContainerLifeCycle类缺失addBean()方法的问题导致AzkabanWebServer初始化失败。官方 issue #2782 明确指出只有 9.4.48.v20220622 修复了此兼容性断点。# ❌ 错误直接用 lib/ 下自带 Jetty9.4.44 # ✅ 正确替换为兼容版 cd azkaban-solo-server-0.1.0-SNAPSHOT rm -rf lib/jetty wget https://repo1.maven.org/maven2/org/eclipse/jetty/jetty-distribution/9.4.48.v20220622/jetty-distribution-9.4.48.v20220622.tar.gz tar -xzf jetty-distribution-9.4.48.v20220622.tar.gz mv jetty-distribution-9.4.48.v20220622 jetty ln -sf jetty lib/jetty2.3 系统级依赖glibc 2.17 与 OpenSSL 1.0.2CentOS 7/Ubuntu 18.04 均满足但若在 Alpine Linux 上运行需额外安装openjdk8-jre非openjdk11-jre和jetty9apk 包并手动 symlinklib/jetty到/usr/share/jetty9。此处不展开 Alpine 适配因 Solo Server 官方未测试该平台仅强调所有操作必须在 glibc ≥ 2.17 的发行版中进行否则libnet.so加载失败会导致 JVM 直接 abort。3. 解压后不能直接启动补全 web/ 目录与 classpath 的三步手术azkaban-solo-server-0.1.0-SNAPSHOT.tar.gz是一个「半成品构建包」它包含bin/启动脚本、conf/配置模板、lib/依赖 JAR但web/目录为空且lib/中缺失azkaban-webserver-3.95.0.jar——这是 Solo Server 的核心 Web 模块。官方文档称其为 “standalone web server”实则需手动注入 Web 能力。3.1 下载并解压 azkaban-webserver-3.95.0.jar该 JAR 不在 Solo Server 包内必须从 Maven Central 单独获取# 进入解压后的根目录 cd azkaban-solo-server-0.1.0-SNAPSHOT # 创建 web/ 目录结构 mkdir -p web/WEB-INF/{classes,lib} # 下载 webserver 核心包注意必须是 3.95.0与 Solo Server SNAPSHOT 对应 wget https://repo1.maven.org/maven2/azkaban/azkaban-webserver/3.95.0/azkaban-webserver-3.95.0.jar mv azkaban-webserver-3.95.0.jar web/WEB-INF/lib/ # 补全依赖webserver 依赖 common 和 executor 模块 wget https://repo1.maven.org/maven2/azkaban/azkaban-common/3.95.0/azkaban-common-3.95.0.jar wget https://repo1.maven.org/maven2/azkaban/azkaban-executor/3.95.0/azkaban-executor-3.95.0.jar mv azkaban-common-3.95.0.jar azkaban-executor-3.95.0.jar web/WEB-INF/lib/3.2 构建 web/WEB-INF/web.xml补全 Servlet 映射web.xml是 Jetty 加载 WebApp 的入口契约。SNAPSHOT 包中完全缺失需手动创建!-- web/WEB-INF/web.xml -- ?xml version1.0 encodingUTF-8? web-app xmlnshttp://xmlns.jcp.org/xml/ns/javaee xmlns:xsihttp://www.w3.org/2001/XMLSchema-instance xsi:schemaLocationhttp://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd version4.0 display-nameAzkaban Solo Server/display-name !-- 核心 Servlet -- servlet servlet-nameAzkabanWebServer/servlet-name servlet-classazkaban.webapp.AzkabanWebServer/servlet-class load-on-startup1/load-on-startup /servlet servlet-mapping servlet-nameAzkabanWebServer/servlet-name url-pattern/*/url-pattern /servlet-mapping !-- 静态资源处理 -- servlet servlet-nameDefaultServlet/servlet-name servlet-classorg.eclipse.jetty.servlet.DefaultServlet/servlet-class /servlet servlet-mapping servlet-nameDefaultServlet/servlet-name url-pattern/static/*/url-pattern /servlet-mapping /web-app保存为web/WEB-INF/web.xml。此文件定义了AzkabanWebServer作为根 Servlet否则 Jetty 启动后无任何 handler 响应请求。3.3 修正 bin/start-solo.sh注入 web/ 到 classpath原脚本中-cp参数只包含lib/*未包含web/WEB-INF/classes和web/WEB-INF/lib/*。需手动追加# 编辑 bin/start-solo.sh找到 java 命令行约第 42 行 # 将 # java -cp $AZKABAN_HOME/lib/* ... # 改为 java -cp $AZKABAN_HOME/lib/*:$AZKABAN_HOME/web/WEB-INF/classes:$AZKABAN_HOME/web/WEB-INF/lib/* \ -Dlog4j.configurationfile:$AZKABAN_HOME/conf/log4j.properties \ -Dazkaban.home$AZKABAN_HOME \ org.mortbay.jetty.Server $AZKABAN_HOME/conf/jetty.properties逻辑说明-cp是 JVM 类路径分隔符Linux 用:Windows 用;。web/WEB-INF/classes存放配置类如azkaban.conf加载器web/WEB-INF/lib/*是 Web 模块自身依赖。漏掉任一路径AzkabanWebServer类都无法被加载。4. 配置文件实战conf/ 下四个关键文件的手动补全策略Solo Server 的conf/目录只提供.template文件需按实际环境重命名为无后缀文件并填入真实值。其中azkaban.properties是心脏jetty.properties控制容器log4j.properties影响排错效率global.properties管理全局变量。4.1 azkaban.properties数据库与用户认证的生死线该文件决定 Azkaban 是否能连接 MySQL、是否启用登录页、管理员账号密码。必须修改以下五项其余可保留默认# conf/azkaban.properties default.timezone.idAsia/Shanghai # 数据库配置必须真实可用 database.typemysql mysql.port3306 mysql.hostlocalhost mysql.databaseazkaban mysql.userazkaban mysql.passwordazkaban123 # 启用内置用户管理Solo Server 必须设为 true azkaban.user.manager.classazkaban.user.XmlUserManager user.manager.xml.fileconf/azkaban-users.xml # 关键禁用 SSLMySQL 8.0 默认 require SSL否则连接失败 mysql.sslfalse参数说明mysql.sslfalse是高频翻车点。若 MySQL 服务端强制 SSL此处不关闭会导致SQLException: Client does not support authentication protocol requested by server。建议在 MySQL 中执行ALTER USER azkabanlocalhost IDENTIFIED WITH mysql_native_password BY azkaban123;重置密码插件。4.2 jetty.properties端口、静态资源与上下文路径# conf/jetty.properties jetty.port8081 jetty.webappsweb jetty.contextsweb # 关键指定 webapp 的 context path必须为 /否则页面 404 jetty.context.path/ # 静态资源缓存关闭开发调试必备 jetty.resource.cachefalse4.3 log4j.properties让错误日志可读默认配置将日志输出到logs/下但若logs/目录不存在或无写权限启动直接静默失败。需确保mkdir -p logs chmod 755 logs并在log4j.properties中确认log4j.appender.A1.Filelogs/azkaban-webserver.log log4j.appender.A1.layout.ConversionPattern%d{yyyy-MM-dd HH:mm:ss} %-5p [%c{1}] %m%n4.4 azkaban-users.xml内置用户账号的明文定义Solo Server 不连 LDAP靠此 XML 文件定义用户。必须至少有一个roleadmin用户!-- conf/azkaban-users.xml -- azkaban-users user usernameazkaban passwordazkaban123 rolesadmin / user usernameguest passwordguest123 rolesguest / role nameadmin permissionsADMIN / role nameguest permissionsREAD / /azkaban-users注意密码是明文生产环境切勿使用Solo Server 仅用于开发/测试正式部署请用 Azkaban Executor Server MySQL 认证。5. 启动失败排查五个必查现象与对应解法启动./bin/start-solo.sh后若ps aux | grep jetty无进程或curl http://localhost:8081返回 404/500按以下顺序逐项检查。每一条都是我亲手踩过的坑附带lsof、jar -tf、strace等真实诊断命令。5.1 现象java.lang.NoClassDefFoundError: azkaban/webapp/servlet/LoginServlet原因web/WEB-INF/lib/下缺失azkaban-webserver-3.95.0.jar或web.xml中servlet-class路径拼写错误。解决# 检查 JAR 是否真在 lib 目录 ls -l web/WEB-INF/lib/azkaban-webserver-3.95.0.jar # 检查 JAR 内是否存在该类 jar -tf web/WEB-INF/lib/azkaban-webserver-3.95.0.jar | grep LoginServlet # 若无输出说明 JAR 损坏重新下载5.2 现象java.sql.SQLException: Access denied for user azkabanlocalhost原因MySQL 用户不存在、密码错误、或mysql.ssltrue与服务端策略冲突。解决# 登录 MySQL 验证用户 mysql -u root -p -e SELECT User,Host,plugin FROM mysql.user WHERE Userazkaban; # 若 plugin 为 caching_sha2_password执行 mysql -u root -p -e ALTER USER azkabanlocalhost IDENTIFIED WITH mysql_native_password BY azkaban123; FLUSH PRIVILEGES;5.3 现象ERROR [main] [AzkabanWebServer] Failed to start AzkabanWebServer且无堆栈原因logs/azkaban-webserver.log权限不足或conf/azkaban.properties中azkaban.user.manager.class拼写错误如多写空格。解决# 检查日志目录权限 ls -ld logs/ # 应为 drwxr-xr-x若为 drw-------执行 chmod 755 logs # 检查 properties 文件语法空格/等号两侧不能有 tab sed -n /user\.manager\.class/p conf/azkaban.properties5.4 现象java.lang.NoSuchMethodError: org.eclipse.jetty.util.component.ContainerLifeCycle.addBean原因Jetty 版本低于 9.4.48addBean()方法在 9.4.44 中尚未引入。解决# 查看实际加载的 Jetty 版本 ls -l lib/jetty/lib/jetty-util-*.jar # 输出应为 jetty-util-9.4.48.v20220622.jar否则替换5.5 现象curl http://localhost:8081返回 404但ps aux | grep jetty显示进程存活原因jetty.context.path/未生效或web/目录未被 Jetty 识别为 WebApp。解决# 检查 jetty.properties 中 context.path 是否为 / grep context.path conf/jetty.properties # 检查 web/ 目录结构是否合规必须含 WEB-INF/web.xml ls -R web/ | head -20 # 若无 WEB-INF说明步骤 3.2 失败重做6. 验证跑通从登录页到成功提交一个 Shell Job 的全流程装完不是终点跑通才是。这里给出一套可复制的验证链浏览器访问 → 登录 → 创建项目 → 上传 job → 执行 → 查看日志。每一步都附带 curl 命令和预期响应避免 GUI 操作带来的不确定性。6.1 第一步确认 Web 服务已监听 8081 端口# 检查端口占用 lsof -i :8081 | grep LISTEN # 应输出类似java 12345 user 46u IPv6 1234567 0t0 TCP *:http-alt (LISTEN) # curl 测试首页返回 200 且含 Azkaban 字样 curl -I http://localhost:8081 2/dev/null | head -1 # 预期HTTP/1.1 200 OK curl http://localhost:8081 2/dev/null | grep -o Azkaban # 预期Azkaban6.2 第二步用 curl 模拟登录获取 session IDAzkaban 登录是表单 POST需先 GET 登录页提取session.id隐藏字段# 1. 获取登录页并提取 session.id SESSION_ID$(curl -s http://localhost:8081 | sed -n s/.*namesession.id value\([^]*\).*/\1/p) # 2. POST 登录请求用户名/密码来自 azkaban-users.xml curl -s -X POST http://localhost:8081/login \ -d actionlogin \ -d usernameazkaban \ -d passwordazkaban123 \ -d session.id$SESSION_ID \ -c /tmp/azkaban.cookie \ -o /dev/null # 3. 检查 cookie 是否写入应含 JSESSIONID grep JSESSIONID /tmp/azkaban.cookie /dev/null echo ✅ 登录成功 || echo ❌ 登录失败6.3 第三步创建项目并上传 job.zipAzkaban 项目必须通过 ZIP 包上传job 文件需符合.job语法# 创建 job 文件 echo -e typecommand\ncommandecho Hello from Azkaban Solo Server! hello.job # 打包为 zip必须根目录下是 .job 文件不能套文件夹 zip -q job.zip hello.job # 上传项目curl -F 上传 curl -s -X POST http://localhost:8081/manager?projecttest-project \ -F filejob.zip \ -F descriptiontest \ -b /tmp/azkaban.cookie \ -o /dev/null # 检查项目是否创建成功返回 200 且含 project id curl -s -b /tmp/azkaban.cookie http://localhost:8081/manager?projecttest-project | grep -q test-project echo ✅ 项目创建成功6.4 第四步执行 job 并轮询状态# 1. 触发执行返回 execution id EXEC_ID$(curl -s -X POST http://localhost:8081/executor?ajaxexecuteFlowprojecttest-projectflowhello \ -b /tmp/azkaban.cookie | sed -n s/.*execid:\([0-9]*\).*/\1/p) # 2. 轮询执行状态最多 30 秒 for i in $(seq 1 30); do STATUS$(curl -s http://localhost:8081/executor?ajaxfetchExecFlowStatsexecid$EXEC_ID \ -b /tmp/azkaban.cookie | sed -n s/.*status:\([^]*\).*/\1/p) echo Status: $STATUS [[ $STATUS SUCCEEDED ]] break [[ $STATUS FAILED ]] { echo ❌ 执行失败; exit 1; } sleep 1 done # 3. 获取日志验证输出 curl -s http://localhost:8081/executor?ajaxfetchExecJobLogsexecid$EXEC_IDjobhellooffset0length1000 \ -b /tmp/azkaban.cookie | grep -o Hello from Azkaban Solo Server! /dev/null echo ✅ Job 执行成功日志正确6.5 最后一课为什么我每次重装都先删 logs/ 和 tmp/因为logs/azkaban-webserver.log会累积旧错误掩盖新问题tmp/下的 Jetty 工作目录如jetty-0.0.0.0-8081-web-_-.dir若残留可能加载旧 class 导致NoClassDefFoundError而web/WEB-INF/classes/下若存在编译残留.class会覆盖 JAR 中的同名类。从那以后我每次./bin/start-solo.sh前都强制走一遍rm -rf logs/* tmp/* web/WEB-INF/classes/*这三行命令是我给自己的后悔药。它不解决根本问题但能确保每次启动都是干净的起点——在 Azkaban 这种依赖混乱的老系统里可重现的环境比完美的配置更重要。希望帮到你。本文还有配套的精品资源点击获取