免费获取学习方案
ARTICLE DETAIL

资讯详情

深耕编程基础知识与建站技术分享的一线实战洞察。

基于Docker部署Azkaban工作流调度系统:从核心架构到生产实践

基于Docker部署Azkaban工作流调度系统:从核心架构到生产实践 1. 项目概述为什么我们需要Azkaban在数据开发、运维自动化乃至日常的脚本任务管理中我们经常会遇到这样的场景一个复杂的业务处理流程需要按顺序执行多个脚本或任务。比如每天凌晨1点先要运行一个Python脚本从数据库A拉取昨天的日志数据清洗转换后再调用一个Java程序进行聚合计算最后将结果通过一个Shell脚本推送到报表系统并发送一封邮件通知。如果中间某个步骤失败我们可能希望整个流程暂停并收到告警如果成功则希望自动触发下一个任务。手动去管理这一系列任务不仅效率低下而且极易出错。今天要聊的Azkaban就是为了解决这类问题而生的一个开源工作流调度系统。它由LinkedIn开发并开源核心目标就是让复杂的任务依赖关系变得可视化、可调度、可监控。简单来说你可以把它想象成一个“任务管家”你只需要告诉它任务之间谁先谁后、什么时候执行它就能帮你自动、可靠地按计划跑起来。最近随着容器化技术的普及“docker安装azkaban”也成了一个热门组合。确实用Docker来部署Azkaban能极大地简化环境配置的复杂度避免“在我的机器上能跑”的尴尬。这篇文章我就结合自己多次在生产环境部署Azkaban的经验从零开始带你彻底搞懂Azkaban的核心概念并手把手完成一次基于Docker的“干净”安装。无论你是数据工程师、运维工程师还是对自动化任务调度感兴趣的开发者这篇内容都能给你提供一份可直接复现的实操指南。2. Azkaban核心架构与设计思路拆解在动手安装之前我们必须先理解Azkaban是怎么工作的。知其然更要知其所以然这样在后续配置和排错时你才能心中有数。2.1 核心组件三驾马车驱动工作流Azkaban的架构非常清晰主要由三个核心组件构成理解它们各自的分工是掌握Azkaban的关键。Azkaban Web Server这是整个系统的“大脑”和“门面”。它提供了一个基于Web的用户界面我们所有的工作流定义、项目管理、任务调度、权限设置、历史日志查看等操作都是通过它与系统交互。同时它也是调度逻辑的核心负责解析我们提交的工作流文件比如.job文件计算任务之间的依赖关系并决定何时触发哪个任务。Web Server本身不执行具体任务它只负责“指挥”。Azkaban Executor Server这是系统的“四肢”负责实际干活。当Web Server决定要运行一个任务时它会将这个任务分派给一个可用的Executor Server。Executor Server接收到任务后会启动一个独立的进程例如一个JVM进程来运行Java作业或一个Shell进程来运行脚本并监控其执行状态成功、失败、运行中最后将状态汇报回Web Server。一个Azkaban集群可以配置多个Executor Server以实现负载均衡和高可用。关系型数据库这是系统的“记忆中枢”。Azkaban重度依赖数据库来存储一切状态信息包括项目元数据、工作流定义、所有历史执行记录、日志、用户权限、调度计划等。Web Server和Executor Server都是无状态的它们的状态都持久化在数据库中。这意味着只要数据库完好即使Web Server或Executor Server重启整个系统的状态也不会丢失。Azkaban官方支持MySQL这也是生产环境最常用的选择。这三个组件协同工作的流程可以概括为用户在Web UI上定义并调度一个工作流 - Web Server将工作流信息和触发事件存入数据库 - 触发时间到达Web Server从数据库加载工作流解析依赖生成待执行任务队列 - Web Server从数据库的executors表中选取一个活跃的Executor将任务分配给它 - Executor执行任务并将状态实时写回数据库 - Web Server从数据库读取状态更新UI展示给用户。2.2 设计哲学简单、可依赖Azkaban的设计有几个鲜明的特点这些特点也决定了它适合的场景。1. 基于文件的工作流定义这是Azkaban的一大特色。你不需要在复杂的UI上拖拽连线虽然它也提供了简单的可视化而是通过编写纯文本的.job文件来定义任务和依赖。每个.job文件定义一个任务通过dependencies参数指明它依赖哪些其他任务。最后将这些.job文件打包成一个ZIP包上传。这种方式虽然看起来“原始”但带来了巨大的好处版本控制友好。你可以用Git来管理你的工作流定义清晰地看到每次变更易于批量创建和修改便于CI/CD集成。2. 调度与执行分离Web Server和Executor Server的分离使得系统扩展性非常好。当任务量增长时你可以单独横向扩展Executor Server的数量而无需改动调度逻辑。同时这种分离也提高了系统的稳定性一个Executor的崩溃不会直接影响调度中心。3. “Solo”与“Cluster”模式为了适应不同规模的需求Azkaban提供了两种部署模式。Solo模式将Web Server和Executor Server打包在一个进程中使用内嵌的H2数据库开箱即用适合个人学习或测试。Cluster模式则是生产级部署三个组件独立部署通常使用MySQL数据库支持多Executor。我们今天的Docker安装本质上是在容器环境下实现一个简化但结构清晰的Cluster模式。注意虽然Solo模式简单但H2数据库在生产环境下有诸多限制如并发性能、稳定性严禁将其用于任何正式环境。即使是测试也建议从一开始就使用MySQL以保持环境一致性。3. 基于Docker的安装环境准备理解了架构我们就可以开始动手了。用Docker安装能让我们快速获得一个干净、隔离、可复现的Azkaban环境。这里我选择使用社区维护度较高的镜像并结合docker-compose进行编排这样服务之间的依赖和网络配置一目了然。3.1 工具与镜像选型解析首先你需要确保你的机器上已经安装了Docker和docker-compose。这是前提安装过程不再赘述。对于镜像的选择经过对比我推荐使用azkaban/azkaban-web-server和azkaban/azkaban-executor-server这两个官方相关的镜像由社区在官方代码基础上构建。为什么不自己从头构建因为这两个镜像已经帮我们做好了基础环境的配置比如Java版本、目录结构等省去了大量繁琐的步骤。数据库方面我们直接使用官方的mysql:8.0镜像。版本选择考量我选择Azkaban 3.x系列的最新稳定版例如3.90.0。3.x系列相较于更老的2.x系列在UI、API、多Executor支持等方面有显著改进是目前的主流。MySQL选择8.0而非5.7主要是为了获得更好的性能和安全性同时确保与最新软件的兼容性。3.2 编写docker-compose.yml编排文件接下来是核心步骤编写docker-compose.yml文件。这个文件定义了三个服务MySQL, Web Server, Executor Server以及它们之间的关系。version: 3.8 services: # 1. MySQL 数据库服务 azkaban-db: image: mysql:8.0 container_name: azkaban-mysql restart: unless-stopped environment: MYSQL_ROOT_PASSWORD: AzkabanRootPass123! # 请务必修改为强密码 MYSQL_DATABASE: azkaban MYSQL_USER: azkaban MYSQL_PASSWORD: AzkabanUserPass123! # 请务必修改为强密码 volumes: - ./mysql_data:/var/lib/mysql # 持久化数据库数据避免容器删除后数据丢失 - ./init-sql:/docker-entrypoint-initdb.d:ro # 初始化SQL脚本目录 ports: - 3306:3306 # 将主机3306端口映射到容器方便本地工具连接查看 networks: - azkaban-net healthcheck: # 健康检查确保数据库就绪后再启动其他服务 test: [CMD, mysqladmin, ping, -h, localhost, -uazkaban, -pAzkabanUserPass123!] interval: 10s timeout: 5s retries: 10 # 2. Azkaban Executor Server azkaban-executor: image: azkaban/azkaban-executor-server:3.90.0 container_name: azkaban-executor restart: unless-stopped depends_on: azkaban-db: condition: service_healthy # 依赖数据库健康状态 environment: AZKABAN_DB_HOST: azkaban-db # 使用Docker服务名进行网络通信 AZKABAN_DB_PORT: 3306 AZKABAN_DB_NAME: azkaban AZKABAN_DB_USER: azkaban AZKABAN_DB_PASSWORD: AzkabanUserPass123! AZKABAN_EXECUTOR_PORT: 12321 # Executor服务端口 volumes: - ./executor-conf:/azkaban-exec-server/conf # 挂载配置文件目录便于自定义 - ./executor-logs:/azkaban-exec-server/logs # 挂载日志目录便于查看 - ./jobs:/azkaban-exec-server/jobs:ro # 挂载一个公共任务目录可选 ports: - 12321:12321 networks: - azkaban-net # 3. Azkaban Web Server azkaban-webserver: image: azkaban/azkaban-web-server:3.90.0 container_name: azkaban-webserver restart: unless-stop depends_on: - azkaban-db - azkaban-executor environment: AZKABAN_DB_HOST: azkaban-db AZKABAN_DB_PORT: 3306 AZKABAN_DB_NAME: azkaban AZKABAN_DB_USER: azkaban AZKABAN_DB_PASSWORD: AzkabanUserPass123! AZKABAN_WEBSERVER_PORT: 8081 # Web Server服务端口 AZKABAN_EXECUTOR_HOST: azkaban-executor # 告知Web Server Executor的地址 AZKABAN_EXECUTOR_PORT: 12321 volumes: - ./web-conf:/azkaban-web-server/conf - ./web-logs:/azkaban-web-server/logs ports: - 8081:8081 # 将Web UI映射到主机8081端口 networks: - azkaban-net networks: azkaban-net: driver: bridge关键配置解读与避坑点网络networks我们创建了一个名为azkaban-net的桥接网络。三个服务都加入这个网络这样它们之间可以通过容器名如azkaban-db直接通信无需知道IP地址这是Docker容器间通信的最佳实践。数据持久化volumes我们将MySQL的数据目录、Azkaban的配置和日志目录都挂载到了主机当前目录下的子文件夹中。这样做有两个巨大好处一是数据不会随容器销毁而丢失二是方便我们直接在主机上查看日志、修改配置无需进入容器。依赖与启动顺序depends_on healthcheck我们定义了启动顺序数据库先启动并健康通过mysqladmin ping检测然后启动Executor最后启动Web Server。这确保了服务启动时它所依赖的服务已经就绪避免连接失败。密码安全示例中的密码是弱密码在实际生产或任何暴露在公网的环境下必须使用复杂的强密码并通过Docker Secrets或环境变量文件.env来管理不要硬编码在yml文件中。端口映射我们将MySQL的3306和Web Server的8081映射到了主机方便我们用本地客户端如Navicat连接数据库用浏览器访问Web UI。Executor的端口12321通常不需要对外暴露仅供内部通信。4. 数据库初始化与核心配置详解编排文件写好了但Azkaban需要的数据库表还没有创建。我们需要提供初始化SQL脚本。4.1 准备数据库初始化脚本在项目根目录下创建init-sql文件夹并在其中创建create-all-sql-3.90.0.sql文件可以从Azkaban官方GitHub仓库的sql目录下找到对应版本的脚本。这里我列出最核心的几个表创建语句并解释其作用。-- 在azkaban数据库中执行 CREATE TABLE executors ( id int(11) NOT NULL AUTO_INCREMENT, host varchar(64) NOT NULL, port int(11) NOT NULL, active tinyint(1) DEFAULT 0, PRIMARY KEY (id), UNIQUE KEY host_port (host,port) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; -- 这个表用于注册和管理所有活跃的Executor Server。Web Server通过读取这个表来分配任务。 CREATE TABLE projects ( id int(11) NOT NULL AUTO_INCREMENT, name varchar(64) NOT NULL, description mediumtext, create_time bigint(20) NOT NULL, last_modified_time bigint(20) NOT NULL, version int(11) DEFAULT NULL, enc_type tinyint(4) DEFAULT NULL, settings_blob longblob, PRIMARY KEY (id), UNIQUE KEY name (name) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; -- 存储所有上传的项目元信息。 CREATE TABLE project_versions ( project_id int(11) NOT NULL, version int(11) NOT NULL, upload_time bigint(20) NOT NULL, uploader varchar(64) NOT NULL, file_type varchar(16) DEFAULT NULL, file_name varchar(128) DEFAULT NULL, md5 varchar(128) DEFAULT NULL, num_chunks int(11) DEFAULT NULL, resource_id varchar(512) DEFAULT NULL, PRIMARY KEY (project_id,version), CONSTRAINT project_versions_ibfk_1 FOREIGN KEY (project_id) REFERENCES projects (id) ON DELETE CASCADE ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; -- 存储项目每个版本的上传信息Azkaban支持项目多版本管理。 -- 还有 project_flows, execution_flows, execution_jobs, project_permissions 等数十张表用于存储工作流定义、执行历史、权限等。将完整的SQL文件放入init-sql目录后Docker会在MySQL容器首次启动时自动执行这些脚本完成数据库的初始化。4.2 自定义Azkaban配置文件虽然镜像提供了默认配置但为了更贴合我们的需求比如时区、邮件报警我们需要自定义配置。我们在docker-compose.yml中已经将容器的conf目录挂载到了主机的web-conf和executor-conf。Web Server配置 (./web-conf/azkaban.properties):# Azkaban Personalization Settings azkaban.nameMyAzkabanCluster azkaban.labelMy Local Cluster azkaban.color#FF6600 # Azkaban Server Settings azkaban.webserver.port8081 azkaban.webserver.ssl.port8443 web.resource.dirweb/ default.timezone.idAsia/Shanghai # 设置时区为上海 # Azkaban Executor Settings azkaban.executor.port12321 executor.port12321 # Database Settings (与docker-compose环境变量对应) database.typemysql mysql.port3306 mysql.hostazkaban-db mysql.databaseazkaban mysql.userazkaban mysql.passwordAzkabanUserPass123! mysql.numconnections100 # Mail Settings (如果需要邮件通知需配置) mail.senderyour-emailgmail.com mail.hostsmtp.gmail.com mail.useryour-emailgmail.com mail.passwordyour-app-password # 注意使用应用专用密码 mail.tlstrue job.failure.emailreceiverexample.com job.success.emailreceiverexample.com # User Manager (使用默认的基于数据库的用户管理) user.manager.classazkaban.user.XmlUserManager user.manager.xml.fileconf/azkaban-users.xmlExecutor Server配置 (./executor-conf/azkaban.properties):# Executor Server azkaban.executor.port12321 executor.port12321 # Database Settings (必须与Web Server配置一致) database.typemysql mysql.port3306 mysql.hostazkaban-db mysql.databaseazkaban mysql.userazkaban mysql.passwordAzkabanUserPass123! mysql.numconnections100 # Executor specific executor.max_threads50 # 最大并发线程数 executor.flow.threads30 # 执行工作流的线程数实操心得配置文件中数据库连接信息、Executor端口等必须与docker-compose.yml中的环境变量以及容器间的网络可达性保持一致这是最常见的启动失败原因。另外邮件配置中的密码对于Gmail等现代邮箱需要使用“应用专用密码”而不是你的登录密码。5. 启动服务与验证安装配置完成后我们就可以启动整个Azkaban集群了。5.1 一键启动与日志观察在包含docker-compose.yml的目录下执行命令docker-compose up -d-d参数表示在后台运行。Docker会依次拉取镜像如果本地没有、创建网络、启动容器。启动后立即查看日志确认服务是否正常启动# 查看所有容器日志的尾部 docker-compose logs -f # 或者分别查看 docker-compose logs -f azkaban-webserver docker-compose logs -f azkaban-executor docker-compose logs -f azkaban-db你需要关注日志中是否有ERROR字样。正常的启动日志会显示数据库连接成功、服务在指定端口监听等信息。5.2 核心验证步骤服务启动后需要通过几步来验证安装是否真正成功。第一步检查容器状态docker-compose ps所有服务的状态State都应该是Up。第二步验证数据库表用MySQL客户端如DBeaver、命令行连接主机的3306端口用户azkaban密码是你设置的查看azkaban数据库。应该能看到一系列以executors,projects,execution_等开头的表被创建出来。这证明初始化SQL脚本已成功执行。第三步验证Web UI打开浏览器访问http://你的服务器IP:8081。你应该能看到Azkaban的登录界面。默认用户名密码在首次使用XmlUserManager且未配置azkaban-users.xml时默认用户是azkaban密码是azkaban。如果能看到登录页说明Web Server运行正常。第四步验证Executor注册登录Web UI后默认密码可能需要先修改点击顶部导航栏的Executor菜单。你应该能看到一个状态为Active的Executor它的地址就是我们在docker-compose.yml中配置的azkaban-executor:12321。这证明Web Server和Executor Server之间的通信是正常的并且Executor已经成功在数据库注册。第五步创建并运行一个测试工作流这是最终的验收测试。在Web UI上创建一个新项目例如叫TestProject。然后在本地准备两个简单的.job文件first.job:# first.job typecommand commandecho This is the first jobsecond.job:# second.job typecommand dependenciesfirst commandecho This is the second job, running after first将这两个文件打包成test-flow.zip在项目页面上传。上传后你可以在Flows页面看到名为test-flow的工作流它包含两个有依赖关系的任务。点击Execute Flow立即运行它。如果一切正常你会看到两个任务依次变成绿色成功并可以查看每个任务的控制台输出日志。6. 常见问题与排查技巧实录即使按照步骤操作你也可能会遇到一些问题。这里我总结几个最常见的坑和解决方法。6.1 数据库连接失败问题现象Web Server或Executor启动日志中大量报错提示Communications link failureAccess denied for user等。排查思路检查数据库容器是否健康docker-compose logs azkaban-db查看MySQL启动日志确认无错误且初始化完成。检查连接参数这是最常见的原因。请逐一核对docker-compose.yml中environment部分的MYSQL_*环境变量。挂载的azkaban.properties文件中的mysql.host,mysql.port,mysql.user,mysql.password。特别注意在配置文件中mysql.host必须填写Docker服务名azkaban-db而不是localhost或127.0.0.1因为是从Azkaban容器内部去连接MySQL容器。手动测试连接进入Azkaban Web Server容器内部用命令行工具测试。docker exec -it azkaban-webserver bash apt-get update apt-get install -y mysql-client # 如果容器内没有mysql客户端 mysql -hazkaban-db -uazkaban -pAzkabanUserPass123! azkaban如果能成功连接说明网络和认证是通的。6.2 Executor未出现在Web UI中问题现象Web UI可以访问但Executor页面为空或者Executor状态为Inactive。排查思路检查Executor日志docker-compose logs azkaban-executor看是否有数据库连接错误或启动错误。检查数据库executors表直接查询数据库看是否有记录插入。USE azkaban; SELECT * FROM executors;如果表中有记录但状态不是active1可能是Executor与Web Server心跳通信有问题。检查网络互通在Web Server容器内尝试ping或telnet到Executor的端口。docker exec -it azkaban-webserver bash telnet azkaban-executor 12321 # 或者用 nc如果不通检查docker-compose.yml中的网络配置确保两个服务在同一个自定义网络下并且AZKABAN_EXECUTOR_HOST环境变量设置正确。检查端口冲突确认主机和容器内部都没有其他进程占用12321端口。6.3 任务执行失败日志显示Cannot run program问题现象工作流任务执行失败点击日志看到类似Cannot run program “python”: error2, No such file or directory的错误。原因与解决Azkaban Executor执行命令时是在它自己的容器环境里。默认的azkaban/azkaban-executor-server镜像是一个精简的Java环境可能没有安装你任务所需的运行时如python、bash实际上bash是有的、hadoop命令等。解决方案自定义Executor镜像推荐编写Dockerfile基于官方镜像安装你需要的所有依赖。FROM azkaban/azkaban-executor-server:3.90.0 USER root RUN apt-get update apt-get install -y python3 python3-pip curl # 安装所需工具 USER azkaban # 切换回非root用户然后修改docker-compose.yml中azkaban-executor的image为你构建的新镜像。使用容器外执行配置Azkaban使用远程的SSH或其它执行器但这增加了复杂度。对于Docker部署自定义镜像是最干净、可复现的方式。6.4 时区问题问题现象Web UI上显示的任务调度时间、执行时间与本地时间不符。解决确保三个地方的时间一致宿主机时区。Docker容器时区在docker-compose.yml中每个服务的配置里可以添加environment: - TZAsia/Shanghai或者通过挂载/etc/localtime文件。Azkaban配置在Web Server的azkaban.properties中设置default.timezone.idAsia/Shanghai。6.5 Web UI访问缓慢或无法加载问题现象页面打开很慢或者静态资源CSS, JS加载失败。排查检查主机端口8081是否被防火墙阻止。检查Web Server容器的日志看是否有资源加载错误。如果是内网环境可能是镜像拉取慢。可以尝试提前拉取镜像docker-compose pull。7. 生产环境部署的进阶考量我们上面搭建的是一个用于学习和开发测试的“标准”Docker环境。如果要用于生产还需要考虑更多因素。1. 高可用HA部署Web Server高可用可以部署多个Web Server实例前面通过Nginx等负载均衡器做代理。多个Web Server连接同一个数据库它们之间通过数据库来同步状态。需要确保上传的项目文件存储在共享文件系统如NFS或对象存储如S3中以便所有Web Server都能访问。Executor高可用这是Azkaban的天然优势。你只需要启动多个Executor容器它们会自动注册到数据库。Web Server会从池中选取可用的Executor来执行任务。在docker-compose.yml中你可以使用docker-compose up -d --scale azkaban-executor3来快速启动3个Executor实例。2. 数据持久化与备份MySQL数据我们通过volumes挂载了./mysql_data务必确保这个目录所在的主机磁盘有足够的容量和备份策略。项目文件与日志Azkaban上传的ZIP包默认存储在数据库的project_versions表中resource_id指向文件系统路径。在生产环境中强烈建议配置外部存储。修改azkaban.properties中的azkaban.storage.type、azkaban.storage.hdfs.path或s3.bucket等参数将项目文件存储在HDFS或S3上实现持久化和共享。3. 安全加固修改默认密码第一时间修改默认的azkaban/azkaban用户密码并创建具有不同权限的用户。启用HTTPS为Web Server配置SSL证书避免密码在网络上明文传输。网络隔离将Azkaban集群部署在内网通过跳板机访问。Executor可能需要访问数据仓库如Hadoop集群需要规划好网络策略。使用专业的用户管理考虑集成LDAP或Active Directory替代默认的XML文件管理。4. 监控与告警服务健康监控监控Web Server、Executor、MySQL容器的运行状态CPU、内存、端口存活。业务监控利用Azkaban的API监控关键工作流的执行状态、耗时。可以编写脚本当工作流失败或超时时通过更强大的告警系统如Prometheus Alertmanager发送通知。日志收集将Azkaban的日志./web-logs,./executor-logs接入ELK或类似日志平台便于集中查询和分析。最后我个人在多次部署中最大的体会是一定要先在小规模环境比如一台开发机上用Docker把整个流程完全跑通形成一套稳定的配置模板和启动脚本。然后再将这套模板复制到生产服务器上根据生产环境的需求网络、存储、权限进行微调。这样能最大程度减少环境差异带来的“玄学”问题。Azkaban本身是一个稳定且强大的工具只要理解了它的运作原理并且保证各个组件之间的连接和配置正确无误它就能成为你数据流水线上最可靠的调度指挥官。
返回列表