CloudNative Days Tokyo 2019 1D3 セッションのスライドです。 #CNDT2019 #OSDT2019 #RoomD
Cloud Native Developers JPKubernetesでJVMアプリを動かすための実践的ノウハウ集@hhiroshell1CloudNative Days Tokyo 2019 [1D3] #CNDT2019 #RoomD
View Slide
Cloud Native Developers JP#CNDT2019 #RoomD自己紹介早川 博(はやかわ ひろし)• Cloud Nativeな技術スタック担当のプリセールスエンジニア• エンジニアコミュニティ 「Cloud Native Developers JP」 オーガナイザー• Developers Summit 2018、Japan Container Days 12.18 登壇2@hhiroshell
Cloud Native Developers JP#CNDT2019 #RoomD宣伝• 皆さん自作キーボードやりましょう!楽しいですよ!3遊舎工房さんの店舗はこちら→↓現在の@hhiroshellのキーボード• 本書きました!買ってください!「Kubernetes実践ガイド」北山 晋吾(著), 早川 博(著)https://www.amazon.co.jp/dp/B07TSBP3CZ/
Cloud Native Developers JP#CNDT2019 #RoomDご注意• このプレゼンテーションにおけるJDK/JREは、特に断りのない場合OpenJDKを指しているものとしてご理解ください4
Cloud Native Developers JP#CNDT2019 #RoomDお品書き• イントロダクション• JVM on Kubernetes ノウハウ集– JVMコンテナアプリの開発作業を楽にしよう– JVMコンテナをビルドしよう– JVMコンテナをデプロイしよう– JVMコンテナを監視しよう• まとめ5
Cloud Native Developers JP#CNDT2019 #RoomDイントロダクション6#CNDT2019 #RoomD
Cloud Native Developers JP#CNDT2019 #RoomDJVMとコンテナワークロード• コンテナワークロードに対する一般的な期待– 軽量、高可搬性、1コンテナ1プロセス• 従来までのJVMの考え方とコンテナとは相性が良くない面もある– 特にJava EEに代表されるアプリケーションサーバーは、1つのJVM上に複数のアプリケーションを動かすことが想定されている• JVMレイヤー上での可搬性 (.jar, .war, .ear)• JVMレイヤー上での管理・運用機能の作りこみ• 1つのJVMに大きなリソースを割り当てる傾向JVMをコンテナで動かす場合、注意が必要な点がある7
Cloud Native Developers JP#CNDT2019 #RoomDCloud Nativeの世界においてJVMはオワコンか?• メジャーなミドルウェア製品で多く利用されている– Kafka、Spark、Casssandra…• モダンなプログラミング言語で、JVMベースのものも多い– Scala、Kotlin…• 開発者のスキルセット– なんだかんだ言って、Javaエンジニアはたくさんいらっしゃるとはいえ避けて通るのは難しい。むしろ使えるのなら使っていきたい8
Cloud Native Developers JP#CNDT2019 #RoomD個人的なモチベーション• 「いちおうJavaエンジニアだし、Kubernetesも勉強してるし、JVM onKubernetesがんばってみよー」9
Cloud Native Developers JP#CNDT2019 #RoomDJVM on Kubernetes ノウハウ集10#CNDT2019 #RoomD
Cloud Native Developers JP#CNDT2019 #RoomDJVM on Kubernetesのランドスケープ• JVM on Kubernetesの考慮事項は、開発・運用全体に渡る…。• ひとつずつ見てきます!11• ツールを活用してKubernetesでも効率よくローカル開発を行う② ビルドBuild Containers• JVM固有の事情を考慮しつつ、Dockerfileのベストプラクティスに従ったコンテナを目指す③ デプロイDeploy Containers• KubernetesでもJVM標準の監視ツールを利用する• Cloud Nativeな監視手法も考慮する• コンテナのリソース制限機能を考慮して、適切なJVMパラメータを設定する• ロールアウト前に暖機運転を行う① ローカル開発Local Development④ 監視Monitoring
Cloud Native Developers JP#CNDT2019 #RoomDJVM on Kubernetesのランドスケープ• JVM on Kubernetesの考慮事項は、開発・運用全体に渡る…。• ひとつずつ見てきます!12① ローカル開発Local Development• ツールを活用してKubernetesでも効率よくローカル開発を行う② ビルドBuild Containers• JVM固有の事情を考慮しつつ、Dockerfileのベストプラクティスに従ったコンテナを目指す③ デプロイDeploy Containers④ 監視Monitoring• KubernetesでもJVM標準の監視ツールを利用する• Cloud Nativeな監視手法も考慮する• コンテナのリソース制限機能を考慮して、適切なJVMパラメータを設定する• ロールアウト前に暖機運転を行う
Cloud Native Developers JP#CNDT2019 #RoomDJVMコンテナアプリのローカル開発を楽にしよう• ツールを活用してKubernetesでも効率よくローカル開発を行う– Skaffold + Jibでローカル開発を省力化13
Cloud Native Developers JP#CNDT2019 #RoomDJVMコンテナアプリの開発作業の課題1. アプリケーションのコードを編集2. ローカルでビルド、自動テスト(Maven/Gradleなどのビルドツールを利用)3. Dockerfileを編集(必要な場合)4. docker build / push5. 開発用のKubernetesクラスターにデプロイ6. 動作確認(→ 1. に戻ってくりかえし)Kubernetes前提のJVMアプリ開発は手間がかかる14動作確認のために毎回Kubernetesにデプロイ成果物をコンテナとしてビルドする必要あり
Cloud Native Developers JP#CNDT2019 #RoomDJib + Skaffoldがやってくれること1. アプリケーションのコードを編集2. ローカルでビルド、自動テスト(Maven/Gradleなどのビルドツールを利用)3. Dockerfileを編集(必要な場合)4. docker build / push5. 開発用のKubernetesクラスターにデプロイ6. 動作確認(→ 1. に戻ってくりかえし)面倒な作業を自動化してローカル開発を効率よく15ここの作業を自動化してくれる!
Cloud Native Developers JP#CNDT2019 #RoomDJibとは• Maven/Gradleプラグインとして利用可能な 、JVM言語アプリケーションのコンテナイメージ作成を省力化してくれるツール• 使い慣れたビルドツールでコンテナイメージが作成できる– Dockerfileフリー。使い慣れた記述形式– Dockerfileのベストプラクティスを知らなくても高品質のコンテナが作れる(JVMアプリとして必要なファイルだけを選択的にコンテナに入れてくれる)• コーディングが滞らない– 高速でコンテナイメージをビルド。ビルド待ちを減らしてコードに集中Dockerfileの編集とコンテナのビルドから、アプリ開発者を開放16
Cloud Native Developers JP#CNDT2019 #RoomDMaven/GradleプラグインとしてのJibの利用方法• Maven/GradleのプラグインとしてJibを指定• 作成するコンテナイメージのプロパティをプラグインの設定値として記述する– mainClass : ENTRYPOINTとなるクラス– ports : コンテナの公開ポート– jvmFlags : JVMに与えるオプション(…etc)17plugins {applicationkotlin("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 containersjvmFlags = listOf(“-server”,“-Djava.awt.headless=true”,“-XX:+UnlockExperimentalVMOptions”,(…snip…))}}build.gradle ファイルの記述例 →
Cloud Native Developers JP#CNDT2019 #RoomDSkaffoldとは• docker build/push/deploy の一連のコマンド実行を自動化するツール– ローカルのコードの変更を検知して、 docker build/push/deployに相当する処理を自動実行(クラスタ上のコンテナのホットスワップ)可能• コーディングが滞らない– コードの編集結果を反映したコンテナが開発用Kubernetesクラスターに自動的にデプロイされる。コードの修正内容の動作確認がすぐできる面倒なBuild, Push, Deployを自動化18
Cloud Native Developers JP#CNDT2019 #RoomDSkaffoldのプラグインアーキテクチャ• SkaffoldはBuild, Push, Deployの各フェーズ自動実行する• それぞれのフェーズで実行する処理に様々なツールを選択可能Build, Push, Deploy各フェーズの処理をプラグイン的に変更できる19Build Push Deploy> docker build > docker push > kubectl apply
Cloud Native Developers JP#CNDT2019 #RoomDBuild Push DeploySkaffold + Jib• Build, PushのフェーズでSkaffoldを利用できるSkaffoldのプラグインとしてJibを利用20Jibを実行 > kubectl apply
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.jar1.2 MB app/libs/kotlin-stdlib-1.3.10.jar784 kB app/libs/kotlinx-coroutines-core-1.0.1.jar730 kB app/libs/kotlinx-html-jvm-0.6.11.jar(… snip …)============================================================814 B $ jib-gradle-plugin:1.0.1============================================================474 B app/resources/logback.xml333 B app/resources/application.conf7 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.class4.9 kB app/classes/example/ktor/AppKt$init$1$1.class4.8 kB app/classes/example/ktor/AppKt$router$1$4$2.class4.0 kB app/classes/example/ktor/AppKt$router$1$3.class(… snip …)↑ dlayer(by @orisanoさん) にかけた結果の抜粋https://github.com/orisano/dlayer
Cloud Native Developers JP#CNDT2019 #RoomDSkaffold + 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
Cloud Native Developers JP#CNDT2019 #RoomDJib + Skaffoldがやってくれること1. アプリケーションのコードを編集2. ローカルでビルド、自動テスト(Maven/Gradleなどのビルドツールを利用)3. Dockerfileを編集(必要な場合)4. docker build / push5. 開発用のKubernetesクラスターにデプロイ6. 動作確認(→ 1. に戻ってくりかえし)面倒な作業を自動化してローカル開発を効率よく23ここの作業を自動化してくれる!
Cloud Native Developers JP#CNDT2019 #RoomD24ここまで15分…。
Cloud Native Developers JP#CNDT2019 #RoomDJVM on Kubernetesのランドスケープ• JVM on Kubernetesの考慮事項は、開発・運用全体に渡る…。• ひとつずつ見てきます!25• ツールを活用してKubernetesでも効率よくローカル開発を行う② ビルドBuild Containers• JVM固有の事情を考慮しつつ、Dockerfileのベストプラクティスに従ったコンテナを目指す③ デプロイDeploy Containers• KubernetesでもJVM標準の監視ツールを利用する• Cloud Nativeな監視手法も考慮する• コンテナのリソース制限機能を考慮して、適切なJVMパラメータを設定する• ロールアウト前に暖機運転を行う① ローカル開発Local Development④ 監視Monitoring
Cloud Native Developers JP#CNDT2019 #RoomDJVMコンテナをビルドする上での指針• Dockerコンテナをビルドするときの一般的な指針に従うのが基本– Dockerfileを書くためのベストプラクティス(公式)• エフェメラル(使い捨て型)コンテナを作成すべし• …etc• JVMのコンテナの場合、コンテナのフットプリントを小さくするためにJVM固有のノウハウが必要– 適切なベースイメージの選択– カスタムJREによるフットプリントの削減– (もっと発展的なJVMコンテナのビルド手法…)JVM固有の事情を考慮しつつ、Dockerfileのベストプラクティスの実現を目指す26
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/JDKDebian (headless) JRE/JDK JRE/JDKOracle Linux 7 JDK JDK JDKAlpine 3.10 JDK JDKWindows Server Core 1803 JRE/JDK JRE/JDK JDK JDK JDKWindows Server Core 1809 JRE/JDK JRE/JDK JDK JDK JDKWindows Server Core LTSC2016 JRE/JDK JRE/JDK JDK JDK JDKDocker公式リポジトリで公開されているOpenJDKイメージhttps://k11i.biz/blog/2018/05/17/base-docker-images-for-java/ をベースに2019/07/18時点の情報に更新
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
Cloud Native Developers JP#CNDT2019 #RoomDカスタムJREを作成してサイズを落とそう• デフォルトのJDKの全機能は、多くのアプリケーションでは不要– 必要なもの: java.{lang,util,…}.*, javax.management.*, …– 不要なもの: corba, jaxws, …• JDK9でモジュールシステム(“Jigsaw”)が導入された– JDK自体をモジュール化するとともに、必要なモジュールだけを含むカスタムJREを生成するツール(jdeps/jlink)を提供JDKの標準機能でフットプリント削減が可能29
Cloud Native Developers JP#CNDT2019 #RoomD30https://www.slideshare.net/oracle4engineer/java-in-the-world-of-container-by-david-buck
Cloud Native Developers JP#CNDT2019 #RoomD31https://www.slideshare.net/oracle4engineer/java-in-the-world-of-container-by-david-buck
Cloud Native Developers JP#CNDT2019 #RoomD32https://www.slideshare.net/oracle4engineer/java-in-the-world-of-container-by-david-buck
Cloud Native Developers JP#CNDT2019 #RoomD33https://www.slideshare.net/oracle4engineer/java-in-the-world-of-container-by-david-buck
Cloud Native Developers JP#CNDT2019 #RoomDjdeps / jlink• jdeps:– アプリケーションの.classや.jarファイルを解析して、依存するJVMモジュールを特定する• jlink:– 指定したJVMモジュールだけを含む、カスタムJREを生成するカスタムランタイムを作るためのJDK標準ツール34$ ${JAVA_HOME}/bin/jdeps target/cowweb.jarcowweb.jar -> java.basecowweb.jar -> java.logging…$ ${JAVA_HOME}/bin/jlink --output cowweb-jre --add-modules java.base,java.logging
Cloud Native Developers JP#CNDT2019 #RoomD35Dockerfile内でカスタムJREを作成する例$ cat target/DockerfileFROM openjdk:11-jdk-slim AS jre-builderWORKDIR /jlinkRUN jlink --output cowweb-jre--add-modules java.base,java.desktop,java.logging,java.managementFROM debian:buster-slimWORKDIR /workdirCOPY --from=jre-builder /jlink/cowweb-jre /opt/cowweb-jreENV PATH /opt/cowweb-jre/bin:$PATHRUN mkdir /appCOPY libs /app/libsCOPY cowweb.jar /appCMD ["java", "-jar", "/app/cowweb.jar"]
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 debianhhiroshell/cowweb v2.1-custom-jre 0233250b4900 3 minutes ago 159MBhhiroshell/cowweb v2.1 4af060beb2eb About an hour ago 214MBdebian buster-slim 83ed3c583403 9 days ago 69.2MB
Cloud Native Developers JP#CNDT2019 #RoomD• Jib– JibとカスタムJREを組み合わせることも可能– Jibの設定で、ベースイメージとしてカスタムJREが入ったコンテナを指定する• Native Image– GraalVMのNative Image生成機能を利用– ランタイムとアプリケーションをまとめてバイトコード化してシングルバイナリを生成する→これをコンテナに入れる– 起動初期の劇的な高速化とフットプリント削減37• SubstrateVM– JVMを必要なコンポーネントだけに絞って自力でビルドする– 使わないJITコンパイラ、GCアルゴリズム、などを削りに削ると5MBくらいのランタイムを作成可能– ご利用は用法用量を守って計画的にもっと発展的なJVMコンテナのビルド手法
Cloud Native Developers JP#CNDT2019 #RoomD38ここまで23分…。
Cloud Native Developers JP#CNDT2019 #RoomDJVM on Kubernetesのランドスケープ• JVM on Kubernetesの考慮事項は、開発・運用全体に渡る…。• ひとつずつ見てきます!39• ツールを活用してKubernetesでも効率よくローカル開発を行う② ビルドBuild Containers• JVM固有の事情を考慮しつつ、Dockerfileのベストプラクティスに従ったコンテナを目指す③ デプロイDeploy Containers• コンテナのリソース制限機能を考慮して、適切なJVMパラメータを設定する• ロールアウト前に暖機運転を行う• KubernetesでもJVM標準の監視ツールを利用する• Cloud Nativeな監視手法も考慮する① ローカル開発Local Development④ 監視Monitoring
Cloud Native Developers JP#CNDT2019 #RoomDJVMコンテナをKubernetesにデプロイしよう• コンテナのリソース制限機能を考慮して、適切なJVMパラメータを設定する– コンテナレベルのCPU/メモリのリソース制限• ロールアウト前に暖機運転を行うコンテナのリソース制限と暖機運転に注意する40
Cloud Native Developers JP#CNDT2019 #RoomDチューニングパラメータの指針• リソース制限(ここではCPU、ヒープメモリ、スレッド)– かつてのJVMはcgroupsによるリソース分離を認識しなかったので、CPU利用量やヒープメモリサイズなどのリソースの設定に注意が必要だった– JDK10以降コンテナランタイムのリソース制限の設定を認識する改善が導入→ 改善後のJVMの挙動を理解してコンテナのリソース制限に適切な設定をJVMをいじるのはその後で• GC– 1コンテナに割り当てるリソース量は、JVMが元来想定していた量より小さい→ GCアルゴリズムの選択を再確認しようコンテナのリソース制限を考慮して、適切な設定を41
Cloud Native Developers JP#CNDT2019 #RoomDDocker/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
Cloud Native Developers JP#CNDT2019 #RoomDDocker/cgroups リソース制限を考慮した設定 – メモリ• JDKが認識してくるコンテナのメモリ制限の設定– --memory• KubernetesでResource Quotaを設定するとコンテナの-mオプションにマッピングされる。これをJVMが認識して動作する• JVMのヒープメモリの設定は、コンテナに割り当てられたメモリ量に対してエルゴノミクスによって決定される(JVMのデフォルトの挙動)• チューニングが必要な場合は、追加で起動オプションを設定するコンテナでメモリ割り当て制限が行われた結果をJVMが認識する43
Cloud Native Developers JP#CNDT2019 #RoomD44Docker/cgroups リソース制限を考慮した設定$ cat target/cowweb.yamlkind: PodapiVersion: v1metadata:name: cowwebspec:containers:- name: cowwebimage: hhiroshell/cowweb:2.1-jdkports:- containerPort: 8080resources:requests:cpu: 1000mmemory: 512Milimits:cpu: 1000mmemory: 512Mi$ kubetl apply -f target/cowweb.yamlpod/cowweb created$ kubectl exec -it cowweb jshellJul 20, 2019 4:11:38 PMjava.util.prefs.FileSystemPreferences$1 runINFO: Created user preferences directory.| Welcome to JShell -- Version 11.0.4| For an introduction type: /help introjshell> Runtime.getRuntime().availableProcessors()$1 ==> 1jshell> Runtime.getRuntime().maxMemory()$1 ==> 129761280
Cloud Native Developers JP#CNDT2019 #RoomDGC• コンテナでJVMアプリを動かす場合、リソースの割当量が比較的小さいため、シリアルGCなどの少リソース向けのGCアルゴリズムが適している場合がある– e.g) JDK11で1CPU, 512MBをコンテナに割り当ててJVMのデフォルトに任せると、シリアルGCが選択される• リソース割り当て量とGCアルゴリズムの選択の考え方は、古くからある議論。先達の知恵から学びましょう…。– 参考資料: 「Javaパフォーマンス」/ Scott Oaks 著少リソースで実行されるケースに合わせて、GCアルゴリズムに改めて注意45
Cloud Native Developers JP#CNDT2019 #RoomDJITコンパイラロールアウトで気にすべきこと• JVMアプリケーションが最大の性能を発揮するには暖機運転が必要– JVMは、実行中のプロファイルを参考にしながら、アプリケーションのコードを動的にバイトコードに変換している (c.f. JIT(Just in Time)コンパイラ)– コンパイルが進んでいない初期のJVMコンテナは理想的な性能を発揮しない暖気運転をしていないJVMは理想的なパフォーマンスを発揮しない460010001110101011010100010111010101110101001010100001100101010101010011010101000101010101…実行時プロファイル
Cloud Native Developers JP#CNDT2019 #RoomDKubernetes標準のルーティングで起きる問題• スケールアウトで追加された直後のPodにも他と同量のトラフィックが分配され、処理が追いつかない場合がある• 最悪Liveness Probeへの応答ができず、Podが再起動されてしまう• 対策は2つ– 暖機運転を自動化して、それが完了してからトラフィックを回す– トラフィックの配送量を制御する → Service Mesh暖気運転が済んでいないJVMコンテナを高負荷に晒さない工夫を行う47Serviceトラフィック追加したばかりのPodにも他と同量のトラフィックが送られる
Cloud Native Developers JP#CNDT2019 #RoomD暖機運転の自動化• Podが起動したらReadiness ProbeがOKとなる前にサイドカーコンテナから暖機運転のトラフィックを送る• 暖機運転が完了したあとでReadiness ProbeがOKとなるようにする– 暖機運転完了までの十分なinitialDelaySecondsを設定する (または– 暖機運転が完了したら、サイドカーコンテナのReadiness ProbeをOKとする48Serviceトラフィック① サイドカーコンテナから暖気のトラフィックを送る② Readiness ProbeがOKになるとServiceからトラフィックが送られるようになる
Cloud Native Developers JP#CNDT2019 #RoomD49暖機運転を自動化するmanifestの記述例kind: Deployment(... snip ...)spec:(... snip ...)template:(... snip ...)spec:containers:- name: cowwebimage: hhiroshell/cowweb:2.1(... snip ...)readinessProbe:httpGet:path: /healthport: httpinitialDelaySeconds: 180periodSeconds: 10livenessProbe:httpGet:path: /healthport: httpinitialDelaySeconds: 5periodSeconds: 15(左からの続き)- name: warmupimage: radial/busyboxplus:curlcommand: ['/bin/sh', '-c']args: ['sleep 15;for i in `seq 0 10000`; docurl "http://localhost:8080/cowsay/say";done;tail -f /dev/null;']• Readiness ProbeがOKとなるまで、Service経由でのPodへのトラフィックが流れないことを利用し、Readiness Probeが開始されるまでの間にサイドカーコンテナから暖気をかけている• (※)理想的には、サイドカーにReadinessProbeを設定しておいて、暖気が終わったらそちらをOKにする方が良いです。確実に暖気が終わったところでトラフィックを流せます
Cloud Native Developers JP#CNDT2019 #RoomDService Meshによるトラフィックの制御• IstioなどのService Meshを利用すると、Podに流すトラフィックの割合を1%単位で調整できる– 追加したばかりのPodには少量のトラフィックを送り、暖気が進んできた段階で徐々に増やす(カナリーデプロイメントに似たやり方)• 本番のトラフィックを暖気に利用するので、理想的な最適化が期待できる50VirtualServiceトラフィック追加したばかりのPodには少量のトラフィックを送り、徐々に増やす99%1%
Cloud Native Developers JP#CNDT2019 #RoomDJVM on Kubernetesのランドスケープ• JVM on Kubernetesの考慮事項は、開発・運用全体に渡る…。• ひとつずつ見てきます!51• ツールを活用してKubernetesでも効率よくローカル開発を行う② ビルドBuild Containers• JVM固有の事情を考慮しつつ、Dockerfileのベストプラクティスに従ったコンテナを目指す③ デプロイDeploy Containers• コンテナのリソース制限機能を考慮して、適切なJVMパラメータを設定する• ロールアウト前に暖機運転を行う• KubernetesでもJVM標準の監視ツールを利用する• Cloud Nativeな監視手法も考慮する① ローカル開発Local Development④ 監視Monitoring
Cloud Native Developers JP#CNDT2019 #RoomD52ここまで32分…。
Cloud Native Developers JP#CNDT2019 #RoomDJVMコンテナを監視しよう• KubernetesでもJVM標準の監視ツールを利用可能(ただし一工夫必要)– jcmd, jstackなどの基本的なツール– JFR (Java Flight Recorder)• Cloud Nativeな監視手法も考慮する– Prometheusによるメトリック監視– OpenTracing準拠のトレーサーによる分散トレーシング→ 各言語のフレームワークやライブラリでサポートされる方式があるのでそちらでの説明に譲りますm(_ _)m目的やスキルセットに合わせて複数の手段を使い分ける53
Cloud Native Developers JP#CNDT2019 #RoomD標準的なJVM監視ツールをKubernetesで利用する• jcmd, jstackなどJDK付属の基本的なツールを使う場合、JDKのコンテナをサイドカーとして追加してそのコンテナからツールを実行する(アプリケーションのコンテナにツールが含まれていないケースがあるため)• トラブルシューティングの場面で活躍従来どおりのツールでトラブルシューティングできるが一工夫が必要54ServiceカスタムJREのアプリコンテナ監視ツールが入ったサイドカーコンテナ経由で監視ツールを実行JDKのコンテナkubectl exec –it /bin/shjmcd
Cloud Native Developers JP#CNDT2019 #RoomD55サイドカーコンテナからのJDK標準ツールの利用$ cat target/cowweb.yamlkind: Podmetadata:name: cowweb(... snip ...)spec:(... snip ...)shareProcessNamespace: truecontainers:- name: cowwebimage: hhiroshell/cowweb:v2.1(... snip ...)- name: jtoolingsimage: openjdk:11-jdk-slimcommand: ['/bin/sh']securityContext:capabilities:add:- SYS_PTRACEstdin: truetty: true$ kubetl apply -f target/cowweb.yamlpod/cowweb created$ kubectl exec -it cowweb -c jtoolings /bin/sh# jps8 cowweb.jar10127 Jps# jcmd 8 VM.flags8:-XX:CICompilerCount=2 -XX:InitialHeapSize=8388608 -XX:MaxHeapSize=134217728 -XX:MaxNewSize=44695552…
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
Cloud Native Developers JP#CNDT2019 #RoomDJava Flight Recorder(JFR)を使ったプロファイリング• JFRとは– JVMのプロファイリングやイベント収集のためのフレームワーク– .jfrという形式のプロファイルデータとして、JVMとアプリケーションの詳細な実行記録を取得– アプリケーションの実行中に記録の開始、停止、.jfrのダンプが実行可能– Oracle JDKの商用機能だったがJDK11からOpenJDKに寄贈され無償で利用可能に– 本番環境での豊富な利用実績JFR → JVMの強力なプロファイリングツール57
Cloud Native Developers JP#CNDT2019 #RoomDKubernetes上でJFRを利用するときの構成• .jfrはjcmdコマンドで取得。Volumeをマウントしてそこに出力する• GUIとプログラムから.jfrにアクセス可能58JVMアプリ(カスタムJRE).jfrの保存kubectl exec –it cowweb -c jtoolings /bin/shFlight Recordingの開始・停止・.jfrのダンプKubernetesクラスターjcmdJMC(GUIツール)による解析JFR APIによる解析JDKJavaプログラム + JFR API
Cloud Native Developers JP#CNDT2019 #RoomDJFRファイルの出力と収集• jcmdの各種コマンドでFlight Recordingの開始、終了、.jfrのダンプなどが行える– .jfrファイルはダンプすることによって取得する– 起動オプションを設定することでJVM起動時からFlight Recordingを開始することも可能• Kubernetes上で利用する場合– .jfrのダンプを手動・自動実行するサイドカーコンテナを用意する– ダンプする先をコンテナ外の永続ストレージにしておく– カスタムJREでアプリを動かす場合 jlinkに --bind-services オプションを追加する59
Cloud Native Developers JP#CNDT2019 #RoomDJVM起動直後からFlight Recordingを開始する例60kind: Podmetadata:name: cowweb(... snip ...)spec:(... snip ...)containers:- name: cowwebimage: hhiroshell/cowweb:2.1command: ['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-volumemountPath: /jfr(... snip ...)volumes:- name: jfr-volumenfs:server: 10.0.40.8path: “/jfr-example"
Cloud Native Developers JP#CNDT2019 #RoomDJFRの解析 1/2• Java Mission Controlを使った解析– JMCはJFRを解析するためのGUIツール– トラブル発生時後の原因究明に適しているグラフィカルなGUIツールを使った解析61
Cloud Native Developers JP#CNDT2019 #RoomDJFRの解析 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 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…)}
Cloud Native Developers JP#CNDT2019 #RoomDまとめ• たくさんありますが、頑張っていきましょう!63• ツールを活用してKubernetesでも効率よくローカル開発を行う② ビルドBuild Containers• JVM固有の事情を考慮しつつ、Dockerfileのベストプラクティスに従ったコンテナを目指す③ デプロイDeploy Containers• コンテナのリソース制限機能を考慮して、適切なJVMパラメータを設定する• ロールアウト前に暖機運転を行う• KubernetesでもJVM標準の監視ツールを利用する• Cloud Nativeな監視手法も考慮する① ローカル開発Local Development④ 監視Monitoring
Cloud Native Developers JP#CNDT2019 #RoomD64
Cloud Native Developers JP#CNDT2019 #RoomDFin.65
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_JavaDayTokyo201766
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-advice67