この記事の概要
独自でWindowsサービスとして登録する機能を持っていない、任意のコマンドをWindowsサービス化したい。
とくに Quarkus版Keycloak をターゲットにするけど、ほかにも候補があれば、それらもサービス化する。
WinSW の紹介
Windows Service Wrapper の略だそうです。
Java Service Wrapper への対抗だそうで。。
(Project manifest に気付くのが遅かった)
単にKeycloakをサービス化するなら、 Java Service Wrapper でも良かったわ。
.net ベースで開発されている。
リリースバイナリ がちょっと面白くて、.netの マネージドコード ベースのものに加えて、x86とx64の実行ファイル(.netが未インストールでも動く)が提供されている。
x86とx64の建付けがどうなっているかというと、.NET Coreを含んたバイナリになっているそうな。
稼働環境にインストールされている.netのバージョンが明らかで変わる予定ないならマネージドコード版を使えばよいと思う。
インストール
例によってscoopで。
{
"version": "3.0.0-alpha.10",
"description": "A wrapper executable that can be used to host any executable as a Windows service",
"homepage": "https://github.com/winsw/winsw",
"license": "MIT",
"url": "https://github.com/winsw/winsw/releases/download/v3.0.0-alpha.10/WinSW-net461.exe#/WinSw3.exe",
"hash": "3c0671e7b6914512062895b5c96f6b9cf16a83889e235a2948379e6e329296e7",
"bin": "WinSw3.exe",
"checkver": "github",
"autoupdate": {
"url": "https://github.com/winsw/winsw/releases/download/v$version/WinSW.NET461.exe#/WinSw3.exe"
}
}
> scoop install winsw3-net4
v3系がalpha.10で放置されているようだけど、v2系 は「実行ファイルと同名のxmlファイルを参照する」って「いけてない」つくりになっている。
馬鹿にならないサイズなのに、サービスの個数ぶんだけexeを準備するのも馬鹿らしいので、v3系を使う。
exe増やすのにシンボリックリンク使えばいい1という話は却下。
Keycloakをサービスとして登録
WinSWサービス用のxmlファイルを作成する。
<service>
<id>keycloak</id>
<name>Keycloak</name>
<description>Keycloak</description>
<workingdirectory>W:\my-service</workingdirectory>
<executable>cmd.exe</executable>
<arguments>/C start-keycloak.cmd</arguments>
<log mode="rotate" />
<onfailure action="restart" delay="300 sec" />
<serviceaccount>
<username>MYDOMAIN\k2ok-app</username>
<allowservicelogon>false</allowservicelogon>
</serviceaccount>
<logpath>W:\my-service\keycloak\logs</logpath>
</service>
サービスとしてインストール。
> winsw3 install keycloak.xml
あとはコマンドラインで起動するのと同様にサービス起動できる。
また、マシン起動時に自動起動させることも可能。遅延開始設定も可能。
ログの出力方法も凝れるけど、とりあえず出力先を指定するくらいで触っていない。
SSHトンネル用コマンドをサービス登録
上記のとおり、XMLさえ記述すればサービス化できるので、sshのトンネルコマンドをサービス化することもできる。
<service>
<id>MyTunnel</id>
<name>My tunnel to some host</name>
<description>My tunnel to some host using SSH</description>
<executable>ssh</executable>
<arguments>-N -g -R7161:127.0.0.1:7161 tunnel@some-host</arguments>
<log mode="rotate" />
<onfailure action="restart" delay="300 sec" />
<serviceaccount>
<username>MYDOMAIN\k2ok-app</username>
<allowservicelogon>false</allowservicelogon>
</serviceaccount>
<logpath>W:\my-service\MyTunnel\logs</logpath>
</service>
課題
OSの再起動時に、起動してくれない場合があった。
(遅延起動は設定しているが、数時間経っても起動してくれないので意図する動作ではない)
システムログを追ってみると、Service Control Managerでサービス起動時のタイムアウト(30000 ミリ秒)になったと出ている。
非力なマシンで、起動直後の応答が悪いのも当然なので、タイムアウトの閾値を延ばす方法を探す…あった。
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control
へ ServicesPipeTimeout
追加するとのこと。
参考: How to extend the timeout for services if they fail to start or stop
うまく起動できるようになりました。
グループポリシーでもいいそうだけど、ポリシーとして設定・配信するには躊躇する項目だ。
-
この記事書いたあとで試してみたけど、実行ファイルパスや実行ファイル名の解決で支障があるのかサービス登録の時点で失敗した。 ↩