运维实战:Ambari开发手册-DolphinScheduler集成实操

继我们被apache linkis社区翻牌子以后,收录了几篇文章,今天被小海豚社区官方翻牌子了哈,当然我们也有flink社区的大佬,贡献flink社区文章若干,那就今天继续更新一篇小海豚的文章哈,本文章来自涤生大数据老师,阿里巴巴技术大佬贡献

Ambari集成大数据组件系列

1.背景

DolphinScheduler本来提供了Ambari的安装程序,可以直接集成的。但是呢,Amabri停止维护了,DS对应的安装代码也就没再更新了。DS最新版本已经到3.x了,但是安装部署脚本依旧停留在DS1.3.8,这太Low了,一点都不适用。对此,咱们就来改改,来实现DS3.x在Ambari下的集成实现。

部署环境:Aliyun Linux 2.x(Centos7.x)


2.RPM制作

安装的方式有很多,但是个人还是比较喜欢AMbari的安装风格rpm,对此,依旧沿用此方法,先把我们的安装包封装成RPM。

2.1软件包准备

官网下载对应的软件包信息,切记!!不要选最新版本的,选次新版本。别问,问就是血的教训。

#下载地址
https://dolphinscheduler.apache.org/zh-cn/download

截止2023年4月,最新版本为3.1.5,咨询了社区那些,相对比较稳定的版本是3.1.2,对此,我们选择3.1.2来进行实际环境的安装。此处,我们需要进行rpmrebuild的环境的制作,可参考百度rpmbuild的使用。然后,将我们的DS软件,解压并拷贝到对应的编译目录,待用。特殊说明:

1.安装目录软件

后续的安装目录,沿用HDP的路径:
/usr/hdp/3.3.1.0-001/dolphinscheduler;

2.编译目录

rpmbulid打包成rpm时候用到的目录,主目录在

/root/rpmbuild/BUILDROOT/;

3.软件包目录

apache-dolphinscheduler-3.1.2-1.x86_64;

4.软件包内的安装目录

/usr/hdp/3.3.1.0-001/dolphinscheduler;

所以,整体的DS的解压完整的路径是:

/root/rpmbuild/BUILDROOT/apache-dolphinscheduler-3.1.2-1.x86_64/usr/hdp/3.3.1.0-001/dolphinscheduler


2.2SPEC文件编辑

SPEC文件,是RPM制作的说明文件,我们可以完全自己写,也可以抄一个现有的。对于看这个文档的小伙伴,直接抄我的即可。完整的内容如下:

# rpmrebuild autogenerated specfile

BuildRoot: /root/.tmp/rpmrebuild.15841/work/root
AutoProv: no
%undefine __find_provides
AutoReq: no
%undefine __find_requires
# Do not try autogenerate prereq/conflicts/obsoletes and check files
%undefine __check_files
%undefine __find_prereq
%undefine __find_conflicts
%undefine __find_obsoletes
# Be sure buildpolicy set to do nothing
%define __spec_install_post %{nil}
# Something that need for rpm-4.1


%define _missing_doc_files_terminate_build 0
#dummy
#dummy
#BUILDHOST:    ambaritest-vbj01c-2
#BUILDTIME:    Tue Mar 15 15:06:49 2022
#SOURCERPM:    apache-dolphinscheduler-2.0.1-2.src.rpm

#RPMVERSION:   4.11.3

#OS:           linux
#SIZE:           245615802
#ARCHIVESIZE:           245813056
#ARCH:         noarch
BuildArch:     x86_64
Name:          apache-dolphinscheduler
Version:       3.1.2
Release:       2
License:       (c) The Apache Software Foundation 
Group:         apache
Summary:       dolphinscheduler-dist
Distribution:  apache dolphinscheduler rpm

URL:           https://www.apache.org/
Vendor:        The Apache Software Foundation
Packager:      dolphinscheduler


Provides:      apache-dolphinscheduler = 3.1.2
Requires:      /bin/sh  
Requires:      /bin/sh  
Requires:      /bin/sh  
Requires:      /bin/sh  
#suggest
#enhance
%description
Dolphin Scheduler is a distributed and easy-to-expand visual DAG workflow scheduling system, dedicated
        to solving the complex dependencies in data processing, making the scheduling system out of the box for data
        processing.
%files
/usr/hdp/3.3.1.0-001/dolphinscheduler
/var/run/dolphinscheduler
/var/log/dolphinscheduler

%pre -p /bin/sh
mkdir -p /usr/hdp/3.3.1.0-001/dolphinscheduler
mkdir -p /var/run/dolphinscheduler
mkdir -p /var/log/dolphinscheduler

%post -p /bin/sh

%postun -p /bin/sh
rm -rf /usr/hdp/3.3.1.0-001/dolphinscheduler
rm -rf /var/run/dolphinscheduler
%changelog

里面的具体内容与细节,参考《RPMSEPC文件解读》,此处不在复述,能用就行了,要啥自行车。说明下,这个rpm的SPEC内容,是用DS官网的1.3.8版本RPM包改的。

2.3rpm制作

有了rpm包信息,有了SPEC说明文件,剩下的就简单了,直接使用rpmbulid-bb进行编辑即可。

[root@bigdata ~]# rpmbuild -bb /root/rpmbuild/SPECS/dolphinscheduler_1.spec


剩下的交给时间即可。



我们的rpm信息就制作完成了,在HDP的repo目录,创建一个dolphinscheduler的目录,拷贝进去

