Amalgam8 - コンテンツ 及び バージョンベース ルーティング サービス

## はじめに

Bluemix(SoftLayer) Advent Calendar 2016、第14日目は Amalgam8 の話です。

## 1. Amalgam8 とは？

Amalgam8 (amalgamate - アマルガメイトと呼ぶそうです) は、IBMの研究者が2016/6月に公開した OSS で、マイクロサービスのためのアプリケーション・スイッチです。OSIのレイヤー７に当たるものであると言ってよいでしょう。

Kubernetes, Docker Swarm, Netflix OSS などがあるのに、なぜ Amalgam8 を開発したのか？という理由について開発者が以下のように述べています。

> There was no clean solution for client-side load balancing that was highly programmable (プログラミング可能なクライアントサイドのロードバランサーのクリーンなソリューションがないため)

クラウド上で実行される、アプリケーションフロントエンドや、バックエンドのマイクロサービスは比較的早いサイクルで開発されることを期待されていますが、テストが不十分なサービスをデプロイしてしまうと問題が発生する可能性があります。そこで、よく言われるカナリアリリースなどの手法を用いよなどと様々な文献[1]に書かれていますが、具体的な How-To (方法)の情報に乏しいのが実情ではないかと思われます。

Amalgam8は、プログラム可能なアプリケーションスイッチということで以下の機能を持ちます。

- コンテキストもしくはバージョンベースのルーティング機能
- サービス耐用性（レジリエンス）試験を行うための Gremlin 試験機能

図で表すと以下のようになります。

