close

點擊上方藍字關注我們


作者 | 小鑽風

編輯| 小哲

✎編 者 按

剛接觸 DolphinScheduler 的小夥伴,總是會被這租戶整得不明不白,這是啥呀?為何要配置租戶呀?執行任務的時候,為哈腳本運行日誌中提示說沒有執行權限(Permission denied)呢?帶着這樣的疑問,咱們繼續往下看。

本文為 姚應哲編輯排版,感謝貢獻


01


背景


初入夢。

小啜一口大王剛送的卡布奇洛,咱們書接上回《在 Apache DolphinScheduler 上調試 LDAP 登錄,親測有效!》。

聽說,小夥伴們看完這篇文章後,對此是好評如潮,花生瓜子八寶粥,雪碧可樂礦泉水備齊了,端個小板凳就過來跟着學習,不時有丟電池,有丟硬幣,還有直呼簡單易懂、666 的,讓人實在是受寵若驚呢!🤤

(停,請停止你那萬惡的幻想,沒有,沒有,都沒有)

額……咱們言歸正傳。

剛接觸 DolphinScheduler 的小夥伴,總是會被這租戶整得不明不白,這是啥呀?為何要配置租戶呀?執行任務的時候,為哈腳本運行日誌中提示說沒有執行權限(Permission denied)呢?帶着這樣的疑問,咱們繼續往下看。


02


租戶是什麼?

度娘屁巔屁巔地跑過來告訴您,租戶,其基本意思是租用物品的人,本質上還是人的概念。

DolphinScheduler 總是要部署在服務器上,方能幫助咱們穩定地實現任務調度等功能。那 DolphinScheduler 中的租戶在服務器上具體是怎麼使用的,咱先不表。且先說道說道 DolphinScheduler 中的租戶,其實際上對應的是服務器上的用戶,不同租戶的作用範圍由服務器上指定的為準。

DolphinScheduler 中用戶、租戶、角色關係:

DolphinScheduler 用戶有兩種角色:管理員、普通用戶,管理員為 DolphinScheduler 初始賬號給定,普通用戶由管理員創建;

DolphinScheduler 用戶在創建資源時,會使用創建或修改該用戶時指定的唯一租戶創建;

DolphinScheduler 用戶在執行任務時,可以指定多個租戶中的某個租戶執行。

好,天氣冷,屁股涼,話不多說,讓咱們進入 DolphinScheduler 源碼,一探租戶如何工作的究竟。


03


準備運行環境

(若已有,請忽略,直接進入下個環節)

1、下載 DolphinScheduler 最新 2.0.1 版本的安裝包

https://dlcdn.apache.org/dolphinscheduler/2.0.1/apache-dolphinscheduler-2.0.1-bin.tar.gz

2、按照官方提供的安裝教程來啟動

比如單機部署:

https://dolphinscheduler.apache.org/zh-cn/docs/latest/user_doc/guide/installation/standalone.html


04


創建資源示例

1、頁面創建文件夾

2、進入文件夾創建流程

咱們從源碼扒一扒上述流程中有以下幾點與 租戶 相關的方法

ResourcesServiceImpl 實現類的 verifyResourceName 方法中:

@Overridepublic Result<Object> verifyResourceName(String fullName, ResourceType type, User loginUser) { Result<Object> result = new Result<>(); putMsg(result, Status.SUCCESS); if (checkResourceExists(fullName, 0, type.ordinal())) { logger.error("resource type:{} name:{} has exist, can't create again.", type, RegexUtils.escapeNRT(fullName)); putMsg(result, Status.RESOURCE_EXIST); } else { // query tenant // 判斷當前登錄用戶是否設置了 租戶 Tenant tenant = tenantMapper.queryById(loginUser.getTenantId()); if (tenant != null) { String tenantCode = tenant.getTenantCode(); try { // 判斷當前登錄用戶的 租戶 是否已經創建過同名文件夾 String hdfsFilename = HadoopUtils.getHdfsFileName(type,tenantCode,fullName); if (HadoopUtils.getInstance().exists(hdfsFilename)) { logger.error("resource type:{} name:{} has exist in hdfs {}, can't create again.", type, RegexUtils.escapeNRT(fullName), hdfsFilename); putMsg(result, Status.RESOURCE_FILE_EXIST,hdfsFilename); } } catch (Exception e) { logger.error(e.getMessage(),e); putMsg(result,Status.HDFS_OPERATION_ERROR); } } else { putMsg(result,Status.TENANT_NOT_EXIST); } } return result;}

ResourcesServiceImpl 實現類的 createDirectory 方法中:

private void createDirectory(User loginUser,String fullName,ResourceType type,Result<Object> result) { // 獲取當前登錄用戶的 租戶 String tenantCode = tenantMapper.queryById(loginUser.getTenantId()).getTenantCode(); String directoryName = HadoopUtils.getHdfsFileName(type,tenantCode,fullName); String resourceRootPath = HadoopUtils.getHdfsDir(type,tenantCode); try { // 判斷 租戶 是否在文件存儲系統上有根目錄 if (!HadoopUtils.getInstance().exists(resourceRootPath)) { createTenantDirIfNotExists(tenantCode); } // 用 租戶 的身份創建文件夾 if (!HadoopUtils.getInstance().mkdir(directoryName)) { logger.error("create resource directory {} of hdfs failed",directoryName); putMsg(result,Status.HDFS_OPERATION_ERROR); throw new ServiceException(String.format("create resource directory: %s failed.", directoryName)); } } catch (Exception e) { logger.error("create resource directory {} of hdfs failed",directoryName); putMsg(result,Status.HDFS_OPERATION_ERROR); throw new ServiceException(String.format("create resource directory: %s failed.", directoryName)); }}

3、創建成功後,頁面返回


05


執行任務示例

DolphinScheduler支持多種類型的任務,下面將shell任務為例講解。這過程有點長,咱們先平撫一下胸腹再繼續。

1、點擊 創建項目

2、輸入 項目名稱 與 描述 後點擊提交

3、點擊創建好的項目 test_task

將自動進入該項目的工作流監控頁面。

4、點擊工作流定義頁面 並點擊 創建工作流

5、拖拽 SHELL 組件,設置參數,點擊 確認添加

為了查看其過程中是什麼樣的,咱先讓它睡個 1000 秒。

6、點擊 保存,設置 DAG 圖 名稱 與 描述,選擇租戶(如 root,生產環境不建議配置 root 租戶)

7、添加後,點擊上線

8、點擊運行,並運行

9、查看執行效果

執行日誌

從日誌上咱們看到 2 個有用信息。切換到worker 節點 對應的路徑,可以看到/tmp/dolphinscheduler/exec/process/3931179920032/3931236986272_1/11/21 目錄下生成了兩個文件:

11_21.command 內容:

11_21_node.sh 內容:

使用租戶執行 11_21.command 文件

sudo -u root sh /tmp/dolphinscheduler/exec/process/3931179920032/3931236986272_1/11/21/11_21.command

10、執行流程(盜一波官網用圖)

(圖片來自https://dolphinscheduler.apache.org/zhcn/docs/latest/user_doc/architecture/design.html)

11、以上圖涉及到 租戶 有 2 處:

其一:持久化 command 前,即 ExecutorServiceImpl 實現類中的 checkTenantSuitable 方法。

// 當前工作流的租戶是否存在if (!checkTenantSuitable(processDefinition)) { logger.error("there is not any valid tenant for the process definition: id:{},name:{}, ", processDefinition.getId(), processDefinition.getName()); putMsg(result, Status.TENANT_NOT_SUITABLE); return result;}
其二:TaskExecuteThread 實現類 run 方法中。
// task handlethis.task.handle();

12、本次測試任務為 SHELL 類型,則繼續跟蹤,SHELL 任務類中的 handle 方法

@Overridepublic void handle() throws Exception { try { // 創建任務腳本 即本例中的 **_**_node.sh String command = buildCommand(); // 執行shell 任務,主要兩個要點 // 1、創建執行腳本 即本例中的 **_**.command // 2、使用 租戶 執行 TaskResponse commandExecuteResult = shellCommandExecutor.run(command); setExitStatusCode(commandExecuteResult.getExitStatusCode()); setAppIds(commandExecuteResult.getAppIds()); setProcessId(commandExecuteResult.getProcessId()); shellParameters.dealOutParam(shellCommandExecutor.getVarPool()); } catch (Exception e) { logger.error("shell task error", e); setExitStatusCode(EXIT_CODE_FAILURE); throw e; }}

13、ShellCommandExecutor 類 繼承 AbstractCommandExecutor 類,其 run 方法大致如下

public TaskResponse run(String execCommand) throws IOException, InterruptedException {......String commandFilePath = buildCommandFilePath();// 創建任務腳本createCommandFileIfNotExists(execCommand, commandFilePath);//build process// 執行任務腳本buildProcess(commandFilePath);// 處理任務腳本輸出內容parseProcessOutput(process);......}
14、buildProcess方法就是咱們最終需要關注的。

private void buildProcess(String commandFile) throws IOException { // setting up user to run commands List<String> command = new LinkedList<>(); //init process builder ProcessBuilder processBuilder = new ProcessBuilder(); // setting up a working directory processBuilder.directory(new File(taskRequest.getExecutePath())); // merge error information to standard output stream processBuilder.redirectErrorStream(true); // setting up user to run commands command.add("sudo"); command.add("-u"); command.add(taskRequest.getTenantCode()); command.add(commandInterpreter()); command.addAll(Collections.emptyList()); command.add(commandFile); // setting commands processBuilder.command(command); process = processBuilder.start(); printCommand(command);}

15、該方法實現了使用租戶 執行該任務腳本,也就是咱們在前面看到的那句。

sudo -u root sh /tmp/dolphinscheduler/exec/process/3931179920032/3931236986272_1/11/21/11_21.command

到這兒,咱們這個追蹤過程也該結束咯。


06


結尾

經過漫長煎熬,您終於看到了這兒……

本次主要和小夥伴們分享了在 DolphinScheduler 中理解租戶的作用,希望該篇文章能夠有幸幫助到您更好的理解在 DolphinScheduler 中租戶的概念。好,話不多說,風緊,扯呼 ……


07


加入社區

隨着國內開源的迅猛崛起,Apache DolphinScheduler 社區迎來蓬勃發展,為了做更好用、易用的調度,真誠歡迎熱愛開源的夥伴加入到開源社區中來,為中國開源崛起獻上一份自己的力量,讓本土開源走向全球。

參與 DolphinScheduler 社區有非常多的參與貢獻的方式,包括:

貢獻第一個PR(文檔、代碼)我們也希望是簡單的,第一個PR用於熟悉提交的流程和社區協作以及感受社區的友好度。

社區匯總了以下適合新手的問題列表:https://github.com/apache/dolphinscheduler/issues/5689

非新手問題列表:https://github.com/apache/dolphinscheduler/issues?q=is%3Aopen+is%3Aissue+label%3A%22volunteer+wanted%22

如何參與貢獻鏈接:https://dolphinscheduler.apache.org/zh-cn/community/development/contribute.html

來吧,DolphinScheduler開源社區需要您的參與,為中國開源崛起添磚加瓦吧,哪怕只是小小的一塊瓦,匯聚起來的力量也是巨大的。

參與開源可以近距離與各路高手切磋,迅速提升自己的技能,如果您想參與貢獻,我們有個貢獻者種子孵化群,可以添加社區小助手微信(Leonard-ds)手把手教會您( 貢獻者不分水平高低,有問必答,關鍵是有一顆願意貢獻的心 )。添加小助手微信時請說明想參與貢獻。








社區官網https://dolphinscheduler.apache.org/

代碼倉地址https://github.com/apache/dolphinscheduler

您的Star,是Apache DolphinScheduler為愛發電的動力❤️~

投稿請添加社區小助手微信

(Leonard-ds)

☞開源並不是大牛的專屬,普通人也能有屬於自己的一畝三分地☞恭喜社區喜提三枚新 Committer!☞在 Apache DolphinScheduler 上調試 LDAP 登錄,親測有效!☞4 億用戶,7W+ 作業調度難題,Bigo 基於 Apache DolphinScheduler 巧化解☞荔枝機器學習平台與大數據調度系統「雙劍合璧」,打造未來數據處理新模式!☞看到社區代碼不規範,強迫症的我順手就給格式化了!☞最佳實踐|聯通數科基於 DolphinScheduler 的二次開發☞DolphinScheduler 榮獲 2021 中國開源雲聯盟優秀開源項目獎!☞巨變!a16z 關於新一代數據基礎設施架構的深度洞察☞手把手教你 Apache DolphinScheduler 本地開發環境搭建 | 中英文視頻教程

點擊閱讀原文,加入開源!


點個在看你最好看

arrow
arrow
    全站熱搜
    創作者介紹
    創作者 鑽石舞台 的頭像
    鑽石舞台

    鑽石舞台

    鑽石舞台 發表在 痞客邦 留言(0) 人氣()