[root@bigdata ~]# cp /root/rpmbuild/RPMS/x86_64/apache-dolphinscheduler-3.1.2-3.x86_64.rpm /var/www/html/ambari/HDP/centos7/3.3.1.0-001/dolphinscheduler/

[root@bigdata ~]# cd /var/www/html/ambari/HDP/centos7/3.3.1.0-001/
[root@bigdata ~]# creatrepo ./

最后用yum验证下,是否能够正确识别到。

[root@bigdata ~]# yum list |grep apache-dolphinscheduler
apache-dolphinscheduler.x86_64          3.1.2-3                  HDP-3.3-repo-1

2.4长久之计

问题来了,如果下次DS升级版本,或者添加什么内容的。那么就需要重新制作RPM,以上操作再来一次。很明显,这种B格一看就不是大佬的作风。要玩,就长久点,代码能搞的,咱们就不动手。(有同样功能的,参考bigtop)我们的目的,是在DS有更新后,能够自动创建更新,创建rpm信息。自动检测一看就比较难,而且价值不大,咱们就不做了。我们把2.1-2.3的步骤全部自动化,还是有十分可观的价值的。

首先,需要解决如下几个问题:

· 编译目录:
/root/rpmbulid/BULIDROOT/.. ,这个目录下的文件回自动删除,我们每次构建都需要创建一次。

· 多版本支持,能不能每次自动更新release信息,自动保存历史记录。

带着疑惑,咋们就开始出发。

· 首先第一点,解决缓存文件被删除,无长久保存的问题。关于这个问题,从两方面进行考虑:1. 创建一个长久地址,每次封装的时候,拷贝次文件夹的内容来生成临时目录;2. 修改spec内容中的file部分,不写详细的文件列表,只写目录即可(2.2 已经修改)。

· 再然后就是release的更新了。这个就简单了,分为现有版本的获取与SPEC的更新。获取可以通过扫描repo中的文件列表,提取固定字段来获取。比如:
apache-dolphinscheduler-3.1.2-3.x86_64.rpm中的3就是Relase的版本,查询 + 排序即可搞定。Relase的替换,也简单,拿到这个数字后,加1后,使用sed命令来进行替换即可。

最后,再来自己加点难度。比如,最好适用hdp的其他程序,和变量相关的,丢前面。尽量使用函数进行封装等。

接下来,上完整代码

#!/bin/bash
# 用于ambari管理平台自动打包dolphinscheduler程序。
#===============
#定义运行环境地址
#----------------
rpm_file_path="/var/www/html/ambari/HDP/centos7/3.3.1.0-001/dolphinscheduler"
buildroot_dir="/root/rpmbuild/BUILDROOT"
src_path="/var/www/html/ambarisrc/rpm/dolphinscheduler"
version="3.1.2"
spec_dir="/root/rpmbuild/SPECS/dolphinscheduler"

#===============
# 获取各种运行变量信息
#----------------
# 获取版本信息
old_release_num=$(ls ${rpm_file_path} |grep dolphinscheduler |grep ${version} |awk -F '-' '{print $NF}'|awk -F '.' '{print $1}' |sort |tail -n 1)
release_num=$((old_release_num+1))
os_type=$(uname -a |awk '{print $12}')

function spec_config() {
  #通过变量获取rpm名
  rpm_file_name=$1
  spec_file_name=${rpm_file_name}_${release_num}".spec"
  #获取spec信息
  if [ ${spec_dir}/${spec_file_name} ];then
    rm -rf ${spec_dir}/${spec_file_name}
  fi
  cp ${spec_dir}/${rpm_file_name}.spec ${spec_dir}/${spec_file_name}
  #更新release版本信息
  sed -i "s/^Release:.*/Release:       ${release_num}/g" ${spec_dir}/${spec_file_name}
}

function buildroot_init() {
  #初始化最初的代码目录,只运行一次
  #源代码目录地址:/var/www/html/ambarisrc/rpm/dolphinscheduler
  cd ${src_path}
  for rpm_file_list in $(ls ${rpm_file_path}|grep ${version})
  do
    #获取release 版本信息
    rpm_file_name=$(echo ${rpm_file_list} |awk -F "-${version}" '{print $1}')
    echo ${rpm_file_name}
    mkdir -p ${src_path}/${rpm_file_name};cd ${src_path}/${rpm_file_name}
    rpm2cpio ${rpm_file_path}/${rpm_file_name}-${version}-${old_release_num}.${os_type}.rpm |cpio -idv
  done
}

