Slide 1

Slide 1 text

Cloud Native Developers JP KubernetesでJVMアプリを 動かすための実践的ノウハウ集 @hhiroshell 1 CloudNative Days Tokyo 2019 [1D3] #CNDT2019 #RoomD

Slide 2

Slide 2 text

Cloud Native Developers JP #CNDT2019 #RoomD 自己紹介 早川 博(はやかわ ひろし) • Cloud Nativeな技術スタック担当のプリセールスエンジニア • エンジニアコミュニティ 「Cloud Native Developers JP」 オーガナイザー • Developers Summit 2018、Japan Container Days 12.18 登壇 2 @hhiroshell

Slide 3

Slide 3 text

Cloud Native Developers JP #CNDT2019 #RoomD 宣伝 • 皆さん自作キーボードやりましょう! 楽しいですよ! 3 遊舎工房さんの店舗はこちら→ ↓現在の@hhiroshellのキーボード • 本書きました!買って ください! 「Kubernetes実践ガイド」 北山 晋吾(著), 早川 博(著) https://www.amazon.co.jp/dp/B07TSBP3CZ/

Slide 4

Slide 4 text

Cloud Native Developers JP #CNDT2019 #RoomD ご注意 • このプレゼンテーションにおけるJDK/JREは、特に断りのない場合 OpenJDKを指しているものとしてご理解ください 4

Slide 5

Slide 5 text

Cloud Native Developers JP #CNDT2019 #RoomD お品書き • イントロダクション • JVM on Kubernetes ノウハウ集 – JVMコンテナアプリの開発作業を楽にしよう – JVMコンテナをビルドしよう – JVMコンテナをデプロイしよう – JVMコンテナを監視しよう • まとめ 5

Slide 6

Slide 6 text

Cloud Native Developers JP #CNDT2019 #RoomD イントロダクション 6 #CNDT2019 #RoomD

Slide 7

Slide 7 text

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

Slide 8

Slide 8 text

Cloud Native Developers JP #CNDT2019 #RoomD Cloud Nativeの世界においてJVMはオワコンか? • メジャーなミドルウェア製品で多く利用されている – Kafka、Spark、Casssandra… • モダンなプログラミング言語で、JVMベースのものも多い – Scala、Kotlin… • 開発者のスキルセット – なんだかんだ言って、Javaエンジニアはたくさんいらっしゃる とはいえ避けて通るのは難しい。むしろ使えるのなら使っていきたい 8

Slide 9

Slide 9 text

Cloud Native Developers JP #CNDT2019 #RoomD 個人的なモチベーション • 「いちおうJavaエンジニアだし、Kubernetesも勉強してるし、JVM on Kubernetesがんばってみよー」 9

Slide 10

Slide 10 text

Cloud Native Developers JP #CNDT2019 #RoomD JVM on Kubernetes ノウハウ集 10 #CNDT2019 #RoomD

Slide 11

Slide 11 text

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

Slide 12

Slide 12 text

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パラメー タを設定する • ロールアウト前に暖 機運転を行う

Slide 13

Slide 13 text

Cloud Native Developers JP #CNDT2019 #RoomD JVMコンテナアプリのローカル開発を楽にしよう • ツールを活用してKubernetesでも効率よくローカル開発を行う – Skaffold + Jibでローカル開発を省力化 13

Slide 14

Slide 14 text

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 にデプロイ 成果物をコンテナとしてビル ドする必要あり

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

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 ファイルの記述例 →

Slide 18

Slide 18 text

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

Slide 19

Slide 19 text

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

Slide 20

Slide 20 text

Cloud Native Developers JP #CNDT2019 #RoomD Build Push Deploy Skaffold + Jib • Build, PushのフェーズでSkaffoldを利用できる SkaffoldのプラグインとしてJibを利用 20 Jibを実行 > kubectl apply

Slide 21

Slide 21 text

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

Slide 22

Slide 22 text

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

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

Cloud Native Developers JP #CNDT2019 #RoomD 24 ここまで15分…。

Slide 25

Slide 25 text

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

Slide 26

Slide 26 text

Cloud Native Developers JP #CNDT2019 #RoomD JVMコンテナをビルドする上での指針 • Dockerコンテナをビルドするときの一般的な指針に従うのが基本 – Dockerfileを書くためのベストプラクティス(公式) • エフェメラル(使い捨て型)コンテナを作成すべし • …etc • JVMのコンテナの場合、コンテナのフットプリントを小さくするた めにJVM固有のノウハウが必要 – 適切なベースイメージの選択 – カスタムJREによるフットプリントの削減 – (もっと発展的なJVMコンテナのビルド手法…) JVM固有の事情を考慮しつつ、Dockerfileのベストプラクティスの実現を目指す 26

Slide 27

Slide 27 text

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時点の情報に更新

Slide 28

Slide 28 text

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

Slide 29

