見出し画像

2020-06-16 JSUG勉強会 2020年その5 Spring Boot 2.3 徹底解説 #jsug

2020/06/16 に開催された JSUG勉強会 2020年その5 Spring Boot 2.3 徹底解説 のイベントレポートです。

●イベント概要
2020年5月にSpring Boot 2.3がリリースされました!
これを記念してBoot 2.3の新機能+αをご紹介します。

セッション概要
Deep dive into Spring Boot 2.3
先月リリースされたSpring Boot 2.3の新機能の詳細を解説します。
・Kubernetes Support (Liveness/Readiness Probe, Graceful shutdown)
・Docker Image Support (Cloud Native Buildpack, Layered Jar Format)
・その他の細かい変更
・2.3へのアップデートの注意点
Spring Boot 2.2までを使っている方を想定して話します。


■Deep dive into Spring Boot 2.3

Toshiaki Maki さん [VMware]

※スライドはURLが変更になることがあので、ブログのリンクから参照してくださいとのことでした。

●Release Cadence Change
・もともと
  一年に1回
  Spring Frameworkに合わせてマイナーバージョンがあがる
→ 半年に一回に変更

●主な変更内容
・k8s support
・Livenes / Readiness Probe のサポート
・Graceful Shutdown のサポート
・k8sではなくても使える

●Livenes / Readiness Probe のサポート
・Actuator Healthcheck
  /actuator/health でアクセス
  アプリが利用する外部サービスの状態をチェックするもの
  複数のHealthIndicatorの集約結果
・k8sでこの結果を利用すると
  外部のサービスのチェックで、自身のコンテナを再起動
  これでは回復しない
・Liveness State
  内部の状態を返す
  NGの場合、再起動されるべき
・Readines State
  Trafficを受けられう状態かを返す
  NGの場合、Trafficは遮断されるべき
・Application Startのフェーズ
  Starting
    Liveness: BROKEN
    Readiness: REFUSING_TRAFFIC
  Started
    Liveness: CORRECT
    Readiness: REFUSING_TRAFFIC
  Ready
    Liveness: CORRECT
    Readiness: ACCEPTING_TRAFFIC
・Application EventFlow
  Application Starting Event
  Environmentが利用可能になった
  Context作成後
  Bean定義のload後
  Application, Command Runner実行前
  LivenesState.CORRECT
  Application, Command Runner実行後
    ウォームアップなど
    Trraficを受け付ける前に実行したい処理を定義できる
  ReadinesState.ACCEPTING_TRAFFIC
・エンドポイント
  /actuator/health/Liveness
  /actuator/health/readiness
・デフォルトはOFFになっている
  k8s環境にデプロイするとON
・設定
  management.health.probes.enabled=true
  spring.main.cloud-platform=kubernetes
・/actuator/health
  これらの結果も集約
・プログラムからコンテナを再作成させる
  AcailabilityChangeEvent.publishで
  LivenessState.BROKEN
・k8sで任意のコマンドをprobeに指定する場合
  cat /tmp/ready を指定する例
  @EventListenerメソッドで
    ACCPTING_TRAFFICだったらファイル作成
    REFUSING_TRAFFICだったらファイル削除
  のような使い方もできる
・どうしても外部のサービスのチェックを含めたい場合
  できるだけ外部は見ない
  前提となるサービスが起動していないといけないなど
  management.endpoint.health.group.readiness.include
   =readinessState,db,redis

●GracefullShutdown

画像1

・shutdownが動き始めてから
  新しいリクエストが来たり
  処理中のリクエストが残っていたり
・SpringBoot2.2 まで
  ServletContainerごとにハックしていた

画像2

・Shutdownの前にGraceful Shutdown処理ができた
  application.properties
    server.shutdown=graceful
    spring.lifecycle.timeout-per-shutdown-phase=10s
  デフォルトは30s
  k8sは30s、CloudFoundryは10s
  プラットフォームに合わせて設定