![amalgam8-overview.png](https://qiita-image-store.s3.amazonaws.com/0/74673/e1465ca9-4480-9cb4-f5cb-580c490536c1.png "Amalgam8 概要")
(https://www.ibm.com/blogs/bluemix/2016/06/amalgam8-integration-fabric-microservices-cloud/から引用)

図中AからBには 70%のトラフィック、B'には30%のトラフィックが転送されている様子がわかると思います。このように負荷分散をプログラミングできるようにしようというのが狙いです。

また Amalgam8 は 稼働するプラットフォームや、開発言語に依存しないように設計されています。IBM Bluemix は言うに及ばず、Kubernetes、Google Platform でも動作するようです。非依存は、"Agnotic" や "Polyglot" という用語がよく使われますが、2016年によく聞いたキーワードになっていると感じました。

さて、今回は Amalgam8 の紹介に留めて、IBM Bluemix 上での動作は別の機会にでも紹介したいと思います。


## 2. Amalgam8 helloworld

論より証拠。早速試してみましょう。なお、本記事内容は [amalgam8.ioサイト](https://amalgam8.io) の DEMO アプリケーション内容そのものです。

### 2.1 準備

デモを動かす前に以下の環境セットアップが必要です。以下の環境（コマンド、ライブラリ）を用意します。

- git コマンド
- Docker 1.10 以上
- Docker-compose 1.5.1 以上
- Python 2.7.9 以上

本投稿では、Ubuntu 10.04 LTS で実行確認しました。

Amalgam8 リポジトリをダウンロードします。

    git clone https://github.com/amalgam8/amalgam8.git
    cd amalgam8

Amalgam8 のコントローラー（Service Registry 及び Route Controller) を起動します。

    docker-compose -f examples/docker-controlplane.yaml up -d

サービスが利用する DB (redis) や ログ収集のためのスタック(logstash/kibana)も同時に入ります。起動すると以下のようなコンテナが動作しているはずです。

    docker ps
    CONTAINER ID        IMAGE                    COMMAND                  CREATED              STATUS              PORTS                     NAMES
    71b53a22f68d        kibana                   "/docker-entrypoint.s"   49 seconds ago       Up 41 seconds       0.0.0.0:30500->5601/tcp   kibana
    f7602f86af4a        logstash                 "/docker-entrypoint.s"   About a minute ago   Up About a minute   0.0.0.0:8092->8092/tcp    logstash
    9fdad0a70f40        amalgam8/a8-registry     "/opt/a8registry/a8re"   About a minute ago   Up About a minute   0.0.0.0:31300->8080/tcp   registry
    dd76c56ac220        amalgam8/a8-controller   "/opt/a8controller/a8"   2 minutes ago        Up 2 minutes        0.0.0.0:31200->8080/tcp   controller
    b67b70805284        redis:alpine             "docker-entrypoint.sh"   2 minutes ago        Up 2 minutes        0.0.0.0:31400->6379/tcp   redis


a8ctl コマンドを導入します。

    pip install --user a8ctl

環境変数を設定します。

    export PATH=$PATH:${HOME}/.local/bin
    export A8_CONTROLLER_URL=http://localhost:31200
    export A8_REGISTRY_URL=http://localhost:31300

試しに a8ctl コマンド実行してみます。

    $ a8ctl -h
    usage: a8ctl [-h] [--debug] [--a8-controller-url A8_CONTROLLER_URL]
                 [--a8-controller-token A8_CONTROLLER_TOKEN]
                 [--a8-registry-url A8_REGISTRY_URL]
                 [--a8-registry-token A8_REGISTRY_TOKEN]
                 [--a8-log-server A8_LOG_SERVER]
                 subcommand ...

    Query and manipulate the Amalgam8 Microservice Fabric Controller to manage
    microservice routing rules or inject failures and delays.

準備が整いました。簡単ですね！

### 2.2 helloworld を動かしてみる

サンプルとして用意されている helloworld には二つのバージョンが存在します。v1, v2 です。examples フォルダーにある docker-helloworld.yaml を起動すると３つのコンテナが起動します。同時にスケールもさせてみましょう。

    docker-compose -f examples/docker-helloworld.yaml up -d
    docker-compose -f examples/docker-helloworld.yaml scale helloworld-v1=2
    docker-compose -f examples/docker-helloworld.yaml scale helloworld-v2=2

この時点で以下の図のような構成になっています。

![helloworld-1.png](https://qiita-image-store.s3.amazonaws.com/0/74673/feac4865-ace6-1818-7182-be4fc564751c.png "helloworld 1" )
図：helloworld のデプロイメント


図に Sidecar というコンポーネントがありますね。説明は後回しにしますが、ここでは簡単に Sidecar とはトラフィックをルーティングする実体とだけ覚えてください。なおこの時点で helloworld(v1, v2) は registry に登録済みになっています。

    $ a8ctl service-list

    +------------+--------------+
    | Service    | Instances    |
    +------------+--------------+
    | helloworld | v1(2), v2(2) |
    +------------+--------------+

### ルーティングの設定をする（v1のみ）

ではルーティングの設定をします。最初はデフォルトで v1 にのみ流れるようにします。

    a8ctl route-set helloworld --default v1

この状態で以下の図ようなトラフィックの流れ設定になっています。

![helloworld-2.png](https://qiita-image-store.s3.amazonaws.com/0/74673/c4c4693f-940e-d7f0-a4f9-48be3a3d2511.png "helloworld 2" )
図：v1 をデフォルトに設定

ルーティングルールは "a8ctl route-list" で出てきます。

    $ a8ctl route-set helloworld --default v1
    Set routing rules for microservice helloworld
    $ a8ctl route-list
    +------------+-----------------+-------------------+
    | Service    | Default Version | Version Selectors |
    +------------+-----------------+-------------------+
    | helloworld | v1              |                   |
    +------------+-----------------+-------------------+

Gateway は http://localhost:32000 で起動しています。helloworld にアクセスするには ”URL/service-name/service” のような形式でアクセスする必要があります。

    $ curl http://localhost:32000/helloworld/hello
    Hello version: v1, container: 46156eea8272

本当に v1 だけなのか？ということで 1000回呼び出すスクリプト(test.sh)を用意しました。

    #!/usr/bin/env bash
    loop=1000

    while [ $loop -gt 0 ]; do
      curl -s http://$GATEWAY_URL/helloworld/hello | awk '{print $3}' | sed s/,//g
    	let loop-=1
    done

スクリプトは v1 か v2 かを取り出すものです。実行してカウントしてみましょう。

    $ export GATEWAY_URL=localhost:32000
    $ bash test.sh | sort | uniq -c
      1000 v1

1000回 v1 だけでした。

### ルーティングの設定をする (v2に10%)

次に、v2 にもルーティングするように設定します。tags を指定して何% のトラフィックを v2 に割り振るかを設定します。

    a8ctl route-set helloworld --default v1 --selector 'v2(weight=0.1)'

ここで v2 がバージョンセレクターで、ルーティングの重みは (weight) です。設定を確認してみます。

    $ a8ctl route-set helloworld --default v1 --selector 'v2(weight=0.1)'
    Set routing rules for microservice helloworld
    $ a8ctl route-list
    +------------+-----------------+-------------------+
    | Service    | Default Version | Version Selectors |
    +------------+-----------------+-------------------+
    | helloworld | v1              | v2(weight=0.1)    |
    +------------+-----------------+-------------------+

この状態で以下の図のようなトラフィックの流れになります。

![helloworld-3.png](https://qiita-image-store.s3.amazonaws.com/0/74673/50bc6ee7-774e-0abc-ffcf-dbaa73bf2349.png "helloworld 3" )
図：v1はデフォルトだが、10%を v2 に転送


確認してみましょう。

    $ bash test.sh | sort | uniq -c
        894 v1
        106 v2
    $ bash test.sh | sort | uniq -c
        896 v1
        104 v2


v1 が 894(896), v2 が 106(104) なので、だいたい 10% くらいでしょうか？

## 3. Sidecar とは？

Amalgam8 のコアはこの Sidecar にあると言ってもよいかと思います。Sidecar が control plain で管理しているルーティングルールを読み込んで、トラフィック分配しています。

![amalgam8-sidecar-components.png](https://qiita-image-store.s3.amazonaws.com/0/74673/7f64292c-f082-68cd-bd0a-8ba09ac648fd.png "Amalgam8 Sidecar コンポーネント")
図：amalgam8-sidecar-components (amalgam8.io から引用)

ルーティングは Proxy コンポーネントで行っています。Tenant Application がアプリケーション本体です。その他、サービスの自動登録をする Service Registration、Proxy へのルート指示を行う (Route Management があります。Supervisor は Proxy その他のコンポーネントを監視して、不測の事態（例えば Proxyの停止）などに備えてコンポーネントの監視をしています。

では、既存のサービス（フロントエンド、バックエンド）がある場合に Sidecar を組み込むにはどうすればよいでしょうか？　２種類方法があります。

1. Dockerfile に　sidecar 導入の命令を追加する
2. Helper サービスとして単独で起動する (Kubernetesのみ)

＃2の方法ではサービスに手を加える必要がないのですが、Kubernetes環境のみのサポートです。実は ＃1 はさほど難しくありません。

例えば Dockerfile があった場合に Sidecar を組み込むには 以下の行を適切な場所にいれればOKです。

    RUN curl -sSL https://github.com/amalgam8/amalgam8/releases/download/${VERSION}/a8sidecar.sh | sh

例えばこのような形。

    FROM <somebaseimage>
    RUN curl -sSL https://github.com/amalgam8/amalgam8/releases/download/${VERSION}/a8sidecar.sh | sh

    ## ここから既存のアプリケーション設定

    ## sidecar とアプリケーションの起動

ただしサービス側のコードに少し修正が必要です。外部サービスの呼び出しは サービス直接の URL ではなく、Proxy をたたく形になり、それは

    http://localhost:6379/serviceName/endpoint

のように呼び出すように変更する必要があります(以下の図参照）。

![sidecar-setting.png](https://qiita-image-store.s3.amazonaws.com/0/74673/232080e2-1cfd-b415-1214-0148423535a2.png "Sidecar 設定")　図：sidecar の設定

このように Sidecar を組み込み、Amalgam8 の Control Plane を用意しておけば、既存の環境に試験対象サービスを組み込み、多少のトラフィックをそちらに流すというようなことができるようになります。まさにカナリア試験ですね。


## まとめ

Amalgam8 はクラウドアプリケーション（フロントエンド、バックエンド）においてコンテキスト、バージョンのアプリケーションスイッチを実現します。

今回紹介しきれませんでしたが、

- 例えば http のヘッダに "QA" という文字があれば試験中のサービスにルーティング
- 特定のユーザーのみ別のサービスにルーティング

する等、様々なルーティング設定方法があります。また、Chaos Monkey ならず、Gremlin機能も付属しており、Chaos Monkey ライクな試験を行う機能も盛り込まれています。

サービス稼働中に新しいサービスをデプロイするというのは勇気のいることですが、Amalgam8 を入れておけば安心ですね！

次回のBluemix (Softlayer) アドベンドカレンダーは@y_tamaさんです。お楽しみに。

### 参考文献
[1] http://martinfowler.com/bliki/CanaryRelease.html "カナリアリリース"