Spring Boot + npm + Geb で入力フォームを作ってテストする ( その76 )( Spring Boot Actuator を導入する )
概要
記事一覧はこちらです。
- 今回の手順で確認できるのは以下の内容です。
- Spring Boot Actuator を導入します。
参照したサイト・書籍
Spring Boot 2.0のActuator、とりあえず動かすために知っておきたい変更点3つ
https://qiita.com/suke_masa/items/acfdf52019538fd8ccc6Introducing Actuator Endpoints in Spring Boot 2.0
https://spring.io/blog/2017/08/22/introducing-actuator-endpoints-in-spring-boot-2-0Spring Boot Reference Guide - 28.4 Actuator Security
https://docs.spring.io/spring-boot/docs/2.0.4.RELEASE/reference/htmlsingle/#boot-features-security-actuatorSpring Boot Reference Guide - Part V. Spring Boot Actuator: Production-ready features
https://docs.spring.io/spring-boot/docs/2.0.4.RELEASE/reference/htmlsingle/#production-readySpring Boot Actuator Web API Documentation
https://docs.spring.io/spring-boot/docs/current/actuator-api/html/How can authenticate user by only ip address in spring security?
https://stackoverflow.com/questions/38304078/how-can-authenticate-user-by-only-ip-address-in-spring-securityCloudFoundry: Java thread and heap dump analysis on remote containers
https://fabianlee.org/2017/12/08/cloudfoundry-java-thread-and-heap-dump-analysis-on-remote-containers/IBM Thread and Monitor Dump Analyzer for Java
https://www.ibm.com/developerworks/community/groups/service/html/communityview?communityUuid=2245aa39-fa5c-4475-b891-14c205f7333cSpring security multiple hasIPAddress antMatchers
https://stackoverflow.com/questions/28303097/spring-security-multiple-hasipaddress-antmatchersSpring Boot Actuator 2.0 & Micrometer
https://www.slideshare.net/makingx/spring-boot-actuator-20-micrometerSpring Boot Actuator metrics monitoring with Prometheus and Grafana
https://www.callicoder.com/spring-boot-actuator-metrics-monitoring-dashboard-prometheus-grafana/
目次
- Actuator を導入せずに IntelliJ IDEA から Tomcat を起動するとどのような状態か?
- build.gradle を変更する
- IntelliJ IDEA から Tomcat を起動して Run Tool Window を確認する
- ログレベルを変更してみる
/actuator/**
を Spring Security の CSRF チェックの対象外にする- ログレベルを変更してみる(続き)
- Info Endpoint から情報を取得してみる
- Shutdown Endpoint からシャットダウンしてみる
- Thread Dump Endpoint からスレッドダンプを出力してみる
/actuator/**
に IPアドレスでアクセス制限をかけるには?- 最後に
手順
Actuator を導入せずに IntelliJ IDEA から Tomcat を起動するとどのような状態か?
IntelliJ IDEA から Tomcat を起動後、画面の下の Run Tool Window 内に表示される「EndPoints」タブの中の「Health」「Mappings」タブを見ると Spring Boot Actuator is not enabled. Add dependency to the spring-boot-actuator to enable it.
のメッセージが表示されています。
build.gradle を変更する
build.gradle の以下の点を変更します。
dependencies { .......... implementation("org.springframework.boot:spring-boot-starter-security") implementation("org.springframework.boot:spring-boot-starter-actuator") runtimeOnly("org.springframework.boot:spring-boot-devtools") ..........
implementation("org.springframework.boot:spring-boot-starter-actuator")
を追加します。
変更後、Gradle Tool Window の左上にある「Refresh all Gradle projects」ボタンをクリックして更新します。
IntelliJ IDEA から Tomcat を起動して Run Tool Window を確認する
今度は「Health」「Mappings」タブ内にデータが表示されるようになりました。
- デフォルトで health check してくれる対象は 50.9.1 Auto-configured HealthIndicator に一覧があります。Elasticsearch、Rabbit、Redis 等もチェックしてくれるようです。
- 現在メールサーバ(smtp4dev)を起動していないので、mail に「Status: DOWN」のアイコンが表示されていました。
- 「Mappings」に表示されている Path の内リンクになっているもの(おそらく GET でアクセス可能なもの?)をクリックすると、ブラウザが起動してドメイン名やポート番号を追加された URL でアクセスしてくれます。大量に表示されていても IntelliJ IDEA の Search 機能が効くのでパスをタイプすると該当するものにジャンプしてくれます(下の例だと
input 03
と入力しています)。これは以外に便利な機能ではないでしょうか。 - webjars は導入していないのですが、
/webjars/**
が表示されていました。Spring Boot Reference Guide を見たところIn addition to the “standard” static resource locations mentioned earlier, a special case is made for Webjars content. Any resources with a path in /webjars/** are served from jar files if they are packaged in the Webjars format.
という記述があり、src/main/resources の下に static ディレクトリを作成すると自動で/webjars/**
の mapping?を作成するようです。初めて知りました。。。
smtp4dev を起動すると mail のアイコンが「Status: UP」のものに変わりました。IntelliJ IDEA で起動している場合にはデフォルトだと 15秒間隔でチェックされます(「Endpoints」タブ内の左側にある歯車アイコンをクリックすると設定画面が表示されます。)。
ログレベルを変更してみる
application.properties に設定を追加して Loggers endpoint を有効にします。
doma.dialect=org.seasar.doma.jdbc.dialect.H2Dialect management.endpoints.web.exposure.include=health,info,loggers spring.datasource.hikari.jdbc-url=jdbc:h2:mem:bootnpmgebdb ..........
management.endpoints.web.exposure.include=health,info,loggers
を追加します。management.endpoints.web.exposure.include
の設定を追加する場合、デフォルトで有効になっている health, info も記述しないと無効になります。
IntelliJ IDEA から Tomcat を再起動した後、ブラウザから http://localhost:8080/inquiry/input/01 にアクセスすると以下のログが出力されます。application-develop.properties に logging.level.org.springframework.web=DEBUG の設定を入れていますので、DEBUG ログが出力されています。
Spring Boot Actuator Web API Documentation を参考に、コマンドプロンプトから curl 'http://localhost:8080/actuator/loggers/org.springframework.web' -i -X POST -H 'Content-Type: application/json' -d '{"configuredLevel":"info"}'
コマンドを実行します。。。が 403 でアクセス拒否されました。Spring Security が入っているので POST メソッドだと CSRF のチェック対象から外さないとアクセスできませんでした。
/actuator/**
を Spring Security の CSRF チェックの対象外にする
src/main/java/ksbysample/webapp/bootnpmgeb/config/WebSecurityConfig.java の以下の点を変更します。http.csrf()
に .ignoringAntMatchers(...)
というメソッドがあることに気づいたのでいろいろ書き直します。
package ksbysample.webapp.bootnpmgeb.config; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; /** * ??? */ @Configuration public class WebSecurityConfig extends WebSecurityConfigurerAdapter { private static final String ACTUATOR_ANT_PATTERN = "/actuator/**"; private static final String H2_CONSOLE_ANT_PATTERN = "/h2-console/**"; @Value("${spring.h2.console.enabled:false}") private boolean springH2ConsoleEnabled; @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() // 認証の対象外にしたいURLがある場合には、以下のような記述を追加します // 複数URLがある場合はantMatchersメソッドにカンマ区切りで対象URLを複数列挙します // .antMatchers("/country/**").permitAll() // // この Web アプリケーションでは Spring Security を CSRF対策で使用したいだけなので、 // 全ての URL を認証の対象外にする .antMatchers("/**").permitAll() .anyRequest().authenticated(); // Spring Boot Actuator のパスは CSRF チェックの対象外にする http.csrf().ignoringAntMatchers(ACTUATOR_ANT_PATTERN); // spring.h2.console.enabled=true に設定されている場合には H2 Console を表示するために必要な設定を行う if (springH2ConsoleEnabled) { http.csrf().ignoringAntMatchers(H2_CONSOLE_ANT_PATTERN); http.headers().frameOptions().sameOrigin(); } } }
private static final Pattern DISABLE_CSRF_TOKEN_PATTERN = Pattern.compile("(?i)^(GET|HEAD|TRACE|OPTIONS)$");
を削除します。private static final String ACTUATOR_ANT_PATTERN = "/actuator/**";
を追加します。private static final Pattern H2_CONSOLE_URI_PATTERN = Pattern.compile("^/h2-console");
→private static final String H2_CONSOLE_ANT_PATTERN = "/h2-console/**";
に変更します。http.csrf().ignoringAntMatchers(ACTUATOR_ANT_PATTERN);
を追加します。http.csrf()
から.requireCsrfProtectionMatcher(...)
を削除し、.ignoringAntMatchers(H2_CONSOLE_ANT_PATTERN)
を追加します。
ログレベルを変更してみる(続き)
再度 curl コマンドを実行すると、今度は 204(No Content)が返ってきました。成功したようです。
ブラウザから http://localhost:8080/inquiry/input/01 にアクセスしてログを出力してみると DEBUG ログが出力されていません。これまで設定を変更して再起動しないと変更できないものと思っていたので、これはちょっと感激です。
curl 'http://localhost:8080/actuator/loggers/org.springframework.web' -i -X GET
コマンドを実行すれば、現在設定されているログレベルが取得できます。
Info Endpoint から情報を取得してみる
Spring Boot Actuator Web API Documentation - 11. Info (info) を参考にコマンドプロンプトから curl 'http://localhost:8080/actuator/info' -i -X GET
コマンドを実行してみます。。。が、何も返ってきませんでした。"git" と "build" の情報が返ってくるものと思ったのですが。
調べてみると Spring Boot Reference Guide に以下の記述を見つけました。build.gradle に設定を追加して情報を生成しないといけないようです。
build.gradle の以下の点を変更します。
plugins { id "java" id "eclipse" id "idea" id "org.springframework.boot" version "2.0.4.RELEASE" id "io.spring.dependency-management" version "1.0.6.RELEASE" id "groovy" id "net.ltgt.errorprone" version "0.0.14" id "checkstyle" id "com.github.spotbugs" version "1.6.2" id "pmd" id "com.moowork.node" version "1.2.0" id "com.gorylenko.gradle-git-properties" version "1.5.1" } .......... // for Doma 2 // JavaクラスとSQLファイルの出力先ディレクトリを同じにする processResources.destinationDir = compileJava.destinationDir // コンパイルより前にSQLファイルを出力先ディレクトリにコピーするために依存関係を逆転する compileJava.dependsOn processResources springBoot { buildInfo() }
- plugins block に
id "com.gorylenko.gradle-git-properties" version "1.5.1"
を追加します。 springBoot { buildInfo() }
を追加します。
変更後、Tomcat を停止してから Gradle Tool Window の左上にある「Refresh all Gradle projects」ボタンをクリックして更新します。
clean タスク → Rebuild Project → build タスクを実行すると bootBuildInfo
と generateGitProperties
というタスクが追加されていました。
Tomcat を起動して、再び curl 'http://localhost:8080/actuator/info' -i -X GET
コマンドを実行してみますがやっぱり何も出ません。どうも Executable Jar から起動しないと何も出ないようです。
Tomcat を停止後 Executable Jar から起動して再度コマンドを実行すると、今度は情報が返ってきました。
JSON がフォーマットされていなくて見にくいので、jq というツールを入れてフォーマットしてみます。Download jq から「Windows」の jq 1.5 executables for 64-bit or 32-bit.
の 64-bit
のリンクをクリックして jq-win64.exe をダウンロードした後、ファイル名を jq.exe に変更して C:\Git\mingw64\bin の下へ入れます。
HTTPヘッダは不要なので -i
オプションを外し、他にも余計な情報を出さないように -s
オプションを付けて curl 'http://localhost:8080/actuator/info' -X GET -s | jq
コマンドを実行するときれいに整形されました。
Shutdown Endpoint からシャットダウンしてみる
application.properties に設定を追加して Shutdown endpoint を有効にします。Shutdown endpoint は management.endpoints.web.exposure.include
に endpoint 名を追加するだけでは有効にならず、management.endpoint.shutdown.enabled=true
も追加する必要があります(Appendix A. Common application properties に記述がありました)。
management.endpoints.web.exposure.include=health,info,loggers,shutdown management.endpoint.shutdown.enabled=true
IntelliJ IDEA から Tomcat を起動後、curl 'http://localhost:8080/actuator/shutdown' -i -X POST
コマンドを実行すると {"message":"Shutting down, bye..."}
のレスポンスが返ってきました。
しかし、Tomcat の方は落ちませんでした。これも Executable Jar から起動しないとダメなのかな。。。
boot-npm-geb-sample-1.0.2-RELEASE.jar を作成し直してコピーしてから、コマンドプロンプトから起動してみます。
curl 'http://localhost:8080/actuator/shutdown' -i -X POST
コマンドを実行すると、
今度は Tomcat が停止しました。ログは IntelliJ IDEA から Tomcat を起動した時と同じく HikariPool-1 - Shutdown completed.
で終わっていました。
ちなみにサービスに登録して起動してから、
curl コマンドを実行して停止してもサービスの画面上は起動したままでした。ログは HikariPool-1 - Shutdown completed.
までは出力されています。
Executable Jar を直接起動している時はきちんと落ちるようですが、IntelliJ IDEA や Windows のサービスから起動している時は落ちたことが起動元のプロセスに伝わらない、ということでしょうか?
Thread Dump Endpoint からスレッドダンプを出力してみる
application.properties に設定を追加して Thread Dump endpoint を有効にします。
management.endpoints.web.exposure.include=health,info,loggers,shutdown,threaddump management.endpoint.shutdown.enabled=true
IntelliJ IDEA から Tomcat を起動後、curl 'http://localhost:8080/actuator/threaddump' -i -X POST
コマンドを実行します。
なんかこれじゃない感が。。。 スレッドダンプと言えばテキスト形式のものだと思っていたので、JSON ではなくテキストのものを返して欲しいのですが、テキストで返す方法は見当たりませんでした。
もしかして最近はスレッドダンプは JSON 形式が常識なのか?と思って調べてみましたが、それらしい記事も見当たらず。その代わり以下の記事を見つけました。IBM Thread and Monitor Dump Analyzer for Java というツールが便利そうです。
- CloudFoundry: Java thread and heap dump analysis on remote containers
- IBM Thread and Monitor Dump Analyzer for Java
試しに Java VisualVM からスレッドダンプを出力してテキストファイルに保存した後、
java -Xmx512m -jar jca457.jar
コマンドで IBM Thread and Monitor Dump Analyzer for Java を起動して保存したスレッドダンプを読み込ませると以下のような感じで表示されます。
2つのタイミングの異なるスレッドダンプを読み込ませて比較表示することも出来るようです。
このツール、全然噂を聞いたことがありませんでした。そんなに有名なツールではないのかな?
/actuator/**
に IPアドレスでアクセス制限をかけるには?
src/main/java/ksbysample/webapp/bootnpmgeb/config/WebSecurityConfig.java に以下のように定義します。
@Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() // アクセス元のホストIPアドレスで指定する場合 .antMatchers(ACTUATOR_ANT_PATTERN).hasIpAddress("127.0.0.1") .antMatchers(ACTUATOR_ANT_PATTERN).hasIpAddress("192.168.56.1") // アクセス元のネットワークIPアドレスで指定する場合 .antMatchers(ACTUATOR_ANT_PATTERN).hasIpAddress("192.168.56.0/24") // アクセス元を複数指定する場合 .antMatchers(ACTUATOR_ANT_PATTERN) .access("hasIpAddress('127.0.0.1') or hasIpAddress('192.168.56.0/24')") ..........
最後に
Health , Loggers, Mappings 等の Endpoint も面白いのですが、Actuator で一番面白そうなのは Prometheus Endpoint を利用して Prometheus と連携してモニタリングすることですよね。他の人が書いたものを見る限りでは簡単に出来るようです。
Spring Boot ってどんどん便利になっていますが、覚えることが多くて大変です。。。 いや、本当に。
Spring Boot Actuator の導入まで終わりましたが、あと以下の点を記述して終わりにする予定です。
- Spring Session が生成している SESSION Cookie の domain 属性や httponly 属性の値を変更する方法の調査
- gradle-processes の Gradle 4.6 以降対応版が出ているようなので正式に導入する
- PMD を 6.6.0 にバージョンアップすると build タスク実行時のメッセージが減るような記述を見かけたので、その検証
履歴
2018/08/09
初版発行。