天天看點

運維實戰:Ambari開發手冊-DolphinScheduler內建實操

作者:滌生大資料

繼我們被apache linkis社群翻牌子以後,收錄了幾篇文章,今天被小海豚社群官方翻牌子了哈,當然我們也有flink社群的大佬,貢獻flink社群文章若幹,那就今天繼續更新一篇小海豚的文章哈,本文章來自滌生大資料老師,阿裡巴巴技術大佬貢獻

運維實戰:Ambari開發手冊-DolphinScheduler內建實操

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           

剩下的交給時間即可。

運維實戰:Ambari開發手冊-DolphinScheduler內建實操

我們的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開發手冊-DolphinScheduler內建實操

代碼解讀:第一段:各種變量的定義,如果其他程式,改路徑和版本即可。比如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服務架構

盜的一個架構圖,一看就比較複雜。

運維實戰:Ambari開發手冊-DolphinScheduler內建實操

不過從圖中可以看出,有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

這個是定義服務的程式,定義軟體版本,安裝的包資訊,以及配置依賴資訊。此處隻貼了些案例,沒貼全。子產品一:服務定義

<name>DOLPHIN</name>
    <displayName>Dolphin Scheduler</displayName>
    <comment>分布式易擴充的可視化DAG工作流任務排程系統</comment>
    <version>3.1.2</version>           

這個的效果圖,在服務添加頁面展示:

運維實戰:Ambari開發手冊-DolphinScheduler內建實操

子產品二:程式定義

主要定義包含哪些程式,以及程式的維護程式,定義等等各種東西,一共有四個:DOLPHIN_MASTER,DOLPHIN_WORKERx0;,DOLPHIN_APIx0;,DOLPHIN_ALERTx0;。單個參考如下,具體細節百度知。

<component>
                    <name>DOLPHIN_MASTER</name>
                    <displayName>DS Master</displayName>
                    <category>MASTER</category>
                    <cardinality>1+</cardinality>
                    <commandScript>
                        <script>scripts/dolphin_master_service.py</script>
                        <scriptType>PYTHON</scriptType>
                        <timeout>600</timeout>
                    </commandScript>
                </component>           

子產品三:安裝rpm定義

這邊定義需要安裝的rpm程式,以及系統。我們這裡能支援的是Centos7.x/8.x,Redha7.x/8.x,KylinV10,Anolis8.x,直接寫個any先用着吧。

<osSpecifics>
                <osSpecific>
                    <osFamily>any</osFamily>
                    <packages>
                        <package>
                            <name>apache-dolphinscheduler*</name>
                        </package>
                    </packages>
                </osSpecific>
            </osSpecifics>           

剩下的,還有點内容,後期加吧,這裡貼一個完成的圖。

<?xml version="1.0"?>
<metainfo>
    <schemaVersion>2.0</schemaVersion>
    <services>
        <service>
            <name>DOLPHIN</name>
            <displayName>Dolphin Scheduler</displayName>
            <comment>分布式易擴充的可視化DAG工作流任務排程系統</comment>
            <version>3.1.2</version>
            <components>
                <component>
                    <name>DOLPHIN_MASTER</name>
                    <displayName>DS Master</displayName>
                    <category>MASTER</category>
                    <cardinality>1+</cardinality>
                    <commandScript>
                        <script>scripts/dolphin_master_service.py</script>
                        <scriptType>PYTHON</scriptType>
                        <timeout>600</timeout>
                    </commandScript>
                </component>
                <component>
                    <name>DOLPHIN_WORKER</name>
                    <displayName>DS Worker</displayName>
                    <category>SLAVE</category>
                    <cardinality>1+</cardinality>
                    <commandScript>
                        <script>scripts/dolphin_worker_service.py</script>
                        <scriptType>PYTHON</scriptType>
                        <timeout>600</timeout>
                    </commandScript>
                </component>

                <component>
                    <name>DOLPHIN_ALERT</name>
                    <displayName>DS Alert</displayName>
                    <category>SLAVE</category>
                    <cardinality>1+</cardinality>
                    <commandScript>
                        <script>scripts/dolphin_alert_service.py</script>
                        <scriptType>PYTHON</scriptType>
                        <timeout>600</timeout>
                    </commandScript>
                </component>

                <component>
                    <name>DOLPHIN_API</name>
                    <displayName>DS Api</displayName>
                    <category>SLAVE</category>
                    <cardinality>1+</cardinality>
                    <commandScript>
                        <script>scripts/dolphin_api_service.py</script>
                        <scriptType>PYTHON</scriptType>
                        <timeout>600</timeout>
                    </commandScript>
                </component>
            </components>

            <requiredServices>
                <service>ZOOKEEPER</service>
            </requiredServices>

            <osSpecifics>
                <osSpecific>
                    <osFamily>any</osFamily>
                    <packages>
                        <package>
                            <name>apache-dolphinscheduler*</name>
                        </package>
                    </packages>
                </osSpecific>
            </osSpecifics>

            <configuration-dependencies>
                <config-type>dolphin_env</config-type>
                <config-type>common.properties</config-type>
                <config-type>dolphin-jvm</config-type>
            </configuration-dependencies>
            <themes>
                <theme>
                    <fileName>theme.json</fileName>
                    <default>true</default>
                </theme>
            </themes>
            <quickLinksConfigurations-dir>quicklinks</quickLinksConfigurations-dir>
            <quickLinksConfigurations>
                <quickLinksConfiguration>
                    <fileName>quicklinks.json</fileName>
                    <default>true</default>
                </quickLinksConfiguration>
            </quickLinksConfigurations>
        </service>
    </services>
