今までいくつかArmeriaに関する記事を書きましたが、今回はArmeriaアプリをCentral Dogmaと連携させてKubernetes上で動かしてみます。


Central Dogmaとは?

Gitをベースにした、サービス構成リポジトリです。
Spring Cloud Configみたいなものだと思ってもらって良いと思います。(僕はSpring Cloud Configは使った事ないので細かい事はわかってないですが)

公式ドキュメント

https://line.github.io/centraldogma/

その他の資料

LINE DEVELOPER DAY 2017でのセッション資料と動画が公開されています。

Central Dogma LINE's Git-backed highly-available service configuration repository from LINE Corporation

ユースケース

Spring Bootアプリでは、アプリ設定をyamlやpropertiesファイルとしてjarに含めたり、環境変数やコマンドライン引数で設定する事が多いと思いますが、
その場合、設定を変更するためには、アプリのビルド・デプロイや、設定のプロビジョニングが必要です。

サービス稼働中に動的に設定を変更したい場合には、Central DogmaやSpring Cloud Configを導入すると便利です。

例えば、以下のようなユースケースが考えられます。

  • サービスが過負荷状態になった場合にスロットリングを行う。スロットリングの設定はCentral DogmaやSpring Cloud Configで管理しておき動的に変更可能にしておく。

※スロットリングとは、サービスが過負荷状態の時にリクエストを制限する手法の事です。



今回のアプリの構成

ブラウザからFrontendのサーバにリクエストすると、FrontendがいくつかのBackendサーバにリクエストして、結果をまとめてブラウザに返します。

構成は以下(画像をクリックすると別ウィンドウで拡大表示します)

Docker for Mac の Kubernetesで動作確認をしています。

