2015年4月27日月曜日

Finagle+Karaf+Dockerでmicroservices

流行りなのでmicroservicesという用語を使ってみましたが、意図としては(microservicesも含む)マルチサーバー構成によるクラウド・システムを構成するサービス群がターゲットです。

この実行基盤としてFinagle、Karaf、Dockerの組合せが有力ではないかということで、試しにサンプルプロジェクトを作ってみました。このサンプルプロジェクトは、新しいクラウド・システム内サービスを作る時の雛形を想定しています。

このサンプルプロジェクトを実際に作ってみることで、Karafがどのぐらいの手間で使えるのか、ScalaやFinagleとの相性はどうなのか、といったことを試してみるのが目的です。この手のプロジェクト構築ではライブラリ間の依存関係の解決が難しいのですが、Finagleをリンクしても大丈夫な設定を発見できたので、この問題はクリアできていると思います。

以下ではクラウド・システム内サービスをサービスの粒度によらずmicroserviceと呼ぶことにします。

Apache Karaf

Apache Karafは軽量OSGiコンテナです。

Karafを導入する目的は大きく以下の3つです。

  • microserviceの環境設定共有
  • dependency hell対策
  • CamelによるEIP(Enterprise Integration Patterns)
環境設定共有

第一の目的はクラウド・システムを構成するmicroservice群の環境設定を共通化することです。

microserviceをmainメソッドを作るなどして自前でデーモン化すると各種設定もすべて自前で行わなければならなくなります。

たとえば、SLF4J+fluentedなどによるロギング、JMX(Java Management Extensions)による運用監視、JNDI(Java Naming and Directory Interface)によるディレクトリ管理といった各種設定をサービス毎に設定する必要があります。

これは(1)設定そのものが大変な手間、(2)クラウド・システム内の共通設定情報の共有の手間、(3)設定漏れの危険、(4)ハードコーディングによるカスタマイザビリティの欠如、といった問題があります。

microserviceをコンテナ内で動作させることで、各種設定はコンテナに対する設定として共通化する上記の問題を解消することができます。

この目的で導入するコンテナとして、軽量OSGiコンテナであるKarafがよいのではないか考えています。

dependency hell対策

Java VM上での開発における未解決問題の一つにdependency hellがあります。

この問題はJava 9でModule機能として解決される見込みですが、当面の対策としてはOSGiコンテナを使用するのが現実解となっています。

最近はちょっとしたライブラリをリンクしても、その裏でApache Commons、Spring、JBossといった巨大なライブラリがついてくることが多いので、思ったより切実な問題です。

CamelによるEIP

Karafを採用したボーナスのようなものですが、KarafからはCamelを簡単に使えるようになっています。(KarafはESB(Enterprise Service Bus)のServiceMixのOSGiコンテナ部を切り出して製品化したものです。)

Camelを使うと、EIPのパターンを使用して様々な通信プロトコルを使って外部サービスと連携する処理を簡単に作成することができます。またCamelにはScala DSLも用意されています。

Twitter Finagle

Twitter Finagleはmicroservices指向のRPCシステムです。

FinagleはFutureモナドによる非同期実行、耐故障性の抽象化を行っており、Monadic Programmingとの相性がよいのもFunctional Reactive Programming指向のmicroservicesの通信基盤として魅力です。

準備

Karafを使うためのベースとしてKarafの実行環境をDockerイメージ化しました。

Karaf Docker Image

Dockerイメージを作成するプロジェクトは以下になります。

Dockerfileだけの簡単なプロジェクトです。

実際にmicroserviceをインストールして使うことを想定しているので、余分な設定は行わずプレインな簡単なものにしています。

Docker Hub

このDockerイメージをDocker Hubに登録しました。

以下のようにして利用できます。

$ docker pull asami/karaf-docker

サンプル・プロジェクト

サンプル・プロジェクトは以下のGitHubプロジェクトとして作成しました。

サンプル・サーバー

Finagleによるサンプル・サーバーは以下のものです。

package sample

import com.twitter.finagle.{Http, Service, ListeningServer}
import com.twitter.util.{Await, Future}
import java.net.InetSocketAddress
import org.jboss.netty.handler.codec.http._

object Server {
  val service = new Service[HttpRequest, HttpResponse] {
    def apply(req: HttpRequest): Future[HttpResponse] =
      Future.value(new DefaultHttpResponse(
        req.getProtocolVersion, HttpResponseStatus.OK))
  }

  def start(): ListeningServer = {
    Http.serve(":8080", service)
  }

  def stop(server: ListeningServer) {
    server.close()
  }

  def main(args: Array[String]) {
    val server = start()
    Await.ready(server)
  }
}
ビルド

ビルドは以下の手順で行います。

  • Karaf KAR
  • Dockerfile
  • Dockerイメージ
Karaf KAR

Karafに配備するKARファイルの作成にはkarafタスクを使用します。

$ sbt karaf

karafタスクはbuild.sbtで定義しています。

Dockerfile

KARファイルを配備したKaraf実行環境のDockerイメージを作成するためのDockerfileの作成にはdockerタスクを使用します。

$ sbt docker

dockerタスクはbuild.sbtで定義しています。

Dockerイメージ

Dockerイメージの作成は以下になります。

$ docker build -t sample-finagle-karaf-docker .

dockerタスクを実行するとDockerfileが作成されるので、このDockerfileでDockerイメージをビルドします。この時、前述したDockerイメージasami/karaf-dockerを内部的に使用します。

実行

作成したDockerイメージsample-finagle-karaf-dockerを実行してみましょう。

$ docker run -t -i --rm -p 1099:1099 -p 8101:8101 -p 44444:44444 -p 8080:8080 sample-finagle-karaf-docker

ポートは1099, 8101, 44444, 8080の4ポートを使用します。

ポート1099, 8101, 44444はKarafが使用するポートです。

ポート用途
1099JMX RMI registry
8101SSHコンソール
44444JMX RMI server

ポート8080はサンプルのFinagleサービスが使用するポートです。

確認

Dockeイメージを実行するとKarafコンテナ内で自動的にサンプルのFinagleサービスが起動されます。

curlコマンドでサンプルのFinagleサービスにアクセスすると以下の結果が得られます。無事動作していることが確認できました。

$ curl http://192.168.59.103:8080 -v
* Rebuilt URL to: http://192.168.59.103:8080/
* Hostname was NOT found in DNS cache
*   Trying 192.168.59.103...
* Connected to 192.168.59.103 (127.0.0.1) port 8080 (#0)
> GET / HTTP/1.1
> User-Agent: curl/7.37.1
> Host: 192.168.59.103:8080
> Accept: */*
> 
< HTTP/1.1 200 OK
< Content-Length: 0
< 
* Connection #0 to host 192.168.59.103 left intact

感想

現時点だとSBTからKaraf向けのKARファイルの作成のための設定が大変なので、まだまだKarafは気軽には使えないような感じです。

ただAPPREL CLOUD級の規模になってくると設定の大変さよりも運用管理上のメリットの方が大きくなるのでそろそろ導入を考えてもよさそうです。

諸元

  • Scala 2.10.5
  • Finagle 6.25.0
  • Karaf 4.0.0.M2
  • Docker 1.3.2
  • sbt 0.13.7

0 件のコメント:

コメントを投稿