RancherとGiddyup

[giddyup]:https://github.com/rancher/giddyup
この記事は[Rancher Advent Calendar 2017](https://adventar.org/calendars/2436)の12/10の記事です。  

12/3に[confdについて](https://qiita.com/m-daichang/items/d4e135b53b984cd414ef)書きましたが(時間がなくて尻切れとんぼになったので後で補習記事書きます...)、Rancherでconfdを使用する場合、あくまでoutputはconfファイルのみ。コンテナの起動時にサービスの状態を取得して直接シェルスクリプトで制御したい場合もあります。そういった場合に使用するのがこれから紹介する[Giddyup][giddyup]です。

Giddyupってなに？
===
[Giddyup]はRancherのサービスを構成する際に補助となるツールです。Goで書かれています。
こいつの存在を知ったのは、MongoDBカタログの特集記事を読んだ時です。
[Building a MongoDB Catalog Item for Rancher](http://rancher.com/building-a-mongodb-catalog-item-for-rancher/)

興味があって調べていくとDockerfileにgiddyupの存在が確認できます。
https://github.com/rancher/catalog-dockerfiles/blob/master/MongoDB/containers/0.1.0/mongodb-config/Dockerfile#L7

```
curl -L https://github.com/cloudnautique/giddyup/releases/download/v0.14.0/giddyup -o /opt/rancher/bin/giddyup
```

MongoDBので使用しているバージョンは[Bill](https://github.com/cloudnautique)がforkしたバージョンですがRancherの中の人なので公式と言って差し支えないかと。すでに本体に取り込まれて本体の方がバージョンが高いみたいですね。

(寄り道)MongoDBカタログについて
===
community-catalogのMongoDBのすごいところは `サービス1つで以下構成を形成している` 点です。

- primary 
- secondary
- secondary

つまり、通常サービス内のコンテナをscaleしても同じ動きしかしないところを、複数の状態を持っているし、サービス内のコンテナ同士で連携もしているのです。  

<img width="400" alt="MongoDBスタック.png" src="https://qiita-image-store.s3.amazonaws.com/0/153776/5897b676-3782-e0d6-3780-72d092560ce1.png">

Giddyupを使ってみる
===
話しが脇道にそれました。では実際にgiddyupを使ってみましょう。

### dockerイメージの準備
テスト用にcentosのイメージをベースにこんなDockerfileを書きました。

```
FROM centos:7

RUN curl -L https://github.com/rancher/giddyup/releases/download/v0.19.0/giddyup -o /giddyup \
    && chmod u+x /giddyup
```

この辺に置いておきますので使いたい方はどうぞ
https://hub.docker.com/r/mdaichang/giddyup-sample/

### Rancherでスタックを作成
んで、テスト用にこんな感じでスタックを作成してみました(画面はサービスですが)。
<img width="500" alt="giddyup-sample_stack.png" src="https://qiita-image-store.s3.amazonaws.com/0/153776/fd58d3bc-78d2-4150-bdd7-3eda2b450913.png">
簡単にカタログ作ってますのでrancher-compose.yml/docker-compose.ymlが欲しいかたはこちらをどうぞ。
https://github.com/m-daichang/rancher-catalog/tree/master/templates/giddyup-sample/0
(もちろんリポジトリごとPrivate Catalogに登録してそこから作成もできます。)

### giddyupのテスト
コンテナに入って早速giddyupを叩いてみましょう。

```shell-session:giddyup実行
[root@giddyup-sample-giddyup-sample-1 /]# /giddyup
NAME:
   giddyup - Entrypoint functions for Rancher

USAGE:
   giddyup [global options] command [command options] [arguments...]

VERSION:
   v0.19.0

COMMANDS:
     exec     exec out to a command
     health   simple healthcheck
     ip       Get IP information
     leader   Provides a deterministic way to elect, route traffic, and get a le
ader of a service
     probe    Probe a TCP/HTTP(S) endpoint to determine if it is healthy
     service  Service actions
     help, h  Shows a list of commands or help for one command

GLOBAL OPTIONS:
   --metadata-url value  override default MetadataURL (default:"http://rancher-metadata/2015-12-19")
   --help, -h            show help
   --version, -v         print the version
```

お約束のヘルプ情報です。

### 自分のIPを取得する
`giddyup ip myip`だと自分のIPが取得できます。コンテナだと`ip`や`ifconfig`すら入っていないことが多いため割と便利です。

```shell-session:自分のIPを取得
[root@giddyup-sample-giddyup-sample-1 /]# /giddyup ip myip
10.42.49.154
```

### サービスの全IPを取得する
`giddyup ip stringify`だとサービス内のコンテナの全IPが文字列として取得できます。初期値はカンマ区切りですが、`--delimiter`オプションを使うと区切り文字が指定できます。後はシェルスクリプト内で好きなように加工してしてください。

```shell-session:区切り文字を指定しない場合
[root@giddyup-sample-giddyup-sample-1 /]# /giddyup ip stringify
10.42.235.205,10.42.134.189,10.42.208.134
```

```shell-session:区切り文字を指定した場合(スペースを指定)
[root@giddyup-sample-giddyup-sample-1 /]# /giddyup ip stringify --delimiter " "
10.42.235.205 10.42.134.189 10.42.208.134
```

### 自分がリーダーかどうかチェックする
自分がリーダー(サービス内で管理用idが一番小さい)かどうかチェックすることができます。これによりprimary/secondaryの制御が可能になります。終了コードで判断するので注意。

- リーダー: 0
- リーダー以外: 1

```shell-session:リーダーの場合
[root@giddyup-sample-giddyup-sample-1 /]# /giddyup leader check; echo $?
0
```

```shell-session:リーダー以外の場合
[root@giddyup-sample-giddyup-sample-3 /]# /giddyup leader check; echo $?
1
```

ちなみにリーダーコンテナが障害等でいなくなった場合、自動的にリーダーが変わります。
試しにリーダーのコンテナをdeleteしてみましょう。

<img width="600" alt="スクリーンショット 2017-12-10 21.34.24.png" src="https://qiita-image-store.s3.amazonaws.com/0/153776/a03c9521-bd81-78b9-e428-8cad020eced6.png">

すると2号機(giddyup-sample-giddyup-sample-2)にリーダーが変わります。

```shell-session:2号機にリーダーが移りました
[root@giddyup-sample-giddyup-sample-2 /]# /giddyup leader check; echo $?
0
```

その後元リーダーの1号機(giddyup-sample-giddyup-sample-1)は復旧しますが、リーダー以外のままです。

```shell-session:復旧した1号機でリーダーチェックした結果
[root@giddyup-sample-giddyup-sample-1 /]# /giddyup leader check; echo $?
1
```

これで例えばsecondaryがprimaryに昇格した後に、元primaryが復活しても移動したprimaryと喧嘩したりしなくなるわけですね。

### サービスのscale数を確認する
`giddyup service scale --current`を使うと現在のscale数が取得できます。

```shell-session:サービスのscale数を取得
[root@giddyup-sample-giddyup-sample-1 /]# /giddyup service scale --current
3
```

### サービスが設定した数が起動するまで待つ
`giddyup service wait`を使うと設定したscale数になるまでプロンプトが返ってきません。何に使うかというと、replicationする時などに全コンテナが起動する必要がある場合などに使用します。`--timeout`オプションを使用すると設定した秒数まで最大待ちます。

ちょっとscale数を3 -> 5に増やしてみましょう。
<img width="293" alt="スクリーンショット 2017-12-10 22.18.12.png" src="https://qiita-image-store.s3.amazonaws.com/0/153776/0aeef4c2-a2b1-edc0-af04-6c82993cdbe9.png">

すると、ちゃんとコンテナが起動するまで待ちます。使用したイメージがすでにpull済みなのでscalingに時間がかからず、わかりづらいですが...

```shell-session:scalingしてない時(0.007s)
[root@giddyup-sample-giddyup-sample-1 /]# time /giddyup service wait scale --timeout 120

real    0m0.007s
user    0m0.000s
sys     0m0.000s
```

```shell-session:scaling中に実行した場合(2.370s)
[root@giddyup-sample-giddyup-sample-1 /]# time /giddyup service wait scale --timeout 120

real    0m2.370s
user    0m0.010s
sys     0m0.000s
```

まとめ
===
他にも簡易healthcheckとかいろいろできるみたいなのですが、一旦この辺で。giddyupを使用するとサービスの状態とか自分がリーダーかどうか確認することができ、これを上手くentorypointに組み込めばステートフルなサービスもCatalogで組むことができそうです。皆さんも是非試してみてください。