
私は、Ubuntu 18.04 で Spring Boot アプリケーション (他の誰かが開発しました。私は Java プログラマーではありません) をプロビジョニングしようとしています。開発者は以前、/etc/init.d
サービスを有効にするためにシンボリックリンクを追加しており、起動時に正常に起動します。ただし、その後サービスが失敗すると、systemd はサービスが実行中であると報告します。
[email protected]:/var/log/apps# systemctl status crm-service
● crm-service.service - LSB: crm-service
Loaded: loaded (/etc/init.d/crm-service; generated)
Active: active (exited) since Wed 2020-04-15 12:27:15 BST; 3h 56min ago
Docs: man:systemd-sysv-generator(8)
Process: 8656 ExecStop=/etc/init.d/crm-service stop (code=exited, status=0/SUCCESS)
Process: 8703 ExecStart=/etc/init.d/crm-service start (code=exited, status=0/SUCCESS)
Apr 15 12:27:15 example.com systemd[1]: Starting LSB: crm-service...
Apr 15 12:27:15 example.com crm-service[8703]: /var/services/crm-service.conf: line 1: -Xms96M: command not found
Apr 15 12:27:15 example.com crm-service[8703]: Started [8747]
Apr 15 12:27:15 example.com systemd[1]: Started LSB: crm-service.
私は同じ systemd ユニットファイルspringboot についてはインターネット上にたくさん投稿されていますが、この問題を解決できそうなものは何も見つかりません。
- systemd にサービスの実際のステータスを確認させるにはどうすればよいですか? (リスニング ソケットを開きますが、ランダムな高ポートで開きます)
- systemdを試す方法はありますか?優しく障害が発生したことがわかっているサービスを再起動するには?
答え1
Systemd には多くの批判があり、その多くは非常に良いのですが、そうではありません。Systemd は、起動スクリプトからフォーク (またはクローン) されたすべてのプロセスとスレッドを追跡し、それらのいずれも残っていない場合はサービスが終了したと見なすことができます。
私が見つけた最初の問題は、systemd が で起動/停止スクリプトを使用しないことです/etc/init.d
。これは、そのための互換性アドオンにすぎません。代わりに、systemd はユニット ファイル、つまりすべてのサービス用の構成ファイルを使用します。
systemd sysv init compat モジュールは、 内のすべてのサービスに対してユニット ファイルを効果的に生成します/etc/init.d
。ただし、init スクリプトに必要な情報が欠落している (または、そこから情報を抽出できない) ため、これが常に適切であるとは限りません。
この互換モジュールは、終了コードがゼロ以外の場合、systemd が init スクリプトが失敗したと見なし、したがってサービスが動作していないと見なすように動作します。終了コードがゼロの場合は、正常に実行されたことを意味します。init スクリプトにバグがあり、失敗しても終了コードがゼロの場合、systemd をだまします。
init スクリプトのバグの原因として最も可能性が高いのは、プロセスをバックグラウンドで開始し、常にゼロで終了することです。カスタム プロバイダーによって作成されたほとんどの init スクリプトに関する私の一般的な経験では、そのほとんどに大幅な改善の余地がある可能性があります。それらを信用せず、何をしているかを見て修正してください。あなたの場合、最善の方法は、次の点を確認することです。
- Javaアプリの起動方法
- どこから始まるのか
- どのユーザーとして起動するか
そして、ユニット ファイルを使用して同じ機能を再現します。
systemd から initscripts を自動的に再起動する方法はありませんが、ユニット ファイルからは可能です。
注意: Java プログラムがランダムにクラッシュした場合も、それは Java プログラムにとって深刻な問題です。健全な Java フレームワークはすべて、自身の致命的なエラーを適切に処理します (すべての例外をキャッチし、ログに記録して続行します)。
init スクリプトのもう 1 つの非常にありそうなバグは、JVM (おそらく /usr/bin/java) が見つからないため、それを空の文字列に置き換え、シェル コマンドとして JVM フラグを起動しようとすることです。明らかに、-Xms96M
システムにはコマンドはありませんが、/usr/bin/java -Xms96M ...
機能します。
Spring Boot アプリのユニット ファイルの例:
[Unit]
Description=Crm Spring Boot App Example
After=network.target
[Service]
Type=simple
ExecStart=/usr/bin/java -Xms96M ...other flags... your.spring.boot.jar
User=exampleuser
Group=examplegroup
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=exampleapp
WorkingDirectory=/path/to/app/home
[Install]
WantedBy=multi-user.target
Alias=exampleapp.service
このユニット ファイルは、Java プロセスの標準出力とエラーも syslog にリダイレクトします。
アプリを自動再起動するには、
RestartSec=5s
Restart=on-failure
セクションに[Service]
。
systemdのチュートリアルがあります翻訳元。