手助けの為のQuarkus Superheroes!
あなたはマイクロサービスを構築する開発者ですか?大きなシステムの一部である個々のマイクロサービスの開発とテストに苦労していますか?RESTベースのアプリケーションやイベントドリブンなアプリケーションの構築について学びたいと思いませんか?
はじめに
Quarkusには、開発者がQuarkusエコシステムのさまざまな機能に慣れるための優れた ドキュメントや クイックスタートがあります。しかし、不足していたのは、これらの機能、パターン、ベストプラクティスを使用しながら、Quarkusが解決しようとしている問題を反映した、完全に実装された実世界のアプリケーションのサンプルセットでした。
この記事では、 Quarkus Superheroesのサンプルアプリケーションを紹介し、構築するための要件を説明し、ローカルで実行する方法や Kubernetesにデプロイする方法を説明します。また、このサンプルアプリケーションが紹介された Quarkus Insightsのエピソードもご覧いただけます。
要件
ただ面白いだけではなく、いくつかの条件が必要でした:
-
全体のアーキテクチャは、マルチサービス・マイクロサービス・アーキテクチャであること。
-
REST、 WebSocket、データベースとのやりとり、メッセージング、 ヘルスチェック、 モニタリング/メトリクス、 Apache Avro、 OpenAPIの統合など、共通の機能をピックアップして、"hello world"以上ではあるが、"kitchen sink"ではないこと
-
アプリケーションは、Quarkusの各バージョンで最新の状態に保たれ、 標準的なQuarkusエコシステムの継続的インテグレーションの一部となり、 Quarkusのステータスダッシュボードに表示されることが望ましい
-
なるべくブロック型とリアクティブ型の両方の例があることが望ましい
-
システム全体としては
-
ローカルの開発者用マシンやKubernetes上で、ビルド、実行、デプロイ、デモが簡単にできること。
-
独立したマイクロサービスのローカル開発を促進するために、Quarkusがどのように役立つかを紹介していること。
-
簡素化のために 単一のGitHubリポジトリに含まれているが、マルチモジュールプロジェクト ではない こと。
-
-
システム内の各アプリケーションは
-
ローカルの開発者用マシンやKubernetes上で、ビルド、実行、デプロイ、デモが簡単にできること。
-
Javaバージョン11と17(JVMとネイティブの両方)の コンテナイメージを提供すること。
-
完全に文書化されていること。
-
完全に自動化された(文書化された)CI/CDプラクティスを持っていること。
-
ユニットテストと統合テストの完全なテストスイートを含んでいること。
-
初期リリース
Quarkus Superheroesアプリケーションの初期バージョンは、2022年2月初旬にリリースされました。いくつかのマイクロサービスが共存してより大きなシステムを形成しており、RESTを介して同期的に通信したり、 Apache Kafkaを介してイベントドリブンで通信したりしています。アプリケーションの中にはリアクティブなものもあれば、伝統的なものもあり、それぞれの種類の構築方法を紹介しています。
図1に示すWebベースのユーザーインターフェースで、スーパーヒーローがスーパーヴィランと戦うことができます。過去の戦いの結果もこのページに表示されます。
図2に示す追加のユーザーインターフェースでは、ヒーロー対ヴィランの勝率や上位10人の勝率とそれぞれの勝数など、過去の対戦統計が表示されます。
ケープの裏側
図3は、本アプリケーションの全体的なアーキテクチャを示しています。
4つのQuarkusアプリケーションがあり、それぞれについては後述しますが、 Angularアプリケーションと、いくつかのバックエンドサービスがあります。 Prometheus、 PostgreSQL、 Apache Kafka、 Apicurio Schema Registryの4つです。
ヒーロー・サービス
Heroサービスは、完全にリアクティブでノンブロッキングなHTTPマイクロサービスで、 Hero
データモデルに対するCRUD操作を公開しています。REST層は、 RESTEasy Reactiveを使用してリアクティブなエンドポイントを実装しています。データは、 Quarkus Hibernate Reactive with Panacheの リポジトリパターンを使用して PostgreSQLデータベースに永続化されます。さらに、Heroサービスは、 フィールドインジェクションよりもビーンの コンストラクタインジェクションを優先します。Heroサービスには、ユニットテストと統合テストの完全なスイートが含まれており、 モッキング、 スパイ、 隔離されたトランザクション内でのテストを使用しています。
起動時間を短縮するために、 利用可能な全ヒーロー3体の中から100体のランダムなヒーローだけがデータベースに読み込まれます。より多くのデータをロードしたい場合は、 レポの |
ヴィラン・サービス
Villainサービスは、 Villain
データモデルに対するCRUD操作を公開するブロッキングHTTPマイクロサービスです。実際、 Villain
データモデルは、 Heroサービスの Hero
データモデルと同一です(テーブルの名前以外は)。また、Heroサービスと同じユースケースをすべて実装しています。唯一の違いは、Villainサービスがブロッキングであることと、 Quarkus Hibernate ORM with Panacheの active recordパターンを使用していることです。
REST層は、 RESTEasy Reactiveを使って、ブロック型のエンドポイントで実装されています。データは PostgreSQLデータベースに保存されます。Villainサービスはまた、いくつかのカスタム設定を作成して、どのように ConfigMapping
オブジェクトを使うかを示すカスタム設定も作成します。さらに、Villainサービスは コンストラクタ・インジェクションよりもビーンの フィールド・インジェクションを好みます。Villainサービスはユニットテストと統合テストの完全なスイートを含み、 モッキング、 スパイ、 隔離されたトランザクション内でのテストを用います。
起動時間を短縮するために、 1体の悪役の中から100体のランダムな悪役だけをデータベースにロードしています。もっと多くのデータをロードしたい場合は、 レポの |
ファイトサービス
Fightサービスは、完全にリアクティブでノンブロッキングなHTTPマイクロサービスで、ヒーローとヴィランの間で戦いを実行するためのRESTful APIを公開しています。REST層は RESTEasy Reactiveを使用して実装されており、リアクティブなエンドポイントを備えています。戦いのデータは、 Quarkus Hibernate Reactive with Panacheの active recordパターンを使用してPostgreSQLデータベースに永続化されます。また、Fightサービスでは、 フィールド・インジェクションよりも コンストラクタ・インジェクションを採用しています。
Fightサービスは、HeroサービスとVillainサービスの両方にREST呼び出しを行います。Heroサービスへの呼び出しは reactive rest clientを使用し、Villainサービスへの呼び出しは RESTEasy Reactive clientを使用します。RESTEasy Reactive clientは、 JAX-RSクライアントAPIの MicroProfile Rest Client実装であり、そのコアはノンブロッキングです。すべての発信コールは、 リトライ、 タイムアウト、 フォールバック、 サーキットブレーキングなどの レジリエンスパターンを使用しています。
さらに、Fightサービスは、 Apache Avro形式のファイトイベントをKafkaに エミットします。Fightスキーマは、 QuarkusのApicurio Avroエクステンションによって、 Apicurio Schema Registryに自動的に登録されます。
Fightサービスには、ユニットテストとインテグレーションテストの完全なスイートが含まれており、 モッキング、 スパイ、 隔離されたトランザクション内でのテストを使用しています。また、下流のRESTエンドポイントをモックするための Wiremockや、ユニット・テスト内でメッセージの検証を行うための インメモリKafkaコネクタを多用しています。また、 Dev Servicesの情報を注入して、 KafkaConsumer
.NETなどのテスト・リソースを設定する方法も紹介しています。
イベント統計サービス
Event Statistics サービスは、 WebSocketHTTPレイヤーを公開するイベント駆動型のマイクロサービスです。 SmallRye Reactive Messagingを利用したKafkaトピック上で、 Apache Avroフォーマットの試合イベントをリッスンします。戦いのスキーマは、 Quarkus Apicurio Avro extensionによって Apicurio Schema Registryに自動的に登録されます。
統計情報は、上の図2に示すように、ブラウザベースのユーザーインターフェースで表示されます。チームの統計は、ヒーローとヴィランの勝利数の割合で表示されます。勝者の統計は、ヒーローとヴィランのそれぞれの勝利数で蓄積され、上位10人の勝利数が保持されます。統計情報は、WebSocketを介してUIにプッシュされます。
Event Statistics サービスには、 モッキングと スパイを使用したユニット・テストと統合テストの完全なスイートが含まれています。また、 Dev Services の情報を注入して、 KafkaProducer
のようなテスト・リソースを構成する方法も紹介しています。
スーパーヒーローUI
上の図1に示されているSuper Hero UIアプリケーションは、Node.jsを介してデプロイされた Angularシングルページアプリケーションです。このアプリケーションは、RESTを介してFightサービスと通信します。サンプルアプリケーションでは、Angular UIではなくQuarkusアプリケーションに焦点を当てています。
アプリケーションをローカルで実行する
アプリケーションをローカルで実行するには、目的に応じていくつかの方法があります。 Docker Composeは、 事前に構築されたコンテナイメージを使用して、 アプリケーション全体または そのサブセットを実行したい場合に使用できます。また、各アプリケーションを ソースから実行することもできます。
Docker Composeでローカルに実行
アプリケーション全体またはそのサブセットを、1つのDocker Composeコマンドで起動することができます。
アプリケーション全体の実行
レスポンダのルートにある deploy/docker-compose
レスポンダのルートにあるディレクトリには、アプリケーションの4つのバージョンそれぞれのコンポーズファイルが含まれています。JVM 11、JVM 17、Java 11で構築されたネイティブ、Java 17で構築されたネイティブの4つのバージョンそれぞれのコンポーズファイルが含まれています。さらに、 付属の prometheus.yml
ファイルを使って、 Prometheusモニタリングを開始することができます。
quarkus-super-heroesディレクトリから、 実行したいアプリケーションのバージョンに応じたコマンドを実行するだけです。例えば、ネイティブのJava 17バージョンを実行するには、 docker-compose -f deploy/docker-compose/native-java17.yml -f deploy/docker-compose/prometheus.yml up
を実行します。
scripts
ディレクトリには watch-services.sh
スクリプトが含まれており、別のターミナルで実行することができます。このスクリプトは、すべてのサービスの起動を監視し、すべてのサービスが起動して準備が整ったら報告します。
アプリケーションの起動時にエラーが発生することがあります。これは、あるサービスが、そのサービスが必要とするサービス(データベース、Kafkaブローカーなど)よりも先に起動を完了した場合に発生する可能性があります。すべての起動が完了すると、意図したとおりに動作します。 |
準備が整い次第、以下のURLで利用可能になります。
-
Super Heroes UI: http://localhost:8080
-
イベント統計UI : http://localhost:8085
-
Apicurio Schema Registry: http://localhost:8086
-
Prometheus: http://localhost:9090
-
ファイトサービス: http://localhost:8082
-
ヒーロー・サービス: http://localhost:8083
-
ヴィラン・サービス: : http://localhost:8084
アプリケーションのサブセットの実行
個々のサービスは、Docker Composeを介して実行することもできます。
リポジトリ内の各サービスのサブディレクトリの中には、4つのバージョンのアプリケーションのComposeファイルを含む deploy/docker-compose
ディレクトリがあります。複数のComposeファイルを1つのコマンドにまとめることができます。
これは、例えば、 Quarkus Dev ModeでFightサービスに取り組み、HeroとVillainサービスを利用できるようにする必要がある場合に便利です。 quarkus-super-heroes
ディレクトリから、 実行したいアプリケーションのバージョンに応じたコマンドを実行するだけです。例えば、ネイティブのJava 17バージョンを実行するには、 docker-compose -f rest-heroes/deploy/docker-compose/native-java17.yml -f rest-villains/deploy/docker-compose/native-java17.yml up
を実行します。
Quarkus 開発モードでローカルに実行
各サービスは、 Quarkus Dev Modeを介して同時に実行することもできます。各Quarkusサービス( event-statistics
, rest-fights
, rest-heroes
, rest-villains
)について、ターミナルを開き、 cd
をプロジェクトディレクトリに入れて、 ./mvnw quarkus:dev
を実行してください。
Super Heroes UIは ソースからビルドして実行することができますが、この記事の焦点はQuarkusなので、コンテナイメージとして実行します。新しいターミナルを開き、 docker run -p 8080:8080 -e API_BASE_URL=http://localhost:8082 quay.io/quarkus-super-heroes/ui-super-heroes:latest
を実行します。
準備が整い次第、以下のURLで利用可能になります。
-
Super Heroes UI: http://localhost:8080
-
イベント統計UI : http://localhost:8085
-
ファイトサービス: http://localhost:8082
-
ヒーロー・サービス: http://localhost:8083
-
ヴィラン・サービス: : http://localhost:8084
これで、アプリケーション全体で Quarkus Dev Modeと Quarkus Continuous Testingのすべてのメリットを一度に得られるようになりました。すべてのバッキングインフラ(データベース、Kafka、Apicurio)は、 Quarkus Dev Servicesによって自動的にプロビジョニングされます。
アプリケーションをKubernetesにデプロイ
Kubernetesディスクリプターは、Kubernetesの様々なフレーバーに対応しています。 OpenShift、 Minikube、 KNative、そして「バニラ」 Kubernetesです。
MinikubeとKubernetesのディスクリプターの唯一の違いは、Minikubeのディスクリプターに含まれる全てのアプリケーション KNativeディスクリプタは、5つのアプリケーションのそれぞれに KNative Servingを使用しています。 |
Docker Composeと同様に、アプリケーション全体またはそのサブセットの 事前に構築されたコンテナイメージを、1つの kubectl apply -f
(OpenShiftを使用している場合は oc apply -f
)でKubernetesにデプロイすることができます。
レスポンダのルートにある deploy/k8s
respositoryのルートにあるディレクトリには、アプリケーションの4つのバージョンそれぞれのKubernetesディスクリプターが含まれています。JVM 11、JVM 17、Java 11で構築されたネイティブ、Java 17で構築されたネイティブの4つのバージョンのKubernetesディスクリプターが含まれています。
例えば、ネイティブのJava 17バージョンをOpenShiftにデプロイするには、単に kubectl apply -f deploy/k8s/native-java17-openshift.yml
(または oc apply -f deploy/k8s/native-java17-openshift.yml
)を実行します。
アプリケーションに加えてPrometheusモニタリングをデプロイするには、 kubectl apply -f
(OpenShiftを使用している場合は oc apply -f
)を実行するのに加え、対象となるKubernetes環境に基づいて適切なPrometheus Kubernetes descriptor: prometheus-openshift.yml
, prometheus-minikube.yml
、または prometheus-kubernetes.yml
を実行します。
MinikubeやKubernetesでは、Super Heroes UIとFightsサービスだけがクラスタの外に公開されています。PrometheusやEvent Statisticsサービスにアクセスしたい場合は、 Ingress を使用するか、Podの kubectl port-forward を行って公開する必要があります。OpenShiftでは、すべてのアプリケーションに `Route`が用意されており、クラスター外に公開されています。
|
さらに、個々のアプリケーションも同様の方法でデプロイできます。リポジトリ内の各サービスのサブディレクトリの中には、同様のKubernetesディスクリプターのマトリックスを含む deploy/k8s
ディレクトリがあります。
これらの記述は、本番環境に対応しているとは考えて いません。これらは、できるだけ少ない設定でシステムをデプロイして実行するための基本的なものです。デプロイされたデータベース、Kafkaブローカー、スキーマレジストリは、高可用性を備えておらず、管理や監視にKubernetesのオペレータを使用していません。また、エフェメラルストレージのみを使用しています。 本番対応のKafkaブローカーについては、Kubernetes上で本番対応のKafkaブローカーを適切に展開・設定する方法について、 Strimziのドキュメントをご覧ください。また、 完全にホストされ、管理されたKafkaサービスを試すこともできます! Apicurio Schema Registryの本番環境については、 Apicurio Registry Operatorのドキュメントをご覧ください。また、 完全にホストされ、管理されたスキーマ・レジストリ・サービスを試すこともできます。 本番環境用のPrometheusインスタンスについては、 Prometheus Operatorのドキュメントで、本番環境用のインスタンスの適切な導入・設定方法をご確認ください。 |
Kubernetesにデプロイされると、可能性は無限に広がります!上記の同じ例(Fightサービスの開発)を再利用すると、 Quarkus Remote Development Modeを使用してリモートインスタンスをローカルマシンに接続し、 Quarkus 開発モードと同様のエクスペリエンスを得ることができます。ポートフォワーディングの必要はありません。