![](https://matsumana.files.wordpress.com/2018/11/armeria_central-dogma-k8s-overview1.png?w=750)

このアプリで使っているArmeriaの機能

  • DocService (Swaggerみたいなやつだと思ってもらうと良いです)
  • Thrift API (Async)
  • REST API
  • Retrofitとのintegration
  • RxJava 2
  • Spring Bootとのintegration
  • Zipkinとのintegration
    • Server side: HttpTracingService
    • Client side: HttpTracingClient
  • Throttling
    • Server side: ThrottlingHttpService
  • Automatic retry
    • Client side: RetryingRpcClient(Thrift), RetryingHttpClient(REST)
  • Circuit Breaker
    • Client side: CircuitBreakerRpcClient(Thrift), CircuitBreakerHttpClient(REST)
  • Client-side load balancing
  • Central Dogmaとのintegration
    • CentralDogmaEndpointGroup

関連する公式ドキュメント


その他、動かしているアプリ・ミドルウェア

  • Prometheusによるモニタリング
    (KubernetesのAPI Serverでモニタリング対象Podのディスカバリを行っている)
  • Zipkinによるトレーシング
    (過去に書いた記事: Armeria w/ Zipkin)
  • Central Dogma
  • armeria-sandbox-job-kubernetesというアプリでPodのディスカバリを行って、
    PodリストをCentral Dogmaに保存。
    そのリストをArmeriaのClient-side load balancingで使用する。

armeria-sandbox-job-kubernetesアプリの補足

Armeriaには、Client-side load balancingという機能があります。
リクエスト先のAPIサーバのリストをClient側で保持して、Client側でロードバランスを行う機能です。

Kubernetesでは、PodのIPアドレスはKubernetesが動的に割り振るため、KubernetesのAPI Serverを使ってディスカバリを行い、PodリストをCentral Dogmaに保存しています。

Central DogmaにはArmeria向けのintegrarion機能があるので、Central Dogmaに保存しているPodリストを元に、ArmeriaでClient-side load balancingが簡単に行えます。



サンプルソースコード

https://github.com/matsumana/armeria-sandbox/tree/0.2.0

0.2.0というtagを付けておきました。



今回使用したバージョン

  • Java: OpenJDK (from Oracle) 11.0.1 (build 11.0.1+13)
  • Armeria: 0.75.0
    • com.linecorp.armeria:armeria
    • com.linecorp.armeria:armeria-spring-boot-starter
    • com.linecorp.armeria:armeria-thrift
    • com.linecorp.armeria:armeria-retrofit2
    • com.linecorp.armeria:armeria-rxjava
    • com.linecorp.armeria:armeria-zipkin
  • Spring Boot: 2.1.0
    • org.springframework.boot:spring-boot-starter-validation (これが無いとアプリが起動できない)
  • Thrift: 0.9.3 (最新は0.11.0だけど、Central Dogmaは0.9に依存している)
    • thrift compiler (ソースリポジトリのlibディレクトリに同梱しています)
    • org.apache.thrift:libthrift
  • thrift-gradle-plugin: 0.4.0
  • Retrofit: 2.4.0
  • Central Dogma: 0.32.1
  • Docker for Mac: 18.06.1-ce-mac73
    • Engine: 18.06.1-ce
    • Kubernetes: v1.10.3


サンプルアプリをKubernetesにデプロイする

1. ローカルにDocker registryを起動する

KubernetesはDocker registryからイメージを取得するので、アプリのDockerイメージを保存するためのローカルなDocker registryが必要です。
(Prometheus, Zipkin, Central DogmaはDocker Hubで公開されているので、ローカルなDocker registryにpushする必要はありません)

$ docker run -d -p 5000:5000 --name registry registry:2.6

2. Prometheus, Zipkin, Central Dogmaを起動する

$ make kubectl-create-depends

3. Central Dogmaにスロットリング設定ファイルを登録する

Central Dogmaが起動するまで少し待って、以下のコマンドを実行してください。

$ make kubectl-create-depends-data

スロットリングについては、この記事の下の方で説明します。


4. アプリをビルドする

Java 11が必要です。

$ ./gradlew --no-daemon clean build

ローカルにJava 11がインストールされていない場合、以下のコマンドを使うとDockerコンテナを使ってビルドが出来ます。
ただし処理のオーバーヘッドがあるのでかなり遅いです。

$ make build-with-docker

5. Dockerイメージをビルドする

$ make docker-build-kubernetes-dev

もしくは、

$ make docker-build-kubernetes-production

docker-build-kubernetes-devの方は、リモートデバッグの設定が入っているので、IntelliJなどで接続してデバッグが出来ます。


6. ローカルのDocker registryにpushする

$ make docker-push

7. アプリをKubernetesにデプロイする

$ make kubectl-create-apps

8. アプリの起動確認

まず、アプリが全て起動している事をPrometheusの画面で確認します。
以下のURLを開いて、
http://localhost:30000/targets

Statusが全てUPになるまで待ちます。


次に、KubernetesのAPIサーバからPodの情報を収集して、Central Dogmaに正しく保存出来ているか確認します。

以下のURLを開いて、
http://localhost:30002/#/projects/armeriaSandbox/repos/apiServers

backend1.jsonbackend4.jsonfrontend.jsonが出来ていればOKです。

これらのjsonファイルは、armeria-sandbox-job-kubernetesアプリで生成しています。


9. 破棄コマンド

以下のコマンドで今回のアプリを全て破棄できます

$ make kubectl-delete-apps
$ make kubectl-delete-depends
$ docker stop registry
$ docker rm registry


サンプルアプリを動かしてみる

以下のURLにブラウザやcurlでリクエストすると、
http://localhost:31000/hello/foo

以下のレスポンスが返ってきます。各APIサーバでechoした結果を集めているだけの簡単なAPIです。

Zipkinで見てみるとこんな感じ。

backend1〜4はそれぞれ非同期でリクエストするように実装しているんですが、
Zipkin( http://localhost:30001/zipkin/ )で見るとよくわかりますね。

スロットリングしてみる

Central Dogmaに保存されているthrottling.jsonがスロットリング設定ファイルです。

以下のURLを開いて、
http://localhost:30002/#/projects/armeriaSandbox/repos/apiServers/files/head/throttling.json

backend1に対するリクエストをスロットリングして、半分のリクエストを拒否するように設定してみましょう。値を0.5にします。

http://localhost:31000/hello/foo にリクエストして、Zipkinで見てみると以下のような感じになると思います。

このアプリでは、Armeria clientのAutomatic retryを設定しているので、リトライしている様子もよくわかりますね。

スロットリングの設定を0とかにすると、Circuit Breakerの動作確認も簡単に出来ます。
(過去に書いた記事: ArmeriaのCircuit Breaker)


また、余談ですが、実際のサービスでリトライやCircuit Breakerの導入を検討する場合は、
SRE本の21章(過負荷への対応)〜22章(カスケード障害への対応)が参考になると思います



まとめ

今回は、ArmeriaアプリをCentral Dogmaと連携させてKubernetes上で動かし、Client-side load balancingやスロットリングの機能を試してみました。

以上です。