Upgrade to Pro — share decks privately, control downloads, hide ads and more …

KubernetesでJVMアプリを動かすための実践的ノウハウ集 / JVM on Kubernetes

KubernetesでJVMアプリを動かすための実践的ノウハウ集 / JVM on Kubernetes

CloudNative Days Tokyo 2019 1D3 セッションのスライドです。
#CNDT2019 #OSDT2019 #RoomD

hhiroshell

July 22, 2019
Tweet

More Decks by hhiroshell

Other Decks in Technology

Transcript

  1. Cloud Native Developers JP #CNDT2019 #RoomD 自己紹介 早川 博(はやかわ ひろし)

    • Cloud Nativeな技術スタック担当のプリセールスエンジニア • エンジニアコミュニティ 「Cloud Native Developers JP」 オーガナイザー • Developers Summit 2018、Japan Container Days 12.18 登壇 2 @hhiroshell
  2. Cloud Native Developers JP #CNDT2019 #RoomD 宣伝 • 皆さん自作キーボードやりましょう! 楽しいですよ!

    3 遊舎工房さんの店舗はこちら→ ↓現在の@hhiroshellのキーボード • 本書きました!買って ください! 「Kubernetes実践ガイド」 北山 晋吾(著), 早川 博(著) https://www.amazon.co.jp/dp/B07TSBP3CZ/
  3. Cloud Native Developers JP #CNDT2019 #RoomD お品書き • イントロダクション •

    JVM on Kubernetes ノウハウ集 – JVMコンテナアプリの開発作業を楽にしよう – JVMコンテナをビルドしよう – JVMコンテナをデプロイしよう – JVMコンテナを監視しよう • まとめ 5
  4. Cloud Native Developers JP #CNDT2019 #RoomD JVMとコンテナワークロード • コンテナワークロードに対する一般的な期待 –

    軽量、高可搬性、1コンテナ1プロセス • 従来までのJVMの考え方とコンテナとは相性が良くない面もある – 特にJava EEに代表されるアプリケーションサーバーは、1つのJVM上に複数の アプリケーションを動かすことが想定されている • JVMレイヤー上での可搬性 (.jar, .war, .ear) • JVMレイヤー上での管理・運用機能の作りこみ • 1つのJVMに大きなリソースを割り当てる傾向 JVMをコンテナで動かす場合、注意が必要な点がある 7
  5. Cloud Native Developers JP #CNDT2019 #RoomD Cloud Nativeの世界においてJVMはオワコンか? • メジャーなミドルウェア製品で多く利用されている

    – Kafka、Spark、Casssandra… • モダンなプログラミング言語で、JVMベースのものも多い – Scala、Kotlin… • 開発者のスキルセット – なんだかんだ言って、Javaエンジニアはたくさんいらっしゃる とはいえ避けて通るのは難しい。むしろ使えるのなら使っていきたい 8
  6. Cloud Native Developers JP #CNDT2019 #RoomD JVM on Kubernetesのランドスケープ •

    JVM on Kubernetesの考慮事項は、開発・運用全体に渡る…。 • ひとつずつ見てきます! 11 • ツールを活用して Kubernetesでも効率 よくローカル開発を 行う ② ビルド Build Containers • JVM固有の事情を考 慮しつつ、Dockerfile のベストプラクティ スに従ったコンテナ を目指す ③ デプロイ Deploy Containers • KubernetesでもJVM標 準の監視ツールを利 用する • Cloud Nativeな監視手 法も考慮する • コンテナのリソース 制限機能を考慮して、 適切なJVMパラメー タを設定する • ロールアウト前に暖 機運転を行う ① ローカル開発 Local Development ④ 監視 Monitoring
  7. Cloud Native Developers JP #CNDT2019 #RoomD JVM on Kubernetesのランドスケープ •

    JVM on Kubernetesの考慮事項は、開発・運用全体に渡る…。 • ひとつずつ見てきます! 12 ① ローカル開発 Local Development • ツールを活用して Kubernetesでも効率 よくローカル開発を 行う ② ビルド Build Containers • JVM固有の事情を考 慮しつつ、Dockerfile のベストプラクティ スに従ったコンテナ を目指す ③ デプロイ Deploy Containers ④ 監視 Monitoring • KubernetesでもJVM標 準の監視ツールを利 用する • Cloud Nativeな監視手 法も考慮する • コンテナのリソース 制限機能を考慮して、 適切なJVMパラメー タを設定する • ロールアウト前に暖 機運転を行う
  8. Cloud Native Developers JP #CNDT2019 #RoomD JVMコンテナアプリの開発作業の課題 1. アプリケーションのコードを編集 2.

    ローカルでビルド、自動テスト (Maven/Gradleなどのビルドツールを利用) 3. Dockerfileを編集 (必要な場合) 4. docker build / push 5. 開発用のKubernetesクラスターにデプロイ 6. 動作確認 (→ 1. に戻ってくりかえし) Kubernetes前提のJVMアプリ開発は手間がかかる 14 動作確認のために毎回Kubernetes にデプロイ 成果物をコンテナとしてビル ドする必要あり
  9. Cloud Native Developers JP #CNDT2019 #RoomD Jib + Skaffoldがやってくれること 1.

    アプリケーションのコードを編集 2. ローカルでビルド、自動テスト (Maven/Gradleなどのビルドツールを利用) 3. Dockerfileを編集 (必要な場合) 4. docker build / push 5. 開発用のKubernetesクラスターにデプロイ 6. 動作確認 (→ 1. に戻ってくりかえし) 面倒な作業を自動化してローカル開発を効率よく 15 ここの作業を自動化してくれ る!
  10. Cloud Native Developers JP #CNDT2019 #RoomD Jibとは • Maven/Gradleプラグインとして利用可能な 、JVM言語アプリケー

    ションのコンテナイメージ作成を省力化してくれるツール • 使い慣れたビルドツールでコンテナイメージが作成できる – Dockerfileフリー。使い慣れた記述形式 – Dockerfileのベストプラクティスを知らなくても高品質のコンテナが作れる (JVMアプリとして必要なファイルだけを選択的にコンテナに入れてくれる) • コーディングが滞らない – 高速でコンテナイメージをビルド。ビルド待ちを減らしてコードに集中 Dockerfileの編集とコンテナのビルドから、アプリ開発者を開放 16
  11. Cloud Native Developers JP #CNDT2019 #RoomD Maven/GradleプラグインとしてのJibの利用方法 • Maven/Gradleのプラグインとして Jibを指定

    • 作成するコンテナイメージのプロ パティをプラグインの設定値とし て記述する – mainClass : ENTRYPOINTとなるクラス – ports : コンテナの公開ポート – jvmFlags : JVMに与えるオプション (…etc) 17 plugins { application kotlin("jvm") version "1.3.10" id("com.google.cloud.tools.jib") version "1.0.1" } (…snip…) val main_class by extra("io.ktor.server.netty.EngineMain") (…snip…) Jib { container { ports = listOf(“8080”) mainClass = main_class // good defauls intended for Java 8 containers jvmFlags = listOf( “-server”, “-Djava.awt.headless=true”, “-XX:+UnlockExperimentalVMOptions”, (…snip…) ) } } build.gradle ファイルの記述例 →
  12. Cloud Native Developers JP #CNDT2019 #RoomD Skaffoldとは • docker build/push/deploy

    の一連のコマンド実行を自動化するツール – ローカルのコードの変更を検知して、 docker build/push/deployに相当する処理 を自動実行(クラスタ上のコンテナのホットスワップ)可能 • コーディングが滞らない – コードの編集結果を反映したコンテナが開発用Kubernetesクラスターに自動的 にデプロイされる。コードの修正内容の動作確認がすぐできる 面倒なBuild, Push, Deployを自動化 18
  13. Cloud Native Developers JP #CNDT2019 #RoomD Skaffoldのプラグインアーキテクチャ • SkaffoldはBuild, Push,

    Deployの各フェーズ自動実行する • それぞれのフェーズで実行する処理に様々なツールを選択可能 Build, Push, Deploy各フェーズの処理をプラグイン的に変更できる 19 Build Push Deploy > docker build > docker push > kubectl apply
  14. Cloud Native Developers JP #CNDT2019 #RoomD Build Push Deploy Skaffold

    + Jib • Build, PushのフェーズでSkaffoldを利用できる SkaffoldのプラグインとしてJibを利用 20 Jibを実行 > kubectl apply
  15. Cloud Native Developers JP #CNDT2019 #RoomD 【参考】Jibのイメージ作成の仕組み • ベースイメージに以下のレイヤーを 足したイメージが作られる

    – 依存ライブラリ(.jar) – リソース(.conf, .properties, …etc) – classファイル(.class) (それぞれ別のレイヤー) • ファイルの変更内容に応じて必要な レイヤーを更新するだけなので高速 • 不要なファイルは自動的に除外され る 21 (… snip …) ============================================================ 13 MB $ jib-gradle-plugin:1.0.1 ============================================================ 2.6 MB app/libs/kotlin-reflect-1.3.10.jar 1.2 MB app/libs/kotlin-stdlib-1.3.10.jar 784 kB app/libs/kotlinx-coroutines-core-1.0.1.jar 730 kB app/libs/kotlinx-html-jvm-0.6.11.jar (… snip …) ============================================================ 814 B $ jib-gradle-plugin:1.0.1 ============================================================ 474 B app/resources/logback.xml 333 B app/resources/application.conf 7 B app/resources/hoge.conf ============================================================ 57 kB $ jib-gradle-plugin:1.0.1 ============================================================ 6.0 kB app/classes/example/ktor/AppKt$router$1$4$1.class 4.9 kB app/classes/example/ktor/AppKt$init$1$1.class 4.8 kB app/classes/example/ktor/AppKt$router$1$4$2.class 4.0 kB app/classes/example/ktor/AppKt$router$1$3.class (… snip …) ↑ dlayer(by @orisanoさん) にかけた結果の抜粋 https://github.com/orisano/dlayer
  16. Cloud Native Developers JP #CNDT2019 #RoomD Skaffold + Jibを利用するプロジェクトの例 •

    pom.xml – Jibをプラグインとして設定した mavenプロジェクトの定義 • k8s/web.yaml – Kubernetesクラスターに自動デプロ イするときに利用するManifest • skaffold.yaml – プラグインとしてJibとkubectlを使 うように設定 22 $ cd scaffold-jib-project $ tree . ├── README.adoc ├── pom.xml ├── k8s │ └─ web.yaml ├── skaffold.yaml └── src └─ main └─ java └─ hello ├─ Application.java └─ HelloController.java $ scaffold dev
  17. Cloud Native Developers JP #CNDT2019 #RoomD Jib + Skaffoldがやってくれること 1.

    アプリケーションのコードを編集 2. ローカルでビルド、自動テスト (Maven/Gradleなどのビルドツールを利用) 3. Dockerfileを編集 (必要な場合) 4. docker build / push 5. 開発用のKubernetesクラスターにデプロイ 6. 動作確認 (→ 1. に戻ってくりかえし) 面倒な作業を自動化してローカル開発を効率よく 23 ここの作業を自動化してくれ る!
  18. Cloud Native Developers JP #CNDT2019 #RoomD JVM on Kubernetesのランドスケープ •

    JVM on Kubernetesの考慮事項は、開発・運用全体に渡る…。 • ひとつずつ見てきます! 25 • ツールを活用して Kubernetesでも効率 よくローカル開発を 行う ② ビルド Build Containers • JVM固有の事情を考 慮しつつ、Dockerfile のベストプラクティ スに従ったコンテナ を目指す ③ デプロイ Deploy Containers • KubernetesでもJVM標 準の監視ツールを利 用する • Cloud Nativeな監視手 法も考慮する • コンテナのリソース 制限機能を考慮して、 適切なJVMパラメー タを設定する • ロールアウト前に暖 機運転を行う ① ローカル開発 Local Development ④ 監視 Monitoring
  19. Cloud Native Developers JP #CNDT2019 #RoomD JVMコンテナをビルドする上での指針 • Dockerコンテナをビルドするときの一般的な指針に従うのが基本 –

    Dockerfileを書くためのベストプラクティス(公式) • エフェメラル(使い捨て型)コンテナを作成すべし • …etc • JVMのコンテナの場合、コンテナのフットプリントを小さくするた めにJVM固有のノウハウが必要 – 適切なベースイメージの選択 – カスタムJREによるフットプリントの削減 – (もっと発展的なJVMコンテナのビルド手法…) JVM固有の事情を考慮しつつ、Dockerfileのベストプラクティスの実現を目指す 26
  20. Cloud Native Developers JP #CNDT2019 #RoomD 適切なベースイメージを選択しよう • LTSならheadless(軽量OS版)やJREが選択可能。LTS以外は要件に合わせて 公式リポジトリからベースイメージを選択する場合、LTS

    + headlessがおすすめ 27 ベースイメージ 8 LTS 11 LTS 12 13 (EA) 14 (EA) Debian JRE/JDK JRE/JDK Debian (headless) JRE/JDK JRE/JDK Oracle Linux 7 JDK JDK JDK Alpine 3.10 JDK JDK Windows Server Core 1803 JRE/JDK JRE/JDK JDK JDK JDK Windows Server Core 1809 JRE/JDK JRE/JDK JDK JDK JDK Windows Server Core LTSC2016 JRE/JDK JRE/JDK JDK JDK JDK Docker公式リポジトリで公開されているOpenJDKイメージ https://k11i.biz/blog/2018/05/17/base-docker-images-for-java/ をベースに2019/07/18時点の情報に更新
  21. Cloud Native Developers JP #CNDT2019 #RoomD 【参考】Project Portola • Alpine/muslで可動するOpenJDKを開発する、

    OpenJDK配下の取り組み – Alpine Linuxとmusl Cライブラリを利用すること で、ベースイメージの大幅軽量化を目指す – 現在プロトタイプの開発が進められている – https://openjdk.java.net/projects/portola/ Alpineを利用してJVMコンテナの大幅軽量化を目指す 28
  22. Cloud Native Developers JP #CNDT2019 #RoomD カスタムJREを作成してサイズを落とそう • デフォルトのJDKの全機能は、多くのアプリケーションでは不要 –

    必要なもの: java.{lang,util,…}.*, javax.management.*, … – 不要なもの: corba, jaxws, … • JDK9でモジュールシステム(“Jigsaw”)が導入された – JDK自体をモジュール化するとともに、必要なモジュールだけを含むカスタム JREを生成するツール(jdeps/jlink)を提供 JDKの標準機能でフットプリント削減が可能 29
  23. Cloud Native Developers JP #CNDT2019 #RoomD jdeps / jlink •

    jdeps: – アプリケーションの.classや.jarファイルを解析して、依存するJVMモジュール を特定する • jlink: – 指定したJVMモジュールだけを含む、カスタムJREを生成する カスタムランタイムを作るためのJDK標準ツール 34 $ ${JAVA_HOME}/bin/jdeps target/cowweb.jar cowweb.jar -> java.base cowweb.jar -> java.logging … $ ${JAVA_HOME}/bin/jlink --output cowweb-jre --add-modules java.base,java.logging
  24. Cloud Native Developers JP #CNDT2019 #RoomD 35 Dockerfile内でカスタムJREを作成する例 $ cat

    target/Dockerfile FROM openjdk:11-jdk-slim AS jre-builder WORKDIR /jlink RUN jlink --output cowweb-jre --add-modules java.base,java.desktop,java.logging,java.management FROM debian:buster-slim WORKDIR /workdir COPY --from=jre-builder /jlink/cowweb-jre /opt/cowweb-jre ENV PATH /opt/cowweb-jre/bin:$PATH RUN mkdir /app COPY libs /app/libs COPY cowweb.jar /app CMD ["java", "-jar", "/app/cowweb.jar"]
  25. Cloud Native Developers JP #CNDT2019 #RoomD カスタムJREを使ったコンテナのサイズ • Helidonを使ったシンプルなREST APIアプリケーションの例

    – 144.8 (214 – 69.2) [MB] -> 89.8 (159 – 69.2) [MB] (JVMのサイズを約38%削減) 36 $ docker images | grep -e cowweb -e debian hhiroshell/cowweb v2.1-custom-jre 0233250b4900 3 minutes ago 159MB hhiroshell/cowweb v2.1 4af060beb2eb About an hour ago 214MB debian buster-slim 83ed3c583403 9 days ago 69.2MB
  26. Cloud Native Developers JP #CNDT2019 #RoomD • Jib – JibとカスタムJREを組み合

    わせることも可能 – Jibの設定で、ベースイ メージとしてカスタムJRE が入ったコンテナを指定 する • Native Image – GraalVMのNative Image生 成機能を利用 – ランタイムとアプリケー ションをまとめてバイト コード化してシングルバ イナリを生成する→これ をコンテナに入れる – 起動初期の劇的な高速化 とフットプリント削減 37 • SubstrateVM – JVMを必要なコンポーネ ントだけに絞って自力で ビルドする – 使わないJITコンパイラ、 GCアルゴリズム、などを 削りに削ると5MBくらい のランタイムを作成可能 – ご利用は用法用量を守っ て計画的に もっと発展的なJVMコンテナのビルド手法
  27. Cloud Native Developers JP #CNDT2019 #RoomD JVM on Kubernetesのランドスケープ •

    JVM on Kubernetesの考慮事項は、開発・運用全体に渡る…。 • ひとつずつ見てきます! 39 • ツールを活用して Kubernetesでも効率 よくローカル開発を 行う ② ビルド Build Containers • JVM固有の事情を考 慮しつつ、Dockerfile のベストプラクティ スに従ったコンテナ を目指す ③ デプロイ Deploy Containers • コンテナのリソース 制限機能を考慮して、 適切なJVMパラメー タを設定する • ロールアウト前に暖 機運転を行う • KubernetesでもJVM標 準の監視ツールを利 用する • Cloud Nativeな監視手 法も考慮する ① ローカル開発 Local Development ④ 監視 Monitoring
  28. Cloud Native Developers JP #CNDT2019 #RoomD JVMコンテナをKubernetesにデプロイしよう • コンテナのリソース制限機能を考慮して、適切なJVMパラメータを 設定する

    – コンテナレベルのCPU/メモリのリソース制限 • ロールアウト前に暖機運転を行う コンテナのリソース制限と暖機運転に注意する 40
  29. Cloud Native Developers JP #CNDT2019 #RoomD チューニングパラメータの指針 • リソース制限(ここではCPU、ヒープメモリ、スレッド) –

    かつてのJVMはcgroupsによるリソース分離を認識しなかったので、CPU利用量 やヒープメモリサイズなどのリソースの設定に注意が必要だった – JDK10以降コンテナランタイムのリソース制限の設定を認識する改善が導入 → 改善後のJVMの挙動を理解してコンテナのリソース制限に適切な設定を JVMをいじるのはその後で • GC – 1コンテナに割り当てるリソース量は、JVMが元来想定していた量より小さい → GCアルゴリズムの選択を再確認しよう コンテナのリソース制限を考慮して、適切な設定を 41
  30. Cloud Native Developers JP #CNDT2019 #RoomD Docker/cgroups リソース制限を考慮した設定 - CPU

    • JDKが認識してくるコンテナのCPU制限の設定 – --cpus, --cpu-shares, --cpu-quota • KubernetesでResource Quotaを設定するとコンテナの--cpu-sharesに マッピングされる。これをJVMが認識して動作する • 結果として、Runtime.availableProcessors()の返り値や、ForkJoinプール、 スレッドプールの割当量が変わる これらに依存して挙動を変えているライブラリやフレームワークも 影響を受ける (e.g. core.async, ElasticSearch, Netty) コンテナでCPU割り当て制限が行われた結果をJVMが認識する 42
  31. Cloud Native Developers JP #CNDT2019 #RoomD Docker/cgroups リソース制限を考慮した設定 – メモリ

    • JDKが認識してくるコンテナのメモリ制限の設定 – --memory • KubernetesでResource Quotaを設定するとコンテナの-mオプションに マッピングされる。これをJVMが認識して動作する • JVMのヒープメモリの設定は、コンテナに割り当てられたメモリ量 に対してエルゴノミクスによって決定される(JVMのデフォルトの 挙動) • チューニングが必要な場合は、追加で起動オプションを設定する コンテナでメモリ割り当て制限が行われた結果をJVMが認識する 43
  32. Cloud Native Developers JP #CNDT2019 #RoomD 44 Docker/cgroups リソース制限を考慮した設定 $

    cat target/cowweb.yaml kind: Pod apiVersion: v1 metadata: name: cowweb spec: containers: - name: cowweb image: hhiroshell/cowweb:2.1-jdk ports: - containerPort: 8080 resources: requests: cpu: 1000m memory: 512Mi limits: cpu: 1000m memory: 512Mi $ kubetl apply -f target/cowweb.yaml pod/cowweb created $ kubectl exec -it cowweb jshell Jul 20, 2019 4:11:38 PM java.util.prefs.FileSystemPreferences$1 run INFO: Created user preferences directory. | Welcome to JShell -- Version 11.0.4 | For an introduction type: /help intro jshell> Runtime.getRuntime().availableProcessors() $1 ==> 1 jshell> Runtime.getRuntime().maxMemory() $1 ==> 129761280
  33. Cloud Native Developers JP #CNDT2019 #RoomD GC • コンテナでJVMアプリを動かす場合、リソースの割当量が比較的小 さいため、シリアルGCなどの少リソース向けのGCアルゴリズムが適

    している場合がある – e.g) JDK11で1CPU, 512MBをコンテナに割り当ててJVMのデフォルトに任せる と、シリアルGCが選択される • リソース割り当て量とGCアルゴリズムの選択の考え方は、古くから ある議論。先達の知恵から学びましょう…。 – 参考資料: 「Javaパフォーマンス」/ Scott Oaks 著 少リソースで実行されるケースに合わせて、GCアルゴリズムに改めて注意 45
  34. Cloud Native Developers JP #CNDT2019 #RoomD JITコンパイラ ロールアウトで気にすべきこと • JVMアプリケーションが最大の性能を発揮するには暖機運転が必要

    – JVMは、実行中のプロファイルを参考にしながら、アプリケーションのコード を動的にバイトコードに変換している (c.f. JIT(Just in Time)コンパイラ) – コンパイルが進んでいない初期のJVMコンテナは理想的な性能を発揮しない 暖気運転をしていないJVMは理想的なパフォーマンスを発揮しない 46 001000111010101101 010001011101010111 010100101010000110 010101010101001101 0101000101010101… 実行時プロファイル
  35. Cloud Native Developers JP #CNDT2019 #RoomD Kubernetes標準のルーティングで起きる問題 • スケールアウトで追加された直後のPodにも他と同量のトラフィック が分配され、処理が追いつかない場合がある

    • 最悪Liveness Probeへの応答ができず、Podが再起動されてしまう • 対策は2つ – 暖機運転を自動化して、それが完了してからトラフィックを回す – トラフィックの配送量を制御する → Service Mesh 暖気運転が済んでいないJVMコンテナを高負荷に晒さない工夫を行う 47 Service トラフィック 追加したばかりのPodにも他と 同量のトラフィックが送られる
  36. Cloud Native Developers JP #CNDT2019 #RoomD 暖機運転の自動化 • Podが起動したらReadiness ProbeがOKとなる前にサイドカーコンテナ

    から暖機運転のトラフィックを送る • 暖機運転が完了したあとでReadiness ProbeがOKとなるようにする – 暖機運転完了までの十分なinitialDelaySecondsを設定する (または – 暖機運転が完了したら、サイドカーコンテナのReadiness ProbeをOKとする 48 Service トラフィック ① サイドカーコンテナから暖気 のトラフィックを送る ② Readiness ProbeがOKになるとServiceから トラフィックが送られるようになる
  37. Cloud Native Developers JP #CNDT2019 #RoomD 49 暖機運転を自動化するmanifestの記述例 kind: Deployment

    (... snip ...) spec: (... snip ...) template: (... snip ...) spec: containers: - name: cowweb image: hhiroshell/cowweb:2.1 (... snip ...) readinessProbe: httpGet: path: /health port: http initialDelaySeconds: 180 periodSeconds: 10 livenessProbe: httpGet: path: /health port: http initialDelaySeconds: 5 periodSeconds: 15 (左からの続き) - name: warmup image: radial/busyboxplus:curl command: ['/bin/sh', '-c'] args: ['sleep 15; for i in `seq 0 10000`; do curl "http://localhost:8080/cowsay/say"; done; tail -f /dev/null;'] • Readiness ProbeがOKとなるまで、Service経由で のPodへのトラフィックが流れないことを利用 し、Readiness Probeが開始されるまでの間にサ イドカーコンテナから暖気をかけている • (※)理想的には、サイドカーにReadiness Probeを設定しておいて、暖気が終わったらそ ちらをOKにする方が良いです。確実に暖気が 終わったところでトラフィックを流せます
  38. Cloud Native Developers JP #CNDT2019 #RoomD Service Meshによるトラフィックの制御 • IstioなどのService

    Meshを利用すると、Podに流すトラフィックの割 合を1%単位で調整できる – 追加したばかりのPodには少量のトラフィックを送り、暖気が進んできた段階 で徐々に増やす(カナリーデプロイメントに似たやり方) • 本番のトラフィックを暖気に利用するので、理想的な最適化が期待 できる 50 Virtual Service トラフィック 追加したばかりのPodには少量のトラ フィックを送り、徐々に増やす 99 % 1 %
  39. Cloud Native Developers JP #CNDT2019 #RoomD JVM on Kubernetesのランドスケープ •

    JVM on Kubernetesの考慮事項は、開発・運用全体に渡る…。 • ひとつずつ見てきます! 51 • ツールを活用して Kubernetesでも効率 よくローカル開発を 行う ② ビルド Build Containers • JVM固有の事情を考 慮しつつ、Dockerfile のベストプラクティ スに従ったコンテナ を目指す ③ デプロイ Deploy Containers • コンテナのリソース 制限機能を考慮して、 適切なJVMパラメー タを設定する • ロールアウト前に暖 機運転を行う • KubernetesでもJVM標 準の監視ツールを利 用する • Cloud Nativeな監視手 法も考慮する ① ローカル開発 Local Development ④ 監視 Monitoring
  40. Cloud Native Developers JP #CNDT2019 #RoomD JVMコンテナを監視しよう • KubernetesでもJVM標準の監視ツールを利用可能(ただし一工夫必要) –

    jcmd, jstackなどの基本的なツール – JFR (Java Flight Recorder) • Cloud Nativeな監視手法も考慮する – Prometheusによるメトリック監視 – OpenTracing準拠のトレーサーによる分散トレーシング → 各言語のフレームワークやライブラリでサポートされる方式があるのでそち らでの説明に譲りますm(_ _)m 目的やスキルセットに合わせて複数の手段を使い分ける 53
  41. Cloud Native Developers JP #CNDT2019 #RoomD 標準的なJVM監視ツールをKubernetesで利用する • jcmd, jstackなどJDK付属の基本的なツールを使う場合、JDKのコンテ

    ナをサイドカーとして追加してそのコンテナからツールを実行する (アプリケーションのコンテナにツールが含まれていないケースがあるため) • トラブルシューティングの場面で活躍 従来どおりのツールでトラブルシューティングできるが一工夫が必要 54 Service カスタムJREの アプリコンテナ 監視ツールが入ったサイドカーコンテナ 経由で監視ツールを実行 JDKのコンテナ kubectl exec –it /bin/sh jmcd
  42. Cloud Native Developers JP #CNDT2019 #RoomD 55 サイドカーコンテナからのJDK標準ツールの利用 $ cat

    target/cowweb.yaml kind: Pod metadata: name: cowweb (... snip ...) spec: (... snip ...) shareProcessNamespace: true containers: - name: cowweb image: hhiroshell/cowweb:v2.1 (... snip ...) - name: jtoolings image: openjdk:11-jdk-slim command: ['/bin/sh'] securityContext: capabilities: add: - SYS_PTRACE stdin: true tty: true $ kubetl apply -f target/cowweb.yaml pod/cowweb created $ kubectl exec -it cowweb -c jtoolings /bin/sh # jps 8 cowweb.jar 10127 Jps # jcmd 8 VM.flags 8: -XX:CICompilerCount=2 -XX:InitialHeapSize=8388608 - XX:MaxHeapSize=134217728 -XX:MaxNewSize =44695552…
  43. Cloud Native Developers JP #CNDT2019 #RoomD 【参考】よく使うコマンド • $ jcmd

    [プロセスID] VM.system_properties – System.getProperties()を通じて得られるのと同じ情報が出力される – コマンドラインで –D オプションとともに指定されたプロパティとアプリケー ションによって動的に追加されたプロパティ、 JVMごとのデフォルトのプロ パティがすべて含まれる • $ jcmd [プロセスID] VM.command_line – 実行時のコマンドライン引数を出力する • $ jcmd [プロセスID] VM.flags [-all] – 有効化されているJVMのチューニングフラグを出力する • $ jstack [プロセスID] – スレッドスタックを出力する 56
  44. Cloud Native Developers JP #CNDT2019 #RoomD Java Flight Recorder(JFR)を使ったプロファイリング •

    JFRとは – JVMのプロファイリングやイベント収集のためのフレー ムワーク – .jfrという形式のプロファイルデータとして、JVMとアプ リケーションの詳細な実行記録を取得 – アプリケーションの実行中に記録の開始、停止、.jfrの ダンプが実行可能 – Oracle JDKの商用機能だったがJDK11からOpenJDKに寄贈 され無償で利用可能に – 本番環境での豊富な利用実績 JFR → JVMの強力なプロファイリングツール 57
  45. Cloud Native Developers JP #CNDT2019 #RoomD Kubernetes上でJFRを利用するときの構成 • .jfrはjcmdコマンドで取得。Volumeをマウントしてそこに出力する •

    GUIとプログラムから.jfrにアクセス可能 58 JVMアプリ (カスタムJRE) .jfrの保存 kubectl exec –it cowweb -c jtoolings /bin/sh Flight Recordingの開始・停止・.jfrのダンプ Kubernetesクラスター jcmd JMC(GUIツール)による解析 JFR APIによる解析 JDK Javaプログラム + JFR API
  46. Cloud Native Developers JP #CNDT2019 #RoomD JFRファイルの出力と収集 • jcmdの各種コマンドでFlight Recordingの開始、終了、.jfrのダンプな

    どが行える – .jfrファイルはダンプすることによって取得する – 起動オプションを設定することでJVM起動時からFlight Recordingを開始するこ とも可能 • Kubernetes上で利用する場合 – .jfrのダンプを手動・自動実行するサイドカーコンテナを用意する – ダンプする先をコンテナ外の永続ストレージにしておく – カスタムJREでアプリを動かす場合 jlinkに --bind-services オプションを追加する 59
  47. Cloud Native Developers JP #CNDT2019 #RoomD JVM起動直後からFlight Recordingを開始する例 60 kind:

    Pod metadata: name: cowweb (... snip ...) spec: (... snip ...) containers: - name: cowweb image: hhiroshell/cowweb:2.1 command: ['java', '-XX:StartFlightRecording=name=cowweb,filename=/jfr/jfr-cowweb.jfr, ¥ delay=30s,maxage=2h,maxsize=10m,dumponexit=true', '-jar', '/app/cowweb.jar’] (... snip ...) volumeMounts: - name: jfr-volume mountPath: /jfr (... snip ...) volumes: - name: jfr-volume nfs: server: 10.0.40.8 path: “/jfr-example"
  48. Cloud Native Developers JP #CNDT2019 #RoomD JFRの解析 1/2 • Java

    Mission Control を使った解析 – JMCはJFRを解析する ためのGUIツール – トラブル発生時後の 原因究明に適してい る グラフィカルなGUIツールを使った解析 61
  49. Cloud Native Developers JP #CNDT2019 #RoomD JFRの解析 2/2 • JFR

    APIを利用する例 • → JFR Exporterを実装することも不可能ではない…。 JFR APIを利用すると、Javaプログラムから .jfrファイルを読むことができる 62 (...snip...) import jdk.jfr.consumer.RecordedEvent; import jdk.jfr.consumer.RecordingFile; public final class Main { (...snip...) void printG1GCEvents() throws IOException { List<RecordedEvent> gcEvents = RecordingFile.readAllEvents(Paths.get("/jfr/jfr-cowweb.jfr")).stream() .filter((e) -> e.getEventType().getName().equals("jdk.G1GarbageCollection")) .collect(Collectors.toList()); gcEvents.forEach(System.out::println); } (...snip…) }
  50. Cloud Native Developers JP #CNDT2019 #RoomD まとめ • たくさんありますが、頑張っていきましょう! 63

    • ツールを活用して Kubernetesでも効率 よくローカル開発を 行う ② ビルド Build Containers • JVM固有の事情を考 慮しつつ、Dockerfile のベストプラクティ スに従ったコンテナ を目指す ③ デプロイ Deploy Containers • コンテナのリソース 制限機能を考慮して、 適切なJVMパラメー タを設定する • ロールアウト前に暖 機運転を行う • KubernetesでもJVM標 準の監視ツールを利 用する • Cloud Nativeな監視手 法も考慮する ① ローカル開発 Local Development ④ 監視 Monitoring
  51. Cloud Native Developers JP #CNDT2019 #RoomD 参考文献 • 「Java in

    a World of Containers」 – https://www.slideshare.net/oracle4engineer/java-in-the-world-of-container-by- david-buck • 「Better Containerized JVMs in JDK10」 – http://blog.gilliard.lol/2018/01/10/Java-in-containers-jdk10.html • 「Javaパフォーマンス」 – https://www.oreilly.co.jp/books/9784873117188/ • 「備えあれば憂いなし!Javaトラブルシューティングはじめの一 歩」 – http://otndnld.oracle.co.jp/ondemand/javaday2017/D1-F3_JavaDayTokyo2017 66
  52. Cloud Native Developers JP #CNDT2019 #RoomD 参考文献 • 「最適な Java

    の Docker イメージを選びたい」 – https://k11i.biz/blog/2018/05/17/base-docker-images-for-java/ • 「Dockerfileを書くためのベストプラクティス 解説編」 – https://www.slideshare.net/zembutsu/explaining-best-practices-for-writing- dockerfiles • 「Dockerfileを改善するためのBest Practice 2019年版」 – https://www.slideshare.net/zembutsu/dockerfile-bestpractices-19-and-advice 67