OpenShift + AMQ Streams(Apache Kafka) + QUARKUS で実現するアプリケーション
QUARKUS を利用するとメモリ使用量を抑え、起動が爆速なアプリケーションを Java 言語で開発することができます。
QUARKUS の Extension には Kafka クライアントや SmallRye Reactive Messaging があり、後者を利用するとアノテーションベースでメッセージのやりとりが可能なアプリケーションを開発することができます。
OpenShift に AMQ Streams(Apache Kafka) を構築し、QUARKUS のサンプルアプリケーションをデプロイして動作させて見ようと思います。
QUARKUS の詳細については Publicky さんの記事を参照ください。
AMQ Streams on OpenShift
ここでは OpenShift 4.2 を使用します。
OpenShift 上のプロジェクトは「quarkus」としてあらかじめ作成しました。OperatorHub にアクセスして AMQ Streams Operatorを選択します。
Install を選択して、AMQ Streams Operator をインストールします。
「quarkus」プロジェクトのみに AMQ Streams Operator を適用して「Subscribe」を選択します。
「Subscribe」を押すと、以下の画面に遷移して Operator がインストールされます。下記の「Status」が「Up to date」から「Install Succeeded」になるまで待機してください。
「Install Succeeded」になったら、「AMQ Streams」のリンクをクリックして、クラスターを作成します。「Kafka」のタブから「Create Kafka」を選択してください。
yaml ファイルが編集できるようになりますが、そのまま「Create」を押してください。デフォルトでは Kafka クラスター × 3、Zookeeper × 3 が起動します。
今回、テスト用に作成しているため、storage は ephemeral にしていますが、本番で AMQ Streams を利用する場合は EBS などのブロックストレージを準備してください。
Kafka クラスターと Zookeeper クラスターが 3 pod ずつ作成されます。
AMQ Streams Operator から Topic の作成もできますが、QUARKUS のサンプルが自動でトピックを作成するよう作られているため今回は作成しません。
QUARKUS kafka-quickstart のビルドと Docker イメージ化
今回使用するサンプルはこれになります。ソースコードはこれです。
ただ、QUARKUS はリリースが頻繁に実施されていることもあり、同じ手順で動作しないケースがありえます。その場合は後述する Docker Hub 上にあるイメージを利用してください。QUARKUS のビルドに必要な準備は終わっているものとして話を進めます。
ソースコード弄るのがいやだよという人は Docker イメージを kkosugiredhat/kafka-quickstart:v1 に置きました。「OpenShift にデプロイ」でこのイメージを使ってください。
このサンプルは以下のような動作をします。
- Kafka Consumer である PriceGenerator が 5 秒おきにランダム(0–99の範囲)で価格を生成し、AMQ Streams の prices トピックに値を格納
- PriceConverter が prices トピックからメッセージを取り出し、価格にCONVERSION_RATE を乗算してメモリ上の my-data-stream に格納。
- prices.html が JAX-RS で作成された PriceResource に REST 経由でアクセスしメモリ上の my-data-stream から価格を取り出して HTML に表示。
git clone を実施するか ZIP をダウンロードしてソースコードを用意します。
まず、Kafka の接続先を定義します。src/main/resources/application.properties を開き、以下の2行を加えてください。QUARKUS のサンプルでは localhost の Kafka に接続するよう設定されているため、デフォルトでは localhost:9092 にずっと接続を試みます。これを OpenShift 上の Kafka Bootstrap Server に変更します。
%prod.mp.messaging.outgoing.generated-price.bootstrap.servers=my-cluster-kafka-bootstrap:9092
%prod.mp.messaging.incoming.prices.bootstrap.servers=my-cluster-kafka-bootstrap:9092
続いて src/main/resources/META-INF/resources/prices.html を編集します。現時点で価格が € 表記されるため、$になおしましょう。
<div class="container">
<h2>Last price</h2>
<div class="row">
<p class="col-md-12">The last price is <strong><span id="content">N/A</span> $</strong>.</p>
</div>
</div>
src/main/docker/Dockerfile.native も編集します。QUARKUS は 8080 ポートを利用するのですが、サンプルは 8081 を EXPOSE しており、しかも
-Dquarkus.http.port=8081 で起動するよう指定していないため、このままでは動作しません。
####
# This Dockerfile is used in order to build a container that runs the Quarkus application in native (no JVM) mode
#
# Before building the docker image run:
#
# mvn package -Pnative -Dnative-image.docker-build=true
#
# Then, build the image with:
#
# docker build -f src/main/docker/Dockerfile.native -t quarkus/kafka-quickstart .
#
# Then run the container using:
#
# docker run -i --rm -p 8081:8081 quarkus/kafka-quickstart
#
###
FROM registry.access.redhat.com/ubi8/ubi-minimal
WORKDIR /work/
COPY target/*-runner /work/application
RUN chmod 775 /work
EXPOSE 8080
CMD ["./application", "-Dquarkus.http.host=0.0.0.0"]
ではビルドしていきます。
QUARKUS ネイティブビルド
native プロファイルと -Dnative-image.docker-build=true オプションを使用して Linux 用のバイナリを生成します。
※ mvnw は Gradlew のように Maven がインストールされていない環境においても Maven ビルドができるように作られているスクリプトになります。
$ ./mvnw package -Pnative -Dnative-image.docker-build=true
Docker イメージのビルド
Docker イメージを作成します。kkosugiredhat の部分はご自身の DockerHub アカウント名に変更してください。
$ docker build -t kkosugiredhat/kafka-quickstart:v1 -f ./src/main/docker/Dockerfile.native .
今回は DockerHub 上に Docker イメージをあげて OpenShift 上にデプロイします。(Docker login を事前に実施しておいてください)
$ docker push kkosugiredhat/kafka-quickstart:v1
OpenShift にデプロイ
「Developer」ポータルから「+Add」->「Conatiner Image」を選択します。
「Image Name」に kkosugiredhat/kafka-quickstart:v1 を入力し、Enter を押して DockerHub 上のイメージを指定します。「Create」を選択すると DeploymentConfig、Pod、Service そして Route が自動で作成されます。
「Networking」->「Routes」から作成された Route を見て「Location」に貼られているリンクをクリックします。
以下のような画面が表示されます。
これは特に編集を加えなかった src/main/resources/META-INF/resources/index.html が表示されています。URL の末尾に prices.html をつけて再度アクセスします。
上記の通り、5秒おきに最新の価格を取得する HTML が表示されます。
おさらいですが、内部的には下記の動作をしています。
OpenShift の「Installed Operators」から「AMQ Streams」->「Kafka Topic」に飛ぶと、QUARKUS のサンプルアプリケーションが自動で作成した prices トピックが表示されているのが確認できます。
最後に
今回のサンプルを通して、Red Hat の OpenShift が用意する AMQ Streams Operator を使用すれば Kafka クラスターの構築が簡単におこなえることがわかっていただけたかと思います。また、QUARKUS を利用することで、Pod としてあがってくるアプリケーションを高速に立ち上げることも可能になります。
Kafka をこれから検討される方は是非 OpenShift 上での利用も検討してみると良いかもしれません。