Kubernetesでサーバーレスファンクションを実行する際に、より高速なスタートアップとメモリフットプリントの削減を実現します。
使用する場合、何千ものアプリケーションを実行することでリソースを大量に消費するため、ワーカーノードやリソースフットプリントを少なくするほどコストが高くなるため、高速起動とメモリフットプリントの小ささが重要になります。Kubernetesプラットフォーム上でコンテナ化されたマイクロサービスを実行する場合、メモリフットプリントはスループットよりも重要な考慮事項です:
- 継続的に実行する必要があるため、より多くのリソースを消費します。
- マイクロサービスは諸経費を増大させます
- モノリシックなアプリケーションが複数のマイクロサービスになったケース
こうした状況は、サーバーレス機能やJavaのデプロイモデルの開発に大きな影響を与えています。これまで多くの企業開発者は、パフォーマンスのボトルネックに対処するための代替手段としてGo、Python、またはNode.jsを選択してきましたが、kubernetesベースのネイティブJavaスタックである Kubernetes 登場しました。この記事では、Quarkusを使用してサーバーレス機能を実行するkubernetesプラットフォームでパフォーマンスを最適化する方法について説明します。
コンテナ・ファーストの設計思想
Java エコシステム内の従来のフレームワークは、構成ファイルの処理、クラスパスのスキャン、クラスのロード、アノテーションの処理、メタモデルの構築など、フレームワークの初期化を実行する必要があり、これらはすべて不可欠な処理であるため、リソースを多く消費します。複数の異なるフレームワークが使用される場合、消費されるリソースは倍増します。
Quarkusは、すべてのリソース集約的な処理をビルドフェーズに移行することで、このようなJavaのパフォーマンス問題を解決します。コードとフレームワークの解析、バイトコードの変換、動的メタモデルの生成は、ビルドフェーズで、しかも1回だけ実行されます。その結果、実行可能ファイルは高速起動のために高度に最適化され、従来の起動プロセスをすべて実行する必要がなくなります。
さらに、Quarkusは、従来のクラウドネイティブJavaスタックと比較して、高速起動や非常に小さなメモリフットプリント、即時のスケーラビリティ、メモリの高密度利用など、優れたパフォーマンスを備えたネイティブ実行可能ファイルの構築をサポートしています。
Quarkusを使用して Javaサーバーレスプロジェクトを ネイティブ実行ファイルとしてビルドする方法の例を示します。
Quarkusを使用したサーバーレスMavenプロジェクトの作成
次のコマンドは、単純な関数を作成するためのQuarkusプロジェクトを生成します:
$ mvn io.quarkus:quarkus-maven-plugin:1.13.4.Final:create \-DprojectGroupId=org.acme \-DprojectArtifactId=quarkus-serverless-native \-DclassName="org.acme.getting.started.GreetingResource"
以下は、ローカルで実行ファイルをビルドする方法の例です。
Javaプログラムのネイティブ実行ファイルを構築するには、GraalVMを使用する必要があります。 Java サーバーレス 、OpenJDK 11上でのQuarkusネイティブ実行可能ファイルの構築をサポートするように設計された Mandrelなど、GraalVMの任意のディストリビューションを選択できます。
pom.xmlを開くと、ネイティブ設定があります。ネイティブの実行ファイルをビルドするときに使います。
<profiles><profile><id>native</id><properties><quarkus.package.type>native</quarkus.package.type></properties></profile></profiles>
注: GraalVM または Mandrel ディストリビューションをローカルにインストールできます。また、Mandrel コンテナイメージをダウンロードしてビルドすることもできますので、ローカルでコンテナエンジンを実行する必要もあります。
コンテナー・ランタイムを開いていると仮定して、この時点でMavenコマンドを実行する必要があります:
コンテナエンジンとして Oracle GraalVM Community Edition 使用します:
$ ./mvnw package -Pnative \-Dquarkus.native.container-build=true \-Dquarkus.native.container-runtime=docker
Mandrel コンテナエンジンとして使用します:
$ ./mvnw package -Pnative \-Dquarkus.native.container-build=true \-Dquarkus.native.container-runtime=podman
出力メッセージの末尾は BUILD SUCCESSでなければなりません。
JVMなしでネイティブ実行可能ファイルを実行します:
$ target/quarkus-serverless-native-1.0.0-SNAPSHOT-runner
出力メッセージも同様です:
__ ____ __ _____ ___ __ ____ ______--/ __ \/ / / / _ | / _ \/ //_/ / / / __/-/ /_/ / /_/ / __ |/ , _/ ,< / /_/ /\ \--\___\_\____/_/ |_/_/|_/_/|_|\____/___/INFO [io.quarkus] (main) quarkus-serverless-native 1.0.0-SNAPSHOT native(powered by Quarkus xx.xx.xx.) Started in 0.019s. Listening on: http://...:80INFO [io.quarkus] (main) Profile prod activated.INFO [io.quarkus] (main) Installed features: [cdi, kubernetes, resteasy]
実質的に超音速です!スタートまでわずか19ミリ秒。ランタイムは多少異なる場合があります。
Linuxのpsユーティリティを使用してこれを確認すると、メモリフットプリントはまだ非常に低いです。これを確認するには、別のターミナルを開き、アプリケーションの実行中に以下のコマンドを実行します:
$ ps -o pid,rss,command -p $(pgrep -f runner)
出力は似ています:
PID RSS COMMAND11360 target/quarkus-serverless-native-1.0.0-SNAPSHOT-runner
このプロセスは、わずか11MBのメモリしか消費しません。とても小さい!
注: さまざまなアプリケーションのレジデント・セットとメモリ・フットプリントのサイズは、オペレーティング環境によって異なり、アプリケーションがロードされるにつれて増加します。
REST APIを使用してこの関数にアクセスすることもできます。出力は Hello RESTEasy.
$ curl localhost:8080/helloHello RESTEasy
関数はKnativeサービスにデプロイされます。
まだの場合は、 Docker名前空間を作成し、このローカル実行ファイルをサーバーレス関数としてデプロイします。そして、quarkus-openshiftエクステンションを追加します:
$ ./mvnw -q quarkus:add-extension -Dextensions="openshift"
KnativeとKubernetes関連のリソースを設定するために、 src/main/resources/application.properties ファイルに以下を追加します:
quarkus.container-image.group=quarkus-serverless-nativequarkus.container-image.registry=image-registry.openshift-image-registry.svc:0050quarkus.native.container-build=truequarkus.kubernetes-client.trust-certs=truequarkus.kubernetes.deployment-target=knativequarkus.kubernetes.deploy=truequarkus.openshift.build-strategy=docker
ローカル実行ファイルをビルドし、OKDクラスタに直接デプロイします:
$ ./mvnw clean package -Pnative
注意: 事前に oc login コマンドを使って、正しいプロジェクトにログインしていることを確認してください。
ローカルバイナリのビルドを完了し、Knativeサービスとしてデプロイするには数分かかります。サービスの作成に成功したら、kubectl または oc コマンドツールを使って Knative サービスとバージョン情報を表示できます:
$ kubectl get ksvcNAME URL [...]quarkus-serverless-native http://--ve-[...].IN True$ kubectl get revNAME CONFIG NAME K8S SERVICE NAME GENERATION READY REASONquarkus-serverless-native-00001 quarkus-serverless-native quarkus-serverless-native- True
ローカル実行可能関数へのアクセス
kubectl 実行して、サーバー機能のないノードを検索します:
$ kubectl get rt/quarkus-serverless-native
出力メッセージも同様です:
NAME URL READY REASONquarkus-serverless-native http://-----.IN True
上記のメッセージのURLフィールドにアクセスするには、curlコマンドを使用します:
$ curl http://-----./lo
1秒もかからずに、ローカルで操作しているのと同じ結果が得られます:
Hello RESTEasy
OKDクラスターでQuarkusが実行されているノードのログにアクセスすると、ローカルの実行ファイルがKnativeサービスとして実行されていることがわかります。
次は?
Javaサーバーレス関数をGraalVMディストリビューションで最適化し、Kubernetesを使用してKnativeでサーバーレス関数としてデプロイできます。




