
我在工作中使用這個定義systemd
:
[Unit]
Description=Some job
[Service]
ExecStart=/usr/local/sbin/somejob
User=dlt
Type=forking
[Install]
WantedBy=multi-user.target
該腳本的呼叫方式如下(呼叫一個偵聽 tcpip 套接字並將輸入附加到檔案的簡單例程):
#!/bin/sh
cd /home/user/tmp/testout
nohup java -jar /home/user/programming/tests/java/core/SocketTest/SocketTest.jar </dev/null >/dev/null &
systemctl start somejob
進程顯示為正在運行後,init
作為其父進程:
user@CANTANDO ~$ ps -u dlt eo pid,ppid,command
PID PPID COMMAND
8718 1 java -jar /home/user/programming/tests/java/core/SocketTest/SocketTest.jar
執行systemctl stop somejob
該程序後不再顯示(且連接埠已關閉)。
所以一切看起來都很好而且花花公子
我的問題是:這是一個可接受的解決方案運行 java 守護進程systemd
,或者是否有警告,以及其他更穩定或安全的方法來實現這一目標?
答案1
以下是一些小的修改:
- 由於它偵聽網路套接字,因此使其成為
network.target
. nohup
不需要,因為systemd
將為您守護可執行檔。- 我認為單獨的 shell 腳本太過分了,所以只需將其合併到服務文件中即可。
< /dev/null
由於 systemd 設定了適當的標準 I/O 上下文,因此不需要重定向(等等)。事實上,如果你採取重定向出去systemd 將在其日誌中記錄 Java 程式傳送至標準輸出的任何內容,無需特殊的日誌記錄機制。&
不需要也不適合從呼叫 shell () 非同步運行。- 需要一個特定的行為模式
Type=forking
,如果守護程式不遵循它,就會出錯。所以嘗試Type=simple
(或Type=notify
)。
所以服務文件如下圖所示:
[Unit]
Description=Some job
After=network.target
[Service]
WorkingDirectory=/home/user/tmp/testout
SyslogIdentifier=SocketTest
ExecStart=/bin/sh -c "exec java -jar /home/user/programming/tests/java/core/SocketTest/SocketTest.jar"
User=dlt
Type=simple
[Install]
WantedBy=multi-user.target
筆記:
- 您不能僅用作
java
要執行的程式的名稱。 systemd 不搜尋PATH
可執行文件,且給出的可執行文件的名稱ExecStart
必須是絕對的。因此,如果您想要路徑搜索,則必須透過 shell 或/usr/bin/env
.我們選擇/bin/sh
這裡。 - 因為這是
Type=simple
必須Java的shellexec
,不能將其作為子進程運行。 systemd 透過主程序控制服務,並且需要是 Java,而不是父 shell 程序。 - 因為這不是直接呼叫 Java 可執行文件,所以 systemd 會將名稱
sh
作為服務名稱放入其日誌中。看如何避免 /usr/bin/env 在 systemd 日誌中被標記為執行檔了解更多相關資訊。
據我所知,使用 Systemd 運行 Java 應用程式沒有特別的警告。