Slide 29 text

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

Slide 30

Slide 30 text

Cloud Native Developers JP #CNDT2019 #RoomD 30 https://www.slideshare.net/oracle4engineer/java-in-the-world-of-container-by-david-buck

Slide 31

Slide 31 text

Cloud Native Developers JP #CNDT2019 #RoomD 31 https://www.slideshare.net/oracle4engineer/java-in-the-world-of-container-by-david-buck

Slide 32

Slide 32 text

Cloud Native Developers JP #CNDT2019 #RoomD 32 https://www.slideshare.net/oracle4engineer/java-in-the-world-of-container-by-david-buck

Slide 33

Slide 33 text

Cloud Native Developers JP #CNDT2019 #RoomD 33 https://www.slideshare.net/oracle4engineer/java-in-the-world-of-container-by-david-buck

Slide 34

Slide 34 text

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

Slide 35

Slide 35 text

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"]

Slide 36

Slide 36 text

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

Slide 37

Slide 37 text

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

Slide 38

Slide 38 text

Cloud Native Developers JP #CNDT2019 #RoomD 38 ここまで23分…。

Slide 39

Slide 39 text

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

Slide 40

Slide 40 text

Cloud Native Developers JP #CNDT2019 #RoomD JVMコンテナをKubernetesにデプロイしよう • コンテナのリソース制限機能を考慮して、適切なJVMパラメータを 設定する – コンテナレベルのCPU/メモリのリソース制限 • ロールアウト前に暖機運転を行う コンテナのリソース制限と暖機運転に注意する 40

Slide 41

Slide 41 text

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

Slide 42

Slide 42 text

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

Slide 43

Slide 43 text

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

Slide 44

Slide 44 text

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

Slide 45

Slide 45 text

Cloud Native Developers JP #CNDT2019 #RoomD GC • コンテナでJVMアプリを動かす場合、リソースの割当量が比較的小 さいため、シリアルGCなどの少リソース向けのGCアルゴリズムが適 している場合がある – e.g) JDK11で1CPU, 512MBをコンテナに割り当ててJVMのデフォルトに任せる と、シリアルGCが選択される • リソース割り当て量とGCアルゴリズムの選択の考え方は、古くから ある議論。先達の知恵から学びましょう…。 – 参考資料: 「Javaパフォーマンス」/ Scott Oaks 著 少リソースで実行されるケースに合わせて、GCアルゴリズムに改めて注意 45

Slide 46

Slide 46 text

Cloud Native Developers JP #CNDT2019 #RoomD JITコンパイラ ロールアウトで気にすべきこと • JVMアプリケーションが最大の性能を発揮するには暖機運転が必要 – JVMは、実行中のプロファイルを参考にしながら、アプリケーションのコード を動的にバイトコードに変換している (c.f. JIT(Just in Time)コンパイラ) – コンパイルが進んでいない初期のJVMコンテナは理想的な性能を発揮しない 暖気運転をしていないJVMは理想的なパフォーマンスを発揮しない 46 001000111010101101 010001011101010111 010100101010000110 010101010101001101 0101000101010101… 実行時プロファイル

Slide 47

Slide 47 text

Cloud Native Developers JP #CNDT2019 #RoomD Kubernetes標準のルーティングで起きる問題 • スケールアウトで追加された直後のPodにも他と同量のトラフィック が分配され、処理が追いつかない場合がある • 最悪Liveness Probeへの応答ができず、Podが再起動されてしまう • 対策は2つ – 暖機運転を自動化して、それが完了してからトラフィックを回す – トラフィックの配送量を制御する → Service Mesh 暖気運転が済んでいないJVMコンテナを高負荷に晒さない工夫を行う 47 Service トラフィック 追加したばかりのPodにも他と 同量のトラフィックが送られる

Slide 48

Slide 48 text

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

Slide 49

Slide 49 text

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にする方が良いです。確実に暖気が 終わったところでトラフィックを流せます

Slide 50

Slide 50 text

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

Slide 51

Slide 51 text

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

Slide 52

Slide 52 text

Cloud Native Developers JP #CNDT2019 #RoomD 52 ここまで32分…。

Slide 53

Slide 53 text

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

Slide 54

Slide 54 text

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

Slide 55

Slide 55 text

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…

Slide 56

Slide 56 text

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

Slide 57

Slide 57 text

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

Slide 58

Slide 58 text

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

Slide 59

Slide 59 text

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

Slide 60

Slide 60 text

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"

Slide 61

Slide 61 text

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

Slide 62

Slide 62 text

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 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…) }

Slide 63

Slide 63 text

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

Slide 64

Slide 64 text

Cloud Native Developers JP #CNDT2019 #RoomD 64

Slide 65

Slide 65 text

Cloud Native Developers JP #CNDT2019 #RoomD Fin. 65

Slide 66

Slide 66 text

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

Slide 67

Slide 67 text

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