Azure Service Fabric を使う（１）利用するための環境を揃える

今までの Azure 関連の記事は以下。

[Azure Container Serviceを使う（１） 基本のデプロイ編](http://qiita.com/derui@github/items/64cc13016c002db69308)
[Azure Container Serviceを使う（２） 自動化してみる編]()

## Azure Container Service と Micro Services ##

Azure Container Service(以下 ACS) についてやってきましたが、ACS は構成を作成するテンプレートという性格上、運用とか監視などは、あくまでこちらがやらなければならないものでした。
Docker Container を利用することによる自由の代償ですが、そもそもそこまで自由である必要がないケースも多くあると思います。

例えば最近 Buzz word になってる感がある Micro Services を、コンテナベースにしてACS上で動かしてみようとすると、以下のような課題を解決していく必要があります。

* アプリの監視系統まで用意しないといけない
* アプリそのもののスケール方式を用意しないといけない
* アプリのリカバリ方式を用意しないといけない
* …その他

実際にアプリケーションを運用していく際に、必要になっていくものを、自前で解決しないとなりません。環境構築マニアなら楽しいかもしれませんが、結構な時間が必要なのも事実です。
また、環境以外でも、サービス間の連携について考慮すべき点など、考える必要があるものはこれ以外にも多岐に渡ります。

こういった点から、すでに周辺でこういった環境が用意されていないのであれば、ACS はファーストチョイスとしづらいかと思います。

Azure 上で Micro Services を構築しようとした時、ファーストチョイスとなるのは ACS ではなく、 [Service Fabric](https://azure.microsoft.com/ja-jp/services/service-fabric/) になるかと思います。

## Service Fabric ##
Service Fabricとは、以下の特徴を持つ Microsoft Azure が 提供する Managed Service です。

* 小さなサービスを組み合わせて一つのサービスとする
* それぞれのサービスは自動的にスケールする
* 各サービスが個別に冗長化される
* ステートフルなサービスとステートレスなサービスを明示的に分けられる
* 更新のあったサービスのみを更新するライブアップデートが標準装備
* サービス間の通信を標準化できる
* コンテナをサービスとして実行できる（2016/10時点ではDockerのみ、Linux サーバー限定）
* Azure/オンプレ間で同一の実装を動かせる

Service Fabric 自体は、その名の通りサービスの基礎としてのサービスを提供しています。実際に Azure が提供している Managed Service や、Microsoft本体のサービスでも利用されているようで、公式には少なくとも以下のサービスで利用されているようです。

> Skype for Business、Intune、Azure Event Hubs、Azure Data Factory、Azure DocumentDB、Azure SQL Database、Cortana

Service Fabric の説明の中では、 Micro Services ＝ Service Fabric 内の各サービス、とされているようです。ステートレスなマイクロサービスってよくわかりませんが、例では nginx 等のプロキシとかが挙げられていました。

用語はさておき、Service Fabric は Micro Services を構築していく中で困ることや欲しい機能が、標準で用意されているところに大きな利点があります。上に挙げたように、スケールの制御とか冗長化とか、自前で行うと結構ヘビーな機能が標準で用意されていますので、作る側としては作ることに集中することが出来ます。

### Service Fabric の制限 ###
割とサービスを構築する上でいたれりつくせりな感がある Service Fabric ですが、いくつか制限があります。

* X509証明書が必要
 * 管理用と接続用に2つ必要です。ちゃんと署名されている必要があるようで。。。
* PowerShellが強い
 * 公式サンプルのほぼ全てがPowerShellです。Azure CLIのサンプルも欲しい。。。
* SDKに則らなければならない
 * これは、他のクラウドの Managed Service でも大抵そうなってるので、まぁ普通かなと

この他の制約としては、基本的にVisual Studio 推しである、というくらいでしょうか。C#をやるにおいて最強のIDEであることに異論はありません。

## Service Fabric と Java/Linux ##
さて、実際に Service Fabric で動作するアプリケーションを作ってみたいところですが…残念ながら私のような、メインマシンが Linux であるようなマイノリティは、Visual Studio も PowerShell も（今の所）利用することが出来ません。

これは詰んだか、と思いきや、最近の Microsoft らしく、 Linux 上での環境構築と、Java での実装ガイドがありました。

https://azure.microsoft.com/ja-jp/documentation/articles/service-fabric-get-started-linux/

これを読みながら、 他でも流用できるように Vagrant で動かせるようにしていきましょう。Java で動かすのか C# で動かすのかはその後でも。

### Service Fabric の用語 ###
事前に [公式の用語集](https://azure.microsoft.com/ja-jp/documentation/articles/service-fabric-technical-overview/) を読んでおいたほうがいいかと思います。結構独自の概念がありますので。

### Vagrantを立ち上げる ###
まずはVagrantを立ち上げましょう。サポートしているのが `Ubuntu 16.04 (Xenial Xerus)` ということなので、公式のを…といきたいところですが、Ubuntu公式のboxは結構問題があって、大抵2回め以降起動しなくなります（経験済み）。

そこで、評価の良い [bentoのubuntu 16.04](https://atlas.hashicorp.com/bento/boxes/ubuntu-16.04) を使います。bentoのロゴが本当の弁当箱な辺り、Chefプロジェクトっぽいですね。

```ruby
Vagrant.configure("2") do |config|
  config.vm.box = "bento/ubuntu-16.04"

```

そして、事前に Service Fabric Explorer で利用するポートを開けておきます。

```ruby
  ...
  config.vm.network "forwarded_port", guest: 19080, host: 19080
  ...
```

Vagrant 本体の設定はこれくらいで、実際のセットアップは provisioning から行うことにします。

```shell
#!/bin/sh

sudo sh -c 'echo "deb [arch=amd64] http://apt-mo.trafficmanager.net/repos/servicefabric/ trusty main" > /etc/apt/sources.list.d/servicefabric.list'
sudo apt-key adv --keyserver apt-mo.trafficmanager.net --recv-keys 417A0893

sudo apt update
sudo apt upgrade -y

sudo locale-gen ja_JP.UTF-8
# servicefabricとservicefabricsdkcommonの両方に対して、EULAの承諾が必要。
echo debconf servicefabric/accepted-all-eula select true | sudo debconf-set-selections
echo debconf servicefabric/accepted-all-eula seen true | sudo debconf-set-selections
echo debconf servicefabricsdkcommon/accepted-all-eula select true | sudo debconf-set-selections
echo debconf servicefabricsdkcommon/accepted-all-eula seen true | sudo debconf-set-selections
sudo DEBIAN_ERONTEND=noninteractive apt install -yq software-properties-common git-core servicefabricsdkcommon servicefabricsdkjava

sudo /opt/microsoft/sdk/servicefabric/common/sdkcommonsetup.sh

# Azure クロスプラットフォーム CLIも利用するので追加しておく
git clone https://github.com/Azure/azure-xplat-cli.git
pushd azure-xplat-cli
npm install

sudo ln -s $(pwd)/bin/azure /usr/bin/azure
popd

azure --completion >> ~/azure.completion.sh
echo 'source ~/azure.completion.sh' >> ~/.bash_profile

sudo /opt/microsoft/sdk/servicefabric/java/sdkjavasetup.sh
sudo /opt/microsoft/sdk/servicefabric/common/clustersetup/devclustersetup.sh
```

最初の2行と、真ん中辺りが実際に Service Fabric 関連をインストールする設定です。Service Fabric 関連をインストールする際に、EULAの承諾を必要とするため、その部分をスキップしています。

後半は、実際に利用する上で、クロスプラットフォームCLIも利用するので、それも追加しています。

最後の行は、ローカルでの開発に利用するためのクラスタを作成しています。これ自体は一回行えば良いため、provisioning のタイミングで行っています。

ここまで設定した時点で、 `vagrant up`後に自動的に Service Fabric が起動するようになります。最初に開いておいた 19080 ポートにブラウザでアクセスすると、ちゃんと設定できていれば、以下のようなページが開きます。

![1.png](https://qiita-image-store.s3.amazonaws.com/0/12490/51707a72-77ec-8d08-bcf1-378c1189aae6.png "1.png")


ちなみに、マシン起動時のService Fabricの立ち上がりには、それなりに時間がかかります。大体4〜5分を見ておけばいいかと。

### 最初の Service をJavaで作ってみる ###
それでは、初めての Service を作っていってみます。今回はあくまでサンプルなのと、私が個人的に Eclipse をあんまり使いたくないので、全部 CUI からやっていきます。

といっても、 実際は [公式ガイド](https://azure.microsoft.com/ja-jp/documentation/articles/service-fabric-create-your-first-linux-application-with-java/) の内容とほとんど変わらないのですが。

まずはテンプレートから、基本形を作成します。なんでか知りませんが、 Yeoman が利用されています。

```bash
$ yo azuresfjava
```

![2.png](https://qiita-image-store.s3.amazonaws.com/0/12490/0edcb7e5-3b6b-7334-15bf-3ed526d37267.png "2.png")


生成されたファイルを見るとわかりますが、ビルドシステムは Gradle でした。が、 gradle-wrapper を設定してくれていません…。Linux ユーザーはGradleくらい入ってるだろ？ってことでしょうか。

Service Fabric の Java SDK をインストールした時点で、gradle自体は入ります。今回は Vagrant 上に環境を構築していますが、実際にはgradleが無い環境で開発することもあると思いますので、gradle-wrapper の設定を追加しておきます。

```bash
$ cd first_service/myapp
$ gradle wrapper --gradle-version 2.14.1
```

後は、gradle/ ディレクトリをコミットすればOKです。

    テンプレートですが、実際には4つ（一つは全体をまとめるためのproject）の gradle プロジェクトが出来ます。ここでは

    * myapp = アプリケーション
    * myactorservice = サービス
    * myactorserviceTestClient = テスト用のクライアント

    となっているようです。

ビルド自体は、gradlew を実行するだけです。

```bash
$ ./gradlew
```

とりあえず、テンプレートそのまんまではありますが、これをVagrant上のService Fabricにデプロイします。公式ガイドでは、ここでコマンド名が違うようです。

```bash
$ azure servicefabric cluster connect
$ cd /vagrant/first_service/myapp
$ ./install.sh
```

デプロイが終わると、こんな感じになります。3つのノードに分散していて、Node1がプライマリだ、というのがわかります。

![3.png](https://qiita-image-store.s3.amazonaws.com/0/12490/55c3578e-a9f8-356d-a5a1-4e0477853baf.png "3.png")


公式にしたがって、フェールオーバーを体験してみます。

```bash
cd /vagrant/myapp/myactorserviceTestClient
watch -n 1 ./testclient.sh
```

これを実行した状態で、上の画像にある **Primary** のノードを止めたり開始したりしてみます。（System欄のサービス自体がシングルトンになっているのが要因かもしれませんが、restartは選択してもうまく行かないようでした）
やってみるとわかりますが、このサンプルは Stateful なサービスのようで、プライマリを止めてもちゃんとカウントアップし続けます。ただし、フェールオーバーを行うためだと思いますが、1〜2秒程カウントアップは止まるようです。

今回やった内容はこちらです。

https://github.com/derui/fabric-java

### おまけ：CLIからサービスを更新してみる ###
さて、テンプレートからやってみましたが、このテンプレートはやっぱり基礎でしかありません。

その証拠？として

* インストール/アップデートしかできない
* バージョンがベタ書き

などがあります。あくまで動作を学ぶっていう意味であればいいと思うんですが、とりあえず更新くらいはしたいですよね。しかし、公式ではJava/Azure CLI のことが書いてあるのはこの辺までで、後はPowerShellについてばっかりです。

とりあえずやってみようということで、テンプレートの以下の部分を書き換えます。myapp とか myactorservice とかは、自分のアプリケーションとサービス名で置き換えれば、他の名前でもOKです。

* myapp/ApplicationManifest.xml の `ApplicaitonManifest@ApplicationTypeVersion` を **1.0.1** に
* myapp/myactorservicePkg/ServiceManifest.xml 内の各 `Version` 属性を **1.0.1** に

そして、以下のコマンドを実行します。

```bash
azure servicefabric application package copy myapp fabric:ImageStore
azure servicefabric application type register myapp
azure servicefabric application upgrade start --application-name 'fabric:/myapp' --target-application-type-version 1.0.1 --rolling-upgrade-mode Monitored
```

成功すると、こんな感じに進むのが確認できます。

![4.png](https://qiita-image-store.s3.amazonaws.com/0/12490/6b44c7cd-e07f-bd24-ab1e-291608dcee03.png "4.png")

実際には、各サービスのManifest.xmlはそれぞれで管理すべきですし、アプリケーションのバージョンも外部から設定できるような仕組みを用意すべきでしょう。が、とりあえずはできるってことは確認できました。

## まとめ ##
よりよいテンプレートが欲しいです。Microsoft的には C# 最強なのはわかりますし、正直私もPure Javaにはそんなに魅力を感じていないですけど。（ぉぃ

ただ、それでもJVMが使えるということは、JVM上で動作する他の言語を利用できるということなので、それらを使うための第一歩になるのでは無いかと思います。

今回は開発用のローカルクラスタでしたが、次回は実際にAzure上のService Fabric を作成して、その上でJava製サービスを動かしてみたいと思います。