編寫完的 kettle job (kjb文件) 放在服務器上執行的時候出現了奇怪的錯誤:
# 執行 kjb
./kitchen.sh -file:/opt/code/ods/ods_inc.kjb
# 錯誤日志
2020/11/10 20:15:40 - TableAccountingState - Running on platform : Linux
2020/11/10 20:15:40 - TableAccountingState - Executing command : /tmp/kettle_72e89b17-234e-11eb-8b7e-49ea52dd39e5shell
2020/11/10 20:15:40 - TableAccountingState - ERROR (version 8.3.0.0-371, build 8.3.0.0-371 from 2019-06-11 11.09.08 by buildguy) : Error running shell [null] : java.io.IOException: Cannot run program "/tmp/kettle_72e89b17-234e-11eb-8b7e-49ea52dd39e5shell": error=13, Permission denied
2020/11/10 20:15:40 - TableAccountingState - ERROR (version 8.3.0.0-371, build 8.3.0.0-371 from 2019-06-11 11.09.08 by buildguy) : java.io.IOException: Cannot run program "/tmp/kettle_72e89b17-234e-11eb-8b7e-49ea52dd39e5shell": error=13, Permission denied
2020/11/10 20:15:40 - TableAccountingState - at java.lang.ProcessBuilder.start(ProcessBuilder.java:1048)
2020/11/10 20:15:40 - TableAccountingState - at org.pentaho.di.job.entries.shell.JobEntryShell.executeShell(JobEntryShell.java:595)
2020/11/10 20:15:40 - TableAccountingState - at org.pentaho.di.job.entries.shell.JobEntryShell.execute(JobEntryShell.java:435)
2020/11/10 20:15:40 - TableAccountingState - at org.pentaho.di.job.Job.execute(Job.java:686)
2020/11/10 20:15:40 - TableAccountingState - at org.pentaho.di.job.Job.access$000(Job.java:121)
2020/11/10 20:15:40 - TableAccountingState - at org.pentaho.di.job.Job$1.run(Job.java:804)
2020/11/10 20:15:40 - TableAccountingState - at java.lang.Thread.run(Thread.java:748)
2020/11/10 20:15:40 - TableAccountingState - Caused by: java.io.IOException: error=13, Permission denied
2020/11/10 20:15:40 - TableAccountingState - at java.lang.UNIXProcess.forkAndExec(Native Method)
2020/11/10 20:15:40 - TableAccountingState - at java.lang.UNIXProcess.<init>(UNIXProcess.java:247)
2020/11/10 20:15:40 - TableAccountingState - at java.lang.ProcessImpl.start(ProcessImpl.java:134)
2020/11/10 20:15:40 - TableAccountingState - at java.lang.ProcessBuilder.start(ProcessBuilder.java:1029)
2020/11/10 20:15:40 - TableAccountingState - ... 6 more
2020/11/10 20:15:40 - ods_inc_test - Finished job entry [Flag] (result=[false])
2020/11/10 20:15:40 - ods_inc_test - Finished job entry [Get Date] (result=[false])
2020/11/10 20:15:40 - ods_inc_test - Job execution finished
2020/11/10 20:15:40 - Kitchen - Finished!
2020/11/10 20:15:40 - Kitchen - ERROR (version 8.3.0.0-371, build 8.3.0.0-371 from 2019-06-11 11.09.08 by buildguy) : Finished with errors
2020/11/10 20:15:40 - Kitchen - Start=2020/11/10 20:15:35.801, Stop=2020/11/10 20:15:40.738
2020/11/10 20:15:40 - Kitchen - Processing ended after 4 seconds.
關鍵錯誤在於
Error running shell [null] : java.io.IOException: Cannot run program "/tmp/kettle_72e89b17-234e-11eb-8b7e-49ea52dd39e5shell": error=13, Permission denied
可以看出錯誤在於沒有權限執行/tmp/kettle_72e89b17-234e-11eb-8b7e-49ea52dd39e5shell
,這個文件是 kettle 在執行腳本的時候生成的臨時文件,但是沒有權限執行。
首先嘗試給用戶賦予 /tmp
文件夾的可執行權限,但是仍然相同的報錯。
一番查閱資料后發現是由於/tmp
文件系統的屬性被設置了noexec
導致該目錄下的程序無法執行。noexec
表示對應文件系統不允許執行可執行程序,即使文件具有可執行過權限。通常是考慮安全原因會這么設置。
那么方法有兩個:
- 移除
/tmp
的noexec
屬性,但是可能會導致安全隱患 - 更改 kettle 生成臨時文件的目錄,讓其在一個有執行權限的文件中生成臨時文件。
第一個方法可能會有安全隱患,/tmp
文件夾是很容易遭受攻擊的地方,而且修改了 /etc/fstab
中的配置后需要對 /tmp
進行重新掛在,這時可能有很多程序在使用這個目錄,需要停掉使用的服務,一些服務甚至需要重啟,在生產環境中不好執行。
那就想辦法修改 kettle 的臨時文件目錄。
首先搜索了 kettle 的幫助使用手冊和幫助文檔,並沒有發現有提供對應的入口。
但是 kettle 是跑在 JVM 上的 java 程序,那么理論上應該可以修改 JVM 啟動參數達到目的。
我們使用 kitchen 執行 kjb 文件(kettle job)實際上就是執行這個 job 中的 kettle transformation,而 kettle transformation 是用 spoon 程序執行的,那么就看一看 spoon.sh(Linux環境下,Windows下則是 spoon.bat)
在 spoon.sh 中發現這么一段代碼:
# **********************************************************************
# ** Set java runtime options
# ** Change 2048m to higher values in case you run out of memory
# ** or set the PENTAHO_DI_JAVA_OPTIONS environment variable
# **********************************************************************
if [ -z "$PENTAHO_DI_JAVA_OPTIONS" ]; then
PENTAHO_DI_JAVA_OPTIONS="-Xms1024m -Xmx2048m"
fi
OPT="$OPT $PENTAHO_DI_JAVA_OPTIONS
-Dhttps.protocols=TLSv1,TLSv1.1,TLSv1.2
-Djava.library.path=$LIBPATH
-Djava.endor sed.dirs=$JAVA_ENDORSED_DIRS
-DKETTLE_HOME=$KETTLE_HOME
-DKETTLE_REPOSITORY=$KETTLE_REPOSITORY
-DKETTLE_USER=$KETTLE_USER
-DKETTLE_PASSWORD=$KETTLE_PASSWORD
-DKETTLE_PLUGIN_PACKAGES=$KETTLE_PLUGIN_PACKAGES
-DKETTLE_LOG_SIZE_LIMIT=$KETTLE_LOG_SIZE_LIMIT
-DKETTLE_JNDI_ROOT=$KETTLE_JNDI_ROOT"
框框的注釋中說得很清楚了,這里就是設置 runtime options 的地方,那么我們在 OPT 后面加上 -Djava.io.tmpdir=/opt/code/kettle_tmp
試試。
java.io.tmpdir 是配置 JVM 默認臨時文件輸出目錄的參數。
再次執行 ./kitchen.sh -file:/opt/code/ods/ods_inc.kjb
出現一下日志輸出:
2020/11/10 20:22:04 - TableAccountingState - Running on platform : Linux
2020/11/10 20:22:04 - TableAccountingState - Executing command : /opt/code/kettle_tmp/kettle_577843c5-234f-11eb-b308-d38e88d4b1fdshell
證明 -Djava.io.tmpdir=/opt/code/kettle_tmp
生效了,並且沒有再報相同的權限錯誤。