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
    KubernetesでJVMアプリを
    動かすための実践的ノウハウ集
    @hhiroshell
    1
    CloudNative Days Tokyo 2019 [1D3] #CNDT2019 #RoomD

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  11. 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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  21. 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

    View Slide

  22. 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

    View Slide

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

    View Slide

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

    View Slide

  25. 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

    View Slide

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

    View Slide

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

    View Slide

  28. 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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  34. 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

    View Slide

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

    View Slide

  36. 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

    View Slide

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

    View Slide

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

    View Slide

  39. 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

    View Slide

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

    View Slide

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

    View Slide

  42. 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

    View Slide

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

    View Slide

  44. 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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  51. 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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  55. 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…

    View Slide

  56. 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

    View Slide

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

    View Slide

  58. 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

    View Slide

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

    View Slide

  60. 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"

    View Slide

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

    グラフィカルなGUIツールを使った解析
    61

    View Slide

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

    View Slide

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

    View Slide

  64. Cloud Native Developers JP
    #CNDT2019 #RoomD
    64

    View Slide

  65. Cloud Native Developers JP
    #CNDT2019 #RoomD
    Fin.
    65

    View Slide

  66. 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

    View Slide

  67. 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

    View Slide