</metainfo>           

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)           

其他安裝程式,類似,隻是需要修改對應的路徑和檔案名資訊

運維實戰:Ambari開發手冊-DolphinScheduler內建實操

特殊說明下,最開始的程式,需要做系統的初始化,沿用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)           

以上代碼,對應的程式

運維實戰:Ambari開發手冊-DolphinScheduler內建實操

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中的相關定義如下:

<property>
  <name>dolphin.database.type</name>
  <value>mysql</value>
  <description>選擇海豚排程的資料庫類型:Mysql/PG 2選一,預設Mysql</description>
  <display-name>資料庫類型</display-name>
  <value-attributes>
    <type>value-list</type>
    <entries>
      <entry>
        <value>mysql</value>
        <label>Mysql</label>
      </entry>
      <entry>
        <value>postgresql</value>
        <label>Postgresql</label>
      </entry>
    </entries>
    <selection-cardinality>1</selection-cardinality>
  </value-attributes>
  <on-ambari-upgrade add="true"/>
</property>

<property>
  <name>dolphin.database.db</name>
  <value>dolphin</value>
  <display-name>資料庫名</display-name>
  <on-ambari-upgrade add="true"/>
</property>           

特殊說明,這種類型不太一樣,資料庫類型提供的是一個多選,提供mysql個PG的單選按鈕,資料庫是一個字元串,不用進階設定。成品大概如下:

運維實戰:Ambari開發手冊-DolphinScheduler內建實操

運維實戰:Ambari開發手冊-DolphinScheduler內建實操

特殊說明下,我是代碼搞好後再寫的文檔,截圖和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中進行的變量擷取。整體套路就是這樣,剩下的就是對比不同的配置,來制作多個模闆。全部的資訊如下:

運維實戰:Ambari開發手冊-DolphinScheduler內建實操

這裡隻是完成了一半,另外的一半,需要定義這些模闆檔案,需要寫到哪些配置裡面。這裡的話,寫在了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
         )           

以上為案例,一看就懂,不做解釋。剩下的就是體力勞動。到此,已經可用了,寫到這裡,自動化部署就已經完成了。但是,還是那句話,格局一定要打開,要最求卓越。

運維實戰:Ambari開發手冊-DolphinScheduler內建實操

3.5themes視覺優化

以下兩個圖,那個好看?很明顯,不做選擇題,咋們全都要。隻是,上圖已經實作了,接下來進行下圖的實作。

運維實戰:Ambari開發手冊-DolphinScheduler內建實操

運維實戰:Ambari開發手冊-DolphinScheduler內建實操

其中,下圖的内容需要使用到的是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:是對整體頁面做拆分,做頁面排布。并對每個頁面命名和編号。頁面的布局内容如下:

運維實戰:Ambari開發手冊-DolphinScheduler內建實操

placement,是對定義在框框中,填入什麼樣的内容。比如JVM處,大題填以下内容:

運維實戰:Ambari開發手冊-DolphinScheduler內建實操

widgets,則是定義資料的規範,和顯示的格式,這個需要和對應的xml中的配置遙相呼應。比如:text-fieldx0;文本框,就是單純的框框格式,比如環境配置資訊的

運維實戰:Ambari開發手冊-DolphinScheduler內建實操

togglex0; 二選一的拖拽框,比如,是否開啟kerbers配置的選項

運維實戰:Ambari開發手冊-DolphinScheduler內建實操
運維實戰:Ambari開發手冊-DolphinScheduler內建實操

combox0;,下拉框,用于多選一的選擇,比如資料庫類型,檔案存儲類型等。

運維實戰:Ambari開發手冊-DolphinScheduler內建實操

大體介紹完了,接下來進行實際的實作。

3.5.2目錄配置

我們在最開始的地方<0,0>來進行環境配置的設定。打算提供,使用者賬号、組,以及環境變量的定義。這裡采用的是大框套小框來進行實作的,整體頁面布局就,及其對應的編碼就變成了這樣。

運維實戰:Ambari開發手冊-DolphinScheduler內建實操

接下來就進行具體的框框的定義。在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的定義。

<property>
  <name>dolphin.user</name>
  <value>dolphin</value>
  <description>安裝哪個使用者并管理海豚排程器</description>
  <display-name>部署使用者</display-name>
  <on-ambari-upgrade add="true"/>
