Javaアプリケーションのsystemdユニットファイルを書いていて、Javaを起動するために使用されます)のバージョンを制御したいと思います。サービスファイルは
[Service]
Type=simple
EnvironmentFile=%h/Documents/apps/app/app-%i/app.cfg
ExecStart=${Java_HOME}/bin/Java ${Java_OPTS} -jar %h/Documents/apps/app/app-%i/myapp.jar
SuccessExitStatus=143
それを起動しようとすると、エラーが返されます
Apr 28 12:43:37 rombert systemd[1613]: [/home/robert/.config/systemd/user/[email protected]:7] Executable path is not absolute, ignoring: ${Java_HOME}/bin/Java ${Java_OPT
Apr 28 12:43:37 rombert systemd[1613]: [email protected] lacks both ExecStart= and ExecStop= setting. Refusing.
Java_HOME
が正しく設定されていることは知っています。 ExecStart
行を/usr/bin/Java
で始まるように変更し、-DsomeOption=${Java_HOME}
のようなものを追加すると、うまく表示されます。
明白な回避策は、ラッパースクリプトを作成することですが、サービスファイルを使用するという点に反するように感じます。
ユニットファイルを使用してJavaアプリケーションにJava_HOMEを設定するにはどうすればよいですか?
Systemd.service(5)の「コマンドライン」セクションから:
最初の引数(つまり、実行するプログラム)は変数ではない場合があることに注意してください。
インスタンス指定子%i
(systemd.unit(5)で詳細を確認できます)を使用することをお勧めしましたが、(systemd.service(5)に戻ります):
コマンドラインの最初の引数(つまり、実行するプログラム)に指定子を含めることはできません。
この時点での最良のオプションは、実際にはJavaバイナリの実行をラップするシェルスクリプトを作成することです。または、Warren Youngによって提案されたバイナリを実行するか、シェルコマンドの例のようにシェルを直接ExecStartできます。 systemd.service(5)の「コマンドライン」セクションの行には、次の例があります。
ExecStart=/bin/sh -c 'dmesg | tac'
あなたはそうすることができます(テストされていません):
ExecStart=/bin/sh -c '${Java_HOME}....'
別の同様のオプションは/usr/bin/env
を使用することです:
ExecStart=/usr/bin/env "${Java_HOME}/bin/Java" -jar ...
このように、コマンド全体を囲む'
引用符を省略できます。引用符で囲まれたものをネストする必要がある場合に役立ちます。
PS。補足として、変数名をSystemdファイルの{
braces}
で囲むと、正しく認識されなくなります。
別のかなり異なるオプションは、別のシステムツールalternatives
の使用を想定しています。 Java SDKがシステムパッケージから提供されている場合、おそらくすでに設定されています。手動でインストールする場合は、次のような方法でそれらをシステムに追加する必要があります。
alternatives --install /usr/bin/Java java /path/to/your/sdk/bin/Java 3
最後の数値が優先されます(数値が大きいほど重要です)。コマンドalternatives --display Java
を発行して既存の優先度を確認できるため、新しいSDKにどの優先度を選択するかを決定できます。
インストールしたら、サービスファイルで/usr/bin/Java
を使用し、サービスを開始する前にalternatives --config Java
を実行して、選択するバージョンを決定できます。実際には試していませんが、次のようなことができるようです:
alternatives --set Java /path/to/your/sdk/bin/Java
...そして、スクリプトからSDKを選択します。 alternatives --config
のインタラクティブインターフェイスがシナリオに適していない場合、これはオプションになる可能性があります。 ExecStartPre
ディレクティブを使用して、サービスファイルの設定を行うこともできます。
私はラッパースクリプトが本当に嫌いです。その内容の多くは恐らく恐ろしいSysV initスクリプトと同じになるでしょう(少なくともそれは開始セクションです)。おそらく、ラッパースクリプトで始まるサービスファイルは、実行されるコマンドが実行されるプロセスではないという事実により、少し複雑になる必要があります。多くのsystemdディレクティブに時間をかけることができる場合は、ぎこちないラッパースクリプトに固執することなく、目的を達成するためのよりクリーンな方法が見つかるかもしれません。