●configuration fileのワイルドカード読み込みをサポート
・ConfigMapで用途別のpropsを用意したい場合に便利
・デフォルトで /config/*/application.properties をロード
  /config/redis/application.properties
  /config/mysql/application.properties
  など

●Docker Image Support
・CloudNative Buildpacks
・Layered Jar Format

●CloudNative Buildpacks
・よくあるだめなDockerfile
FROM openjdk:8-jdk-alpine
COPY target/*.jar app.jar
ENTRYPOINT ["java", "-Xmx2g", "-jar", "app.jar"]
・本格的には100行+必要
  Dockerfile Best Practices でも足りない
  これをコピペして管理、、、
・CloudFoundry、Herokuではソースからcontainer imageをつくっている
  Here is my source code
  Run it on the cloud for me
  I do not care how
  → Buildpack
・Cloud Native Buildpacks
  OCI標準のコンテナイメージに変換
  ポータビリティ、ビルド高速化、ローカル環境でh実行可能
  ベストプラクティスで書いたものと同等
・maven/gradle pluginを追加
  paketoを利用
  mvn package の代わりに
  mvn spring-boot:build-image
  で jar + OCI image
・pomに合わせてJREダウンロード
  BellSoft Liberica
  IntelliJ ideaと同じもの
・ヒープサイズとノンヒープサイズを算出
  コンテナのメモリサイズ、jarのクラスファイル数から
・Dockerfileでつくったimageとの違い
  docker push, pull が早い!
  dockerfile
    base image
    + 再利用されない中間layer
    + app
  CloudNative Buildpacks
    base image
    + 再利用される中間Layer
      JRE, Memory Calculator, JVMKill ...
    + app
・コンテナでJavaアプリに必要なメモリの考え方

画像3

  コンテナのメモリ 1024MB
    Javaアプリのメモリ
      Heapは少ない
      Non Heapが複数
    Java以外(Head Room)
  -Xmx, -XX:MaxMetaSpaceSize, ReservedCodeCacheSize...
    設定しきれない、、、
・Memory Calculatorが自動設定
  MetaSpace
    class数から計算
  ThreadStack
    スレッド数の掛け算で計算が必要
    デフォルトは 250 thread
    = tomcatのmax200 + 周辺
  コンテナのメモリサイズが不足すればエラーになる
    デフォルトだと 700m程度のメモリサイズが必要
    docker run -m 512m -e BPL_JVM_THREAD_COUNT=30
    docker run -m 256m -e JAVAOPS="-XX:ReservedCodeCacheSize=32M -Xss512k"
  指定できる環境変数はbuild時のログに出ている
・JVMKill Agent
  OutOfMemoryError
  動けないのにプロセスが残って、ずっとタイムアウト
  プロセスをkillするべき
  設定
    -XX:+ExitOnOutOfMemoryError
    -XX:OnOutOfMemoryError='kill -9 %p'
  この代わりにkillするJVMTI Agent

●Layered Jar Format
・CloudNativeBuildpacksで
 アプリケーション以外のlayerが再利用されるようになった
・アプリケーションのlayer
  dependencies
  spring-boot-loader
  snapshot-dependencies
  application
・これらを分ければ更に効率が良い
  サンプルでpushするレイヤーサイズは KB単位に
・利用方法
  pom.xml
  spring-boot-maven-plugin/
    configration/layered = true
・それでもDockerfileを書きたい
  jar -Djarmode=layertools で、レイヤーを分けて展開できる
  dockerfileでmultistage buildすれば、手書きにも利用できる

●その他の変更点
・Java 14 support
・Spring Dataの各実装がアップグレード
  R2DBC, Couchbase v3, Cassandra v4,
  MongoDB 4, Elasticsearch 7.5+
  このサイクルに追いつくのがケーデンス変更の目的の一つ
・Spring Security 5.3
・RSocket 1.0
・Micometer 1.5

●2.3に上げるときの注意点
・デフォルトのエラーメッセージが空になった
  誤って重要な内容をメッセージで表示してしまったりを防ぐ
  server.error.include-message
  server.error.include-binding-errors
     always, never, on_param
・spring-boot-starter-validationが含まれなくなった
  あまり使われていない、起動に時間がかかる
  bean validationが必要な場合は、dependency追加
  Hibernete Validation 6.1から日本語メッセージ対応
    -Duser.language=en でもとに戻る
・BootstrapMode for JPA repositories
  spring.data.jpa.repositories.bootstrap-mode=deffered になった
・spring-boot-properties-migrator
  非推奨になった設定項目をログに出してくれる

●Wavefront Spring Boot Starter
・SaaSのモニタリングサービス
  フリーミアムアカウントをSpring Boot経由で作成できる
  すぐにRED method
  すぐに分散トレーシング
  フリーアカウントは容量制限あり
・接続情報はログに出る
  application.properties に貼って
  同じWavefrontプロジェクトにデータを送る
  invite userで自分を招待しておくと便利

●Spring GraalVM Native 0.7
・Springのwebアプリケーションを高速に起動
・これまでは、色々変更してnative imageをつくっていた
  JVM切り替え、設定変更など
・多くのアプリが、変更なしでビルドできるように
  サンプルのpetclinicも変更なしでOK
・消費メモリが小さくなった
・ビルド用コンテナ
  localを汚さないで済む
・SpringCloud Functionもサポート
  AWS lambdaでも動かせるっぽい
・jafu
  DSLで記述
  最速のwebapp 0.02sec
    他のサンプルで0.4sec程度

コミュニティで上がった声がどんどん実装されていく
spring bootをアップデートするだけで利用できるのはありがたい


■感想

久しぶりにSpring Bootの状況を知りましたが、めちゃくちゃ便利になってますね!k8s、OCIサポートも手厚い!

wavefrontは知りませんでしたが、フリーで、サクッとRED methodに沿って始められて、分散トレーシングもできるならかなり便利そうですね。

支援先の調査で TKG / TAS → PKS / PAS → CFCR / CFAR / BOSH と遡って、先週から情報を追いはじめました。cfdevでサンプルのjavaアプリをデプロイした時に、かなりメモリを割り当てないとデプロイできなかったのですが、今回の説明で Memory Calculator の設定をしてなかったからだと理解できました。設定方法もさっと教えていただけてとても助かりました!

サンプル

Makiさん、運営の皆さん、ありがとうございました!


この記事が参加している募集

いつも応援していただいている皆さん支えられています。