</property>           

通過以上,操作,最後的效果圖如下。

運維實戰:Ambari開發手冊-DolphinScheduler內建實操

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,可以根據具體的配置設定。

<property>
  <name>alert.jvm.xmx</name>
  <value>1</value>
  <display-name>Alert JVM大小</display-name>
  <description>Alert 預配置設定的JVM使用的最大記憶體量
    如果您希望輸入一個高于滑塊上最大值的值,請單擊滑鼠懸停在設定上時出現的鉛筆,并忽略不建議輸入更高的值。
  </description>
  <value-attributes>
    <type>int</type>
    <minimum>1</minimum>
    <maximum>4</maximum>
    <increment-step>1</increment-step>
    <unit>GB</unit>
  </value-attributes>
</property>           

最後效果案例效果。

運維實戰:Ambari開發手冊-DolphinScheduler內建實操

3.5.3資料庫配置

資料庫的,同上。不整廢話,都一樣的東西。效果圖如下:

運維實戰:Ambari開發手冊-DolphinScheduler內建實操

3.5.4存儲類型選擇

資料存儲類型的時候,這個有點不同了,因為添加了可選,并且可選進行資料内容的展示。先來看效果圖:

運維實戰:Ambari開發手冊-DolphinScheduler內建實操

運維實戰:Ambari開發手冊-DolphinScheduler內建實操
運維實戰:Ambari開發手冊-DolphinScheduler內建實操

運維實戰:Ambari開發手冊-DolphinScheduler內建實操

選擇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,這是一個多選

<property>
  <name>resource.storage.type</name>
  <value>HDFS</value>
  <description>
    資源存儲類型: HDFS , S3 , OSS , NONE
  </description>
  <display-name>資源存儲類型</display-name>
  <value-attributes>
    <type>value-list</type>
    <entries>
      <entry>
        <value>HDFS</value>
        <label>HDFS</label>
      </entry>
      <entry>
        <value>S3</value>
        <label>S3/MinIO/Ozone</label>
      </entry>
      <entry>
        <value>OSS</value>
        <label>OSS</label>
      </entry>
      <entry>
        <value>NONE</value>
        <label>NONE</label>
      </entry>
    </entries>
    <selection-cardinality>1</selection-cardinality>
  </value-attributes>
  <on-ambari-upgrade add="true"/>
</property>           

這樣,下拉框就完成了。接下來,怎麼根據下拉框的格式來進行相應配置的選擇呢?其實,這個的重點就是判斷+可顯示字段的資訊标記。貼代碼就懂了。在資料展示處:

{
  "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

這兩個功能還沒設定好,先把功能頁面開啟來先。

運維實戰:Ambari開發手冊-DolphinScheduler內建實操

資料框,及其框中資料編輯都同上,不在叙述。

不同就是資料的定義:

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

對應的XML資料定義,剩下的自己複制改。

<property>
  <name>hadoop.security.authentication.startup.state</name>
  <value>false</value>
  <description>功能未開發完畢,别開啟</description>
  <display-name>是否開啟Kerberos認證</display-name>
  <value-attributes>
    <type>value-list</type>
    <entries>
      <entry>
        <value>true</value>
        <label>Enabled</label>
      </entry>
      <entry>
        <value>false</value>
        <label>Disabled</label>
      </entry>
    </entries>
    <selection-cardinality>1</selection-cardinality>
  </value-attributes>
  <on-ambari-upgrade add="false"/>
</property>通過以上一波操作,就全部完成了themes的定義,重點配置丢這裡,看起來就舒服了。這樣,重點配置在Setting頁面,詳細配置在advance頁面。           

3.6超連結實作

DS給提供了Web頁面,最好的話,再搞個超連結,點選即可通路。說幹就看,先看效果圖

運維實戰:Ambari開發手冊-DolphinScheduler內建實操

這個功能一共需求兩個東東。

第一個,服務定義metainfo.xml中,需要添加關于超連結的定義。

<quickLinksConfigurations>
                <quickLinksConfiguration>
                    <fileName>quicklinks.json</fileName>
                    <default>true</default>
                </quickLinksConfiguration>
            </quickLinksConfigurations>           

在建立檔案夾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+)#34;,
          "site": "dolphin-application-api"
        }
      }
    ]
  }
}           

這個改起來簡單,效率給力。到此,文檔完畢,還有監控和告警相關的,不想寫了,就是這麼有脾氣。不是代碼不想寫,而且不想寫文檔。因為幹IT最讨厭兩件事:自己寫代碼的時候,寫備注+文檔、看别人代碼的時候,沒備注和文檔;

運維實戰:Ambari開發手冊-DolphinScheduler內建實操

歡迎在研究大資料叢集二開的朋友們來戰(交流交流哈哈哈),也可以在b站上看我錄制的apache hadoop叢集運維實戰哈

繼續閱讀