function buildroot_create() {
  #生成对应的编辑目录
  echo "获取软件包名为: ${rpm_file_name}"
  rpm_file_name=$1
  rpm_buildroot_dir=${rpm_file_name}-${version}-${release_num}.${os_type}
  echo "软件包编译安装名:$buildroot_dir/$rpm_buildroot_dir"
  if [ ! -z ${buildroot_dir}/${rpm_buildroot_dir} ];then
    mkdir ${buildroot_dir}/${rpm_buildroot_dir}
    #使用现有rpm包信息,直接覆盖
  fi
  cd ${buildroot_dir}/${rpm_buildroot_dir}
  echo "使用更新代码替换原有包信息:${src_path}/${rpm_file_name} ${buildroot_dir}/${rpm_buildroot_dir}"
  cp -raf ${src_path}/${rpm_file_name}/* ${buildroot_dir}/${rpm_buildroot_dir}
  echo "执行编译命令:rpmbuild -bb ${spec_dir}/${rpm_file_name}_${release_num}.spec"
  rpmbuild -bb ${spec_dir}/${rpm_file_name}_${release_num}".spec"
  echo "拷贝编译包更新到yum源:${rpm_file_path}"
  cp /root/rpmbuild/RPMS/${os_type}/${rpm_file_name}-${version}-${release_num}.${os_type}.rpm ${rpm_file_path}
}

for rpm_file_name in $(ls ${rpm_file_path} |grep ${version} |awk -F "-${version}" '{print $1}' |uniq)
do
  #spec配置生成
  spec_config ${rpm_file_name}
  buildroot_create ${rpm_file_name}
done

cd ${rpm_file_path}/../
createrepo ./



?


代码解读:第一段:各种变量的定义,如果其他程序,改路径和版本即可。比如ambari的打包,修改配置如下

rpm_file_path="/var/www/html/ambari/ambari/centos7/2.7.6.3-0/ambari"
buildroot_dir="/root/rpmbuild/BUILDROOT"
src_path="/var/www/html/ambarisrc/rpm/ambari"
version="2.7.6.0"
spec_dir="/root/rpmbuild/SPECS/ambari"

第二段:获取版本信息。获取现在的最新版本信息;函数:spec_config。此函数,先拷贝一个模板spec文件,步骤2.2做好的东西,然后使用sed进行版本的替换

sed -i "s/^Release:.*/Release:       ${release_num}/g" ${spec_dir}/${spec_file_name}

函数:buildroot_initx0;这个是为了方便创建永久保存的目录:${src_path}。就第一次运行的时候运行;

函数:buildroot_createx0;,进行rpm的封装。从${src_path}路径拷贝最新的文件到缓存目录,然后运行rpmbuild-bb进行实际rpm的制作;

整体函数使用for循环,进行文件列表循环,以适应多个包的更新;

最后的最后:更新rpm信息:createrepo./演示示例:

有了此代码后,更新就简单多了。比如我们想修改DS的存储为Mysql,需要添加mysql-connection-java.jar到DS各个程序的lib中。

首先第一步,下载jar包:
mysql-connector-java-8.0.26.jar

第二步:拷贝此jar包到alert-server/libs,api-server/libs,master-server/libs,worker-server/libs

第三步:运行程序。就会自动封装:
apache-dolphinscheduler-3.1.2-4.x86_64.rpm

3.Dolphin集成

为了调试DS的安装,本人按照官网的安装教程,使用自带的安装程序install.shN次后得出的结论。有兴趣的小伙伴,可以自己折腾下。

3.1DS服务架构

盗的一个架构图,一看就比较复杂。


?



不过从图中可以看出,有ZK,有API、UI、DB、Alert、Master、Worker。这些,其实就是我们安装部署过程中需要运行的程序。安装DS前,需要有ZK集群以及一个Mysql。UI页面是封装到API中的,后面的Alert,Master,Worker每个作为单独的程序来运行。那么对于我们自动化部署,就是要实现DS的四个程序的启动。

3.2代码结构

有了架构图,大概对这个软件有了大概的意思,但是这东西来得不实际,很飘。涉及到具体部署的时候,拿来没啥用。最有用的,还是看安装的压缩包。第一层目录,直接拆分了角色了,一下就清爽多了,一看就懂了,每个角色程序,一个文件夹。

[root@bigdata-pricloud-mirrors dolphinscheduler]# ll
总用量 184
drwxr-xr-x. 5 root root  4096 4月  12 16:12 alert-server
drwxr-xr-x. 6 root root  4096 4月  12 16:12 api-server
drwxr-xr-x. 3 root root  4096 4月   7 16:05 bin
-rw-r--r--. 1 root root 53845 4月   7 16:05 LICENSE
drwxr-xr-x. 4 root root 20480 4月   7 16:05 licenses
drwxr-xr-x. 5 root root  4096 4月  12 16:12 master-server
-rw-r--r--. 1 root root 77523 4月   7 16:05 NOTICE
drwxr-xr-x. 5 root root  4096 4月  21 11:56 standalone-server
drwxr-xr-x. 6 root root  4096 4月   7 16:05 tools
drwxr-xr-x. 4 root root  4096 4月   7 16:05 ui
drwxr-xr-x. 5 root root  4096 4月  12 16:12 worker-server


随便进一个角色的目录:api-server

[root@bigdata-pricloud-mirrors api-server]# ll
总用量 36
drwxr-xr-x. 2 root root  4096 4月   7 16:05 bin
drwxr-xr-x. 2 root root  4096 4月   7 16:05 conf
drwxr-xr-x. 2 root root 24576 4月   7 16:05 libs
lrwxrwxrwx. 1 root root    25 4月  12 16:11 logs -> /var/log/dolphinscheduler
drwxr-xr-x. 4 root root  4096 4月   7 16:05 ui
[root@bigdata-pricloud-mirrors api-server]# ll bin/
总用量 4
-rw-r--r--. 1 root root 1400 4月   7 16:05 start.sh
[root@bigdata-pricloud-mirrors api-server]# ll conf/
总用量 32
-rw-r--r--. 1 root root 6198 4月   7 16:05 application.yaml
-rw-r--r--. 1 root root  987 4月   7 16:05 bootstrap.yaml
-rw-r--r--. 1 root root 5797 4月   7 16:05 common.properties
-rw-r--r--. 1 root root 2879 4月   7 16:05 dolphinscheduler_env.sh
-rw-r--r--. 1 root root 2587 4月   7 16:05 logback-spring.xml
-rw-r--r--. 1 root root 1385 4月   7 16:05 task-type-config.yaml

和这个角色相关的东西,大体有以下目录:

bin/start.sh 
#启动命令,写死了,每个下面的,都是单独起单个进程的。比如,api下的,就是起api-server的
libs
#下面是一堆依赖文件
conf 
#下面是一堆配置文件,具体的配置信息,后面实现的时候来分析
logs 
#日志目录,这个不要改,不要改,改了地址后,没法在线刷新日志。但是可以用超链接换到其他地方。
ui 
#这个只有api有,其他的没有。
这样的目录结构,conf、bin 目录下的文件,在不同的服务目录下面,都是一样,一样的。只需要根据不同的内容,改配置即可。

除了服务以外,还有一个特殊的目录bin/env,这个下面有两个文件,在安装的时候需要进行配置的修改,用于安装,初始化的时候需要,也要做对应的修改。

[root@bigdata ]# ll bin/env/
总用量 8
-rwxr-xr-x. 1 root root 2879 4月   7 16:05 dolphinscheduler_env.sh
-rwxr-xr-x. 1 root root 3816 4月   7 16:05 install_env.sh

3.3安装实现

目录结构看完了,部署大体结构也知道了,接下来就要开始进行实际的自动化实现了。

3.3.1服务定义:metainfo.xml

这个是定义服务的程序,定义软件版本,安装的包信息,以及配置依赖信息。此处只贴了些案例,没贴全。模块一:服务定义

    DOLPHIN
    Dolphin Scheduler
    分布式易扩展的可视化DAG工作流任务调度系统
    3.1.2


这个的效果图,在服务添加页面展示:


?


模块二:程序定义

主要定义包含哪些程序,以及程序的维护程序,定义等等各种东西,一共有四个:DOLPHIN_MASTER,DOLPHIN_WORKERx0;,DOLPHIN_APIx0;,DOLPHIN_ALERTx0;。单个参考如下,具体细节百度知。

                  
                    DOLPHIN_MASTER
                    DS Master
                    MASTER
                    1+
                    
                        
                        PYTHON
                        600
                    
                

模块三:安装rpm定义

这边定义需要安装的rpm程序,以及系统。我们这里能支持的是Centos7.x/8.x,Redha7.x/8.x,KylinV10,Anolis8.x,直接写个any先用着吧。

           
                
                    any
                    
                        
                            apache-dolphinscheduler*
                        
                    
                
            

剩下的,还有点内容,后期加吧,这里贴一个完成的图。



    2.0
    
        
            DOLPHIN
            Dolphin Scheduler
            分布式易扩展的可视化DAG工作流任务调度系统
            3.1.2
            
                
                    DOLPHIN_MASTER
                    DS Master
                    MASTER
                    1+
                    
                        
                        PYTHON
                        600
                    
                
                
                    DOLPHIN_WORKER
                    DS Worker
                    SLAVE
                    1+
                    
                        
                        PYTHON
                        600
                    
                

                
                    DOLPHIN_ALERT
                    DS Alert
                    SLAVE
                    1+
                    
                        
                        PYTHON
                        600
                    
                

                
                    DOLPHIN_API
                    DS Api
                    SLAVE
                    1+
                    
                        
                        PYTHON
                        600
                    
                
            

            
                ZOOKEEPER
            

            
                
                    any
                    
                        
                            apache-dolphinscheduler*
                        
                    
                
            

            
                dolphin_env
                common.properties
                dolphin-jvm
            
            
                
                    theme.json
                    true
                
            
            quicklinks
            
                
                    quicklinks.json
                    true
                
            
        
    

3.3.2程序安装:master_install.py

上面服务定义好了,接下来就进行软件的安装流程。就是看服务定义中的“
scripts/dolphin_master_service.pyx0;”程序内容。这个里面呢,就是定义各个软件的安装与启动程序。以下,是经过N多次改版过后的实际安装代码。

# -*- coding: utf-8 -*-

import time
from resource_management import *
from dolphin_env import dolphin_env

class DolphinMasterService(Script):
    def install(self, env):
        import params
        env.set_params(params)
        self.install_packages(env)
        with open("/etc/passwd") as f:
            userlist = []
            for line in f:
                line=line.strip()
                vec =line.split(':')
                userlist.append(vec[0])
            if params.dolphin_user in userlist:
                Logger.info("Dolphin Deploy User : " + params.dolphin_user + "already exists ")
            else:
                Execute(('useradd', params.dolphin_user))
        Execute(('sed -i \'/^' + params.dolphin_user + '/d\' /etc/sudoers'))
        Execute(('sed -i \'$a' + params.dolphin_user + '  ALL=(ALL)  NOPASSWD: NOPASSWD: ALL\' /etc/sudoers'))

        Execute(('mkdir -p  ' + " " + params.dolphin_home))
        Execute(('mkdir -p  ' + " " + params.dolphin_log_dir))
        Execute(('mkdir -p  ' + " " + params.dolphin_pidfile_dir))

        Execute(('chown -R ' + params.dolphin_user + ":" + params.dolphin_group + " " + params.dolphin_home))
        Execute(('chown -R ' + params.dolphin_user + ":" + params.dolphin_group + " " + params.dolphin_log_dir))
        Execute(('chown -R ' + params.dolphin_user + ":" + params.dolphin_group + " " + params.dolphin_pidfile_dir))
        Execute(('chown -R ' + params.dolphin_user + ":" + params.dolphin_group + "/var/log/dolphinscheduler"))

        Execute(('rm -f ' + " " + params.dolphin_home+"/master-server/conf/core-site.xml"))
        Execute(('ln -s /etc/hadoop/conf/core-site.xml' + " " + params.dolphin_home+"/master-server/conf/core-site.xml"))
        Execute(('rm -f ' + " " + params.dolphin_home+"/master-server/conf/hdfs-site.xml"))
        Execute(('ln -s /etc/hadoop/conf/hdfs-site.xml' + " " + params.dolphin_home+"/master-server/conf/hdfs-site.xml"))


    def configure(self, env):
        import params
        params.pika_slave = True
        env.set_params(params)
        dolphin_env()

    def start(self, env):
        import params
        env.set_params(params)
        self.configure(env)
        Execute(('sed -i \'/^' + params.dolphin_user + '/d\' /etc/sudoers'))
        Execute(('sed -i \'$a' + params.dolphin_user + '  ALL=(ALL)  NOPASSWD: NOPASSWD: ALL\' /etc/sudoers'))

        no_op_test = format("ls {dolphin_pidfile_dir}/master-server.pid >/dev/null 2>&1 && ps `cat {dolphin_pidfile_dir}/master-server.pid` | grep `cat {dolphin_pidfile_dir}/master-server.pid` >/dev/null 2>&1")
        start_cmd = format("sh " + params.dolphin_bin_dir + "/dolphinscheduler-daemon.sh start master-server")
        Execute(start_cmd, user=params.dolphin_user, not_if=no_op_test)

    def stop(self, env):
        import params
        env.set_params(params)
        stop_cmd = format("sh " + params.dolphin_bin_dir + "/dolphinscheduler-daemon.sh stop master-server")
        Execute(stop_cmd, user=params.dolphin_user)
        time.sleep(5)

    def status(self, env):
        import params
        env.set_params(params)
        check_process_status(params.dolphin_pidfile_dir + "/master-server/pid")


if __name__ == "__main__":
    DolphinMasterService().execute()


具体内容,其中,服务安装的程序在下面代码的:install_packages中,会根据3.1.1中,os处定义的内容,来进行rpm包的安装,此处实际执行命令:
yuminstall-yapache-dolphinscheduler*

def install(self, env):
        import params
        env.set_params(params)
        self.install_packages(env)

其他安装程序,类似,只是需要修改对应的路径和文件名信息


?


特殊说明下,最开始的程序,需要做系统的初始化,沿用1.3.8版本的初始化逻辑,把数据库的初始化放在api的启动程序中:dolphin_api_service.pyx0;

     def start(self, env):
        import params
        env.set_params(params)
        self.configure(env)
        Execute(('sed -i \'/^' + params.dolphin_user + '/d\' /etc/sudoers'))
        Execute(('sed -i \'$a' + params.dolphin_user + '  ALL=(ALL)  NOPASSWD: NOPASSWD: ALL\' /etc/sudoers'))

        #init
        init_cmd=format("sh " + params.dolphin_home + "/tools/bin/upgrade-schema.sh")
        Execute(init_cmd, user=params.dolphin_user)

        no_op_test = format("ls {dolphin_pidfile_dir}/api-server.pid >/dev/null 2>&1 && ps `cat {dolphin_pidfile_dir}/api-server.pid` | grep `cat {dolphin_pidfile_dir}/api-server.pid` >/dev/null 2>&1")

        start_cmd = format("sh " + params.dolphin_bin_dir + "/dolphinscheduler-daemon.sh start api-server")
        Execute(start_cmd, user=params.dolphin_user, not_if=no_op_test)



3.4配置管理

你以为上面写好就能用了?肤浅了,格局一定要打开。安装才是第一步,怎么做配置的更新、管理才是一个好的部署平台。最好自动化安装,点一下需要安装的程序,剩下的全部根据集群,系统来默认最优配置设置,这才是一个大佬应该写出来的自动化程序。其实,3.3中的程序,已经包含了配置的更新,其中,每个控制模块前的importparams和set-params即配置的读取与更新程序。

  def install(self, env):
        import params
        env.set_params(params)


以上代码,对应的程序



3.4.1配置解读

在我N多次的安装、卸载,对比配置等各个操作手段后,得出了以下内容。需要修改的配置内容如下,以ds的安装相对路径进行文件的书写。

#各种允许环境的指定,以及DB的环境信息,其他环境全部通用。
./bin/env/dolphinscheduler_env.sh
#各种软件角色地址的部署地址信息。以及一些hdfs的配置...
./bin/env/install_env.sh
#各个服务相关的配置,定义数据库信息,ZK信息,以及端口信息。
./api-server/conf/application.yaml
#这个组件里面的配置不同
./api-server/conf/bootstrap.yaml
#启动程序名的定义,这个不需要做任何修改。
./api-server/conf/common.properties
#主要的配置信息,数据库,存储地址啊,等等相关的。
./api-server/conf/logback-spring.xml
#日志路径相关的,不用改内容,尝试改过,然后功能不正常了。所以还是用超链接来实现log的修改吧。
./api-server/conf/task-type-config.yaml
#支持的调度定义,默认即可。

差不多,这些配置都得改吧。

3.4.2confiuration配置管理

对于配置相关的管理,在Amabri中,是通过一个叫configuration相关的xml进行设置的。这里以dolphin-env.xml比如配置
./bin/env/dolphinscheduler_env.sh中的一个配置

# Database related configuration, set database type, username and password
export DATABASE=${DATABASE:-mysql}
export SPRING_PROFILES_ACTIVE="dolphin"
export SPRING_DATASOURCE_URL="jdbc:mysql://127.0.0.1:3306/pricloud_dolphin?useUnicode=true&characterEncoding=UTF-8&useSSL=false"
export SPRING_DATASOURCE_USERNAME="admin"
export SPRING_DATASOURCE_PASSWORD="password"


其中在configuration中的相关定义如下:


  dolphin.database.type
  mysql
  选择海豚调度的数据库类型:Mysql/PG 2选一,默认Mysql
  数据库类型
  
    value-list
    
      
        mysql
        
      
      
        postgresql
        
      
    
    1
  
  



  dolphin.database.db
  dolphin
  数据库名
  


特殊说明,这种类型不太一样,数据库类型提供的是一个多选,提供mysql个PG的单选按钮,数据库是一个字符串,不用高级设置。成品大概如下:


?



?



特殊说明下,我是代码搞好后再写的文档,截图和xml中的定义,不太一样。

3.4.2params配已置读取

接下来,数据的定义有了,那就需要进行数据的读取了,在web页面,如果修改了配置,需要将这个配置写入到具体的配置文件中。怎么来读取这个配置呢?这个写入在脚本parms.py中,先来一个案例:

#==================================
# dolphin env
#==================================
dolphin_database_type = config['configurations']['dolphin-env']['dolphin.database.type']
dolphin_database_db = config['configurations']['dolphin-env']['dolphin.database.db']
dolphin_database_username = config['configurations']['dolphin-env']['dolphin.database.username']
dolphin_database_password = config['configurations']['dolphin-env']['dolphin.database.password']

if 'mysql' == dolphin_database_config['dolphin_database_type']:
    dolphin_database_config['dolphin_database_url'] = 'jdbc:mysql://'...
    dolphin_database_driver = 'com.mysql.cj.jdbc.Driver'
    driverDelegateClass = 'org.quartz.impl.jdbcjobstore.StdJDBCDelegate'
    dolphin_database_url = 'jdbc:mysql://'...
else:
    dolphin_database_config['dolphin_database_driver'] = 'org.postgresql.Driver'
    dolphin_database_config['driverDelegateClass'] = 'org.quartz.impl.jdbcjobstore.PostgreSQLDelegate'
    dolphin_database_config['dolphin_database_url'] = 'jdbc:postgresql://'...


案例解读,这里就是定义各种变量信息的。比如读取“dolphin-envx0;.xml”中关于mysql类型的定义为:

dolphin_database_type = config['configurations']['dolphin-env']['dolphin.database.type']

玩得再花一点,就再写点判断,这样就可以根据一个选择来进行不同数据的定义。除了这种定义的以外,还有和集群相关的配置,比如ZK相关的,可以根据ZK集群的信息,自动读取ZK配置,具体写法如下:

ZookeeperServerHostInfo = config['clusterHostInfo']['zookeeper_server_hosts']

if len(ZookeeperServerHostInfo) > 0 and "clientPort" in config["configurations"]['zoo.cfg']:
    clientPort = config['configurations']['zoo.cfg']['clientPort']
    zookeeperPort = ":" + clientPort + ","
    dolphin_registry_addr = zookeeperPort.join(ZookeeperServerHostInfo) + ":" + clientPort
    Logger.info("dolphin_registry_addr : " + str(dolphin_registry_addr))

剩下的,自己更具配置的内容添加即可。

3.4.3Templates模板生成

数据配置定义了,数据配置的方法读取方法获取了,接下来,问题来了:怎么把这些信息写入到具体配置里面呢?这里,使用Templates模板来进行配置文档的编辑。此处核心就是配置使用{{变量名}}来进行替换首先用application.yaml来打个样。

spring:
  config:
    activate:
      on-profile: {{application_jdbc_type}}
  datasource:
    driver-class-name: {{application_jdbc_driver}}
    url: {{application_jdbc_url}}
    username: {{application_jdbc_username}}
    password: {{application_jdbc_password}}


其中:{{application_jdbc_type}}等,都是parms.py中进行的变量获取。整体套路就是这样,剩下的就是对比不同的配置,来制作多个模板。全部的信息如下:


?




这里只是完成了一半,另外的一半,需要定义这些模板文件,需要写到哪些配置里面。这里的话,写在了dolphin_env.py中,这里面主要进行文件夹的创建,以及配置的更新。

def dolphin_env():
    import params

Directory(params.dolphin_pidfile_dir,
              mode=0755,
              owner=params.dolphin_user,
              group=params.dolphin_group,
              create_parents=True
)

    File(format(params.dolphin_home + '/alert-server/conf/application.yaml'),
         mode=0644,
         content=Template("application-alter.yaml.j2"),
         owner=params.dolphin_user,
         group=params.dolphin_group
         )

    File(format(params.dolphin_home + '/api-server/conf/application.yaml'),
         mode=0644,
         content=Template("application-api.yaml.j2"),
         owner=params.dolphin_user,
         group=params.dolphin_group
         )


以上为案例,一看就懂,不做解释。剩下的就是体力劳动。到此,已经可用了,写到这里,自动化部署就已经完成了。但是,还是那句话,格局一定要打开,要最求卓越。


?


3.5themes视觉优化

以下两个图,那个好看?很明显,不做选择题,咋们全都要。只是,上图已经实现了,接下来进行下图的实现。


?



?


其中,下图的内容需要使用到的是Ambari提供的Themes模板,类似于一个页面编辑框的工具,可以将单单选,多选文本的换个花样来展示。

3.5.1themes解读

首先来看看themes的写法,大概长这样的,主题包含三个目录。layouts,placement和widgets

{
  "name": "default",
  "description": "Default theme for Dolphin Scheduler service",
  "configuration": {
    "layouts": [
      {
        "name": "default",
        "tabs": [
          {
            "name": "settings",
            "display-name": "Settings",
            "layout": {
              "tab-rows": "4",
              "tab-columns": "3",
              "sections": [
                {
                  "name": "dolphin-env-config",
                  "display-name": "海豚环境配置",
                  "row-index": "0",
                  "column-index": "0",
                  "row-span": "1",
                  "column-span": "2",
                  "subsections": [
                    {
                      "name": "env-row1-col1",
                      "display-name": "部署用户信息",
                      "row-index": "0",
                      "column-index": "0",
                      "row-span": "1",
                      "column-span": "1"
                    },...
              ],
              "placement": {
                "configuration-layout": "default",
                "configs": [
                  {
                    "config": "dolphin-env/dolphin.user",
                    "subsection-name": "env-row1-col1"
                  }
                  ...
                ]
              },
              "widgets": [
                {
                  "config": "dolphin-env/dolphin.user",
                  "widget": {
                    "type": "text-field"
                  }


layouts:是对整体页面做拆分,做页面排布。并对每个页面命名和编号。页面的布局内容如下:


?




placement,是对定义在框框中,填入什么样的内容。比如JVM处,大题填以下内容:


?

widgets,则是定义数据的规范,和显示的格式,这个需要和对应的xml中的配置遥相呼应。比如:text-fieldx0;文本框,就是单纯的框框格式,比如环境配置信息的


?


togglex0; 二选一的拖拽框,比如,是否开启kerbers配置的选项




?


combox0;,下拉框,用于多选一的选择,比如数据库类型,文件存储类型等。




大体介绍完了,接下来进行实际的实现。

3.5.2目录配置

我们在最开始的地方<0,0>来进行环境配置的设置。打算提供,用户账号、组,以及环境变量的定义。这里采用的是大框套小框来进行实现的,整体页面布局就,及其对应的编码就变成了这样。


?




接下来就进行具体的框框的定义。在configurationx0;.layoutsx0;.tabs.x0;sectionsx0;处进行定义,从外部定义到内部,逐级定义。

        {
                  "name": "dolphin-env-config",
                  "display-name": "海豚环境配置",
                  "row-index": "0",
                  "column-index": "0",
                  "row-span": "1",
                  "column-span": "2",
                  "subsections": [
                    {
                      "name": "env-row1-col1",
                      "display-name": "部署用户信息",
                      "row-index": "0",
                      "column-index": "0",
                      "row-span": "1",
                      "column-span": "1"
                    }


接下来,定义这个框里面需要输入的数据:账号、组,以及环境变量;在配置位置:configurationx0;.placementx0;x0;.configsx0;

  "placement": {
      "configuration-layout": "default",
      "configs": [
        {
          "config": "dolphin-env/dolphin.user",
          "subsection-name": "env-row1-col1"
        },
        {
          "config": "dolphin-env/dolphin.group",
          "subsection-name": "env-row1-col1"
        },
        {
          "config": "dolphin-env/dolphinscheduler-env-content",
          "subsection-name": "env-row1-col1"
        }

最后,定义处这些内容的数据展示格式。在配置configuration.widgetsx0;处

 "widgets": [
      {
        "config": "dolphin-env/dolphin.user",
        "widget": {
          "type": "text-field"
        }
      },
      {
        "config": "dolphin-env/dolphin.group",
        "widget": {
          "type": "text-field"
        }
      },
      {
        "config": "dolphin-env/dolphinscheduler-env-content",
        "widget": {
          "type": "text-area"
        }
      },


这里都是text格式,对应的一个xml案例,dolphin-env.xml关于部署用户dolphin.user的定义。


  dolphin.user
  dolphin
  安装哪个用户并管理海豚调度器
  部署用户
  


通过以上,操作,最后的效果图如下。


?

3.5.2JVM配置

同上,依旧来进行JVM的设置,复制3.5.1开头的内容,先来进行JVM的位置信息设置。他的位置是<0,1>;

{
  "name": "env-row1-col2",
  "display-name": "JVM信息配置",
  "row-index": "0",
  "column-index": "1",
  "row-span": "1",
  "column-span": "1"
}

接下来进行对应数据的填充与设置,同上,这里只提供一些参数的设置,其他的,参考排布即可。

  {
          "config": "dolphin-jvm/alert.jvm.xmx",
          "subsection-name": "env-row1-col2"
        },
        {
          "config": "dolphin-jvm/api.jvm.xmx",
          "subsection-name": "env-row1-col2"
        },

与上图不同的是,这里采用拉条的方式来进行数据的数据的设置,左右横拉,实现JVM的设置。其中,在themes中的数据定义如下:

 {
        "config": "dolphin-jvm/alert.jvm.xmx",
        "widget": {
          "type": "slider",
          "units": [
            {
              "unit-name": "GB"
            }
          ]
        }
      },

对应的xml信息,在配置dolphin-jvm.xml中,每次可调节1G大小,允许设置的范围为1-4G,可以根据具体的配置设置。


  alert.jvm.xmx
  1
  Alert JVM大小
  Alert 预分配的JVM使用的最大内存量
    如果您希望输入一个高于滑块上最大值的值,请单击鼠标悬停在设置上时出现的铅笔,并忽略不建议输入更高的值。
  
  
    int
    1
    4
    1
    GB
  

最后效果案例效果。


?


3.5.3数据库配置

数据库的,同上。不整废话,都一样的东西。效果图如下:


?



3.5.4存储类型选择

数据存储类型的时候,这个有点不同了,因为添加了可选,并且可选进行数据内容的展示。先来看效果图:


?







?





选择HDFS为存储后,对应的配置如图左上;选择Null的效果如右上;AwsS3及其同类产品的如左下;阿里云OSS的如右下。这个是怎么实现的呢?关于图表框的定义,同上。不在叙述。接下来就是关于具体内容的选择,这里设置不一样了。首选,下拉框,选择存储格式,下面定义数据的输入

{
  "config": "common.properties/resource.storage.type",
  "subsection-name": "dynamic-row1-col1"
}

对应的数据格式为:

  {
        "config": "common.properties/resource.storage.type",
        "widget": {
          "type": "combo"
        }
      }

对应的xml定义文件:common.properties.xml,这是一个多选


  resource.storage.type
  HDFS
  
    资源存储类型: HDFS , S3 , OSS , NONE
  
  资源存储类型
  
    value-list
    
      
        HDFS
        
      
      
        S3
        
      
      
        OSS
        
      
      
        NONE
        
      
    
    1
  
  

这样,下拉框就完成了。接下来,怎么根据下拉框的格式来进行相应配置的选择呢?其实,这个的重点就是判断+可显示字段的信息标记。贴代码就懂了。在数据展示处:

{
  "config": "common.properties/resource.alibaba.cloud.oss.endpoint",
  "subsection-name": "dynamic-row1-col1",
  "depends-on": [
    {
      "configs":[
        "common.properties/resource.storage.type"
      ],
      "if": "${common.properties/resource.storage.type} === OSS",
      "then": {
        "property_value_attributes": {
          "visible": true
        }
      },
      "else": {
        "property_value_attributes": {
          "visible": false
        }
      }
    }
  ]
},
{
  "config": "common.properties/resource.hdfs.root.user",
  "subsection-name": "dynamic-row1-col1",
  "depends-on": [
    {
      "configs":[
        "common.properties/resource.storage.type"
      ],
      "if": "${common.properties/resource.storage.type} === HDFS",
      "then": {
        "property_value_attributes": {
          "visible": true
        }
      },
      "else": {
        "property_value_attributes": {
          "visible": false
        }
      }
    }
  ]
},

在每个选项中,添加一个判断,只有当type类型相关的时候,显示标记位再设置是否显示。这样就完事儿了。

3.5.5Kerberos&Wechat

这两个功能还没设置好,先把功能页面开启来先。



数据框,及其框中数据编辑都同上,不在叙述。

不同就是数据的定义:

  {
        "config": "common.properties/hadoop.security.authentication.startup.state",
        "widget": {
          "type": "toggle"
        }
      },
      {
        "config": "common.properties/enterprise.wechat.enable",
        "widget": {
          "type": "toggle"
        }
      }


对应的XML数据定义,剩下的自己复制改。


  hadoop.security.authentication.startup.state
  false
  功能未开发完毕,别开启
  是否开启Kerberos认证
  
    value-list
    
      
        true
        
      
      
        false
        
      
    
    1
  
  
通过以上一波操作,就全部完成了themes的定义,重点配置丢这里,看起来就舒服了。这样,重点配置在Setting页面,详细配置在advance页面。

3.6超链接实现

DS给提供了Web页面,最好的话,再搞个超链接,点击即可访问。说干就看,先看效果图


?


这个功能一共需求两个东东。

第一个,服务定义metainfo.xml中,需要添加关于超链接的定义。

      
                
                    quicklinks.json
                    true
                
            

在新建文件夹quicklinks,并在下面新建文件quicklinks.json案例数据如下,具体内容,自己百度。

{
  "name": "default",
  "description": "default quick links configuration",
  "configuration": {
    "protocol":
    {
      "type":"http"
    },
    "links": [
      {
        "name": "dolphin-application-ui",
        "label": "DolphinApplication UI",
        "requires_user_name": "false",
        "component_name": "DOLPHIN_API",
        "url": "%@://%@:%@/dolphinscheduler/ui/",
        "port":{
          "http_property": "server.port",
          "http_default_port": "12345",
          "regex": "^(\\d+)$",
          "site": "dolphin-application-api"
        }
      }
    ]
  }
}


这个改起来简单,效率给力。到此,文档完毕,还有监控和告警相关的,不想写了,就是这么有脾气。不是代码不想写,而且不想写文档。因为干IT最讨厌两件事:自己写代码的时候,写备注+文档、看别人代码的时候,没备注和文档;


?


欢迎在研究大数据集群二开的朋友们来战(交流交流哈哈哈),也可以在b站上看我录制的apache hadoop集群运维实战哈