tsuruの紹介とtsuru-nowを使った簡単な導入方法

こんにちは、 [@hico_horiuchi](https://twitter.com/hico_horiuchi) です。
この記事は [NTTコミュニケーションズ Advent Calendar 2017](https://qiita.com/advent-calendar/2017/nttcom) の1日目です。

普段は [Enterprise Cloud 2.0](https://ecl.ntt.com) のベアメタルサーバメニューの開発をしていますが、
今回は来週末開催予定のハッカソンのためにPaaSを構築してみたので、その紹介をします。

## tsuruとは?

[tsuru](https://github.com/tsuru/tsuru) ( :star: 2.6k) は [Docker](https://www.docker.com) をベースにしたオープンソースのPaaS(Open PaaS)です。
ブラジル最大の放送局である [globo.com](http://www.globo.com/) が中心となって、Go言語で開発されています。
Open PaaSには他にもありますが、Flynnと悩んだ末、今回はtsuruを採用しました。
(参考: [Best Platform as a Service Software - 2017 Reviews of the | StackShare](https://stackshare.io/platform-as-a-service) )

- [Dokku](https://github.com/dokku/dokku) ( :star: 14.6k)
    - Minimalだが、その分Node追加/ユーザー管理などの機能が不足している。
- [Flynn](https://github.com/flynn/flynn) ( :star: 6.4k)
    - 今回の用途にはオーバースペックで、構築が少し難しい。
- [Deis](https://github.com/deis/deis) ( :star: 6.1k)
    - Microsoftに買収され、OSSとしてのメンテナンスが終了してしまった。
- [OpenShift](https://github.com/openshift/origin) ( :star: 3.7k)
    - Kubernetesのノウハウが無く、構築・運用が難しい。

## tsuruの用語とコンポーネント

### アーキテクチャ

**2017/12/09 アーキテクチャの図を追加しました。**

![tsuru_archtecture.png](https://qiita-image-store.s3.amazonaws.com/0/58742/496097d1-9a23-3642-882e-e4331031dd38.png)

### 用語

[Concepts](https://docs.tsuru.io/stable/understanding/concepts.html) より。

- Cluster
    - Nodeの集り、この中でUnitが分散される。
        - [Segregate Scheduler](https://docs.tsuru.io/stable/managing/segregate-scheduler.html)
- Node
    - Unitが動作するDockerホスト。
    - EC2などのIaaS上でオートスケール可能。
        - [Node Auto Scaling](https://docs.tsuru.io/stable/advanced_topics/node_scaling.html)
- Application
    - Unit上で動作するアプリケーション。
    - パッケージやライブラリの依存情報と `Procfile` を含む。
- Unit
    - アプリケーションが動作するDockerコンテナ。
    - デプロイ時にDockerイメージがビルドされる。
- Platform
    - 各言語のランタイムを含んだDockerイメージ。
    - PlatformをベースにUnitのDockerイメージがビルドされる。
    - Node.jsやRubyだけでなく、Buildpackにも対応している。
        - [tsuru/platforms](https://github.com/tsuru/platforms)
- Service
    - Application向けのミドルウェアを提供する機能。

### コンポーネント

[Architecture](https://docs.tsuru.io/stable/understanding/architecture.html) より、全てGo言語で開発さています。

- [tsuru/tsuru](https://github.com/tsuru/tsuru)
    - `tsurud` と呼ばれるRESTful APIサーバ。
    - データベースに[MongoDB](https://www.mongodb.com)を使用している。
    - [API reference](https://docs.tsuru.io/stable/reference/api.html)
- [tsuru/gandalf](https://github.com/tsuru/gandalf)
    - Gitリポジトリを管理するRESTful APIサーバ。
    - ユーザーの作成、公開鍵の登録、リポジトリの作成など。
- [tsuru/planb](https://github.com/tsuru/planb)
    - [Hipache](https://github.com/hipache/hipache)インスパイアのHTTPプロキシサーバ。
    - バックエンドに[Redis](https://redis.io)を使用している。
    - アプリケーションへのアクセスをUnitに転送している。

## tsuru-nowを使ったインストール

**2017/12/09 tsuru-nowをベースに [tsuru-ansible](https://github.com/hico-horiuchi/tsuru-ansible) を作りました。**

では、実際にtsuruをインストールしてみます。
インストール方法は主に種類ありますが、今回はtsuru-nowを使います。

* [Installing](https://docs.tsuru.io/stable/installing/index.html) を読んで手動インストール
* [tsuru-now](https://github.com/tsuru/now) でAll-in-oneインストール
* [tsuru-bootstrap](https://github.com/tsuru/tsuru-bootstrap) でVagrantで起動
* [tsuru-installer](https://docs.tsuru.io/stable/experimental/installer.html#installer) でdocker-composeで起動 (開発中)

今回はConoHa 2GBプランの仮想サーバ上のUbuntu 16.04にインストールします。
基本的に、サーバにログインして下記のコマンドを実行するだけで環境が出来上がります。

`--host-name` でドメイン名を指定していますが、標準では `{ip address}.nip.io` が設定されます。
(ドメイン名を指定する場合は、DNSで `*.example.com` のようにワイルドカードも設定する必要があります。)
[tsuru-dashboard](https://github.com/tsuru/tsuru-dashboard) は使わないので除外しています。

```
$ curl -sL https://raw.github.com/tsuru/now/master/run.bash -o run.bash
$ LANG=C bash ./run.bash --host-name example.com --without-dashboard
```

手元のMacなどで [tsuru/tsuru-client](https://github.com/tsuru/tsuru-client/releases) をダウンードしておきます。
管理ユーザ( `admin@example.com` )でログインして、パスワードを変えておきます。
初期パスワードはインストールの最後にも表示されますが `admin123` のはずです。

```
$ tsuru target-add default http://example.com:8080 -s
$ tsuru login
$ tsuru change-password
```

## プラットフォームの追加

後程JavaScriptのサンプルアプリケーションを動作させるので、Node.jsのプラットフォームを追加しておきます。

```
$ tsuru platform-add nodejs
```

## パーミッションとチームの設定

tsuruでは [Managing users and permissions](https://docs.tsuru.io/stable/managing/users-and-permissions.html) の通り、細かく権限を管理することができます。

### デフォルト設定の確認

`Roles` の詳細は `tsuru role-list` で確認できます。

- ユーザを作成するとチームの作成権限が付与される。
- チームを作成するとチームメンバの権限が付与される。
    - チームメンバになるとアプリケーションの作成権限が付与される。

```
$  tsuru role-default-list
+-------------+-----------------------------------------------+-------------+
| Event       | Description                                   | Roles       |
+-------------+-----------------------------------------------+-------------+
| team-create | role added to user when a new team is created | team-member |
+-------------+-----------------------------------------------+-------------+
| user-create | role added to user when user is created       | team-create |
+-------------+-----------------------------------------------+-------------+
```

### ハッカソン用のチーム作成・権限の制限

ハッカソン用の `hackathon` チームを作成します。
ただし、ユーザには他のチームを作成して欲しくないので、
ユーザ作成時にデフォルトで権限が付与されないように修正します。

```
$ tsuru team-create hackathon
$ tsuru role-default-remove --user-create team-create
```

### ユーザーの作成とロールのアサイン

ユーザーを作成して、 `hackathon` チームの権限をアサインします。
これで、このユーザーは `hackathon` チームでアプリケーションを作成できます。
(tsuruではアプリケーションはユーザーではなくチームに紐付きます。)

```
$ tsuru user-create user@example.com
$ tsuru role-assign team-member user@example.com hackathon
```

## アプリケーションのデプロイ

最後に、実際にtsuruにアプリケーションをデプロイして動作確認します。
管理ユーザをログアウトし、`user@example.com` でログインし直します。

```
$ tsuru logout
$ tsuru login
$ tsuru user-info
```

GitリポジトリにSSHでpushするための公開鍵を登録します。

```
$ tsuru key-add default ~/.ssh/id_rsa.pub
```

今回はサンプルとして [heroku/node-js-sample](https://github.com/heroku/node-js-sample) をデプロイします。
tsuruでアプリケーションを作成するとリポジトリのアドレスが得られます。

```
$ git clone git@github.com:heroku/node-js-sample.git
$ cd node-js-sample
$ tsuru app-create node-js-sample nodejs
$ git remote add tsuru git@example.com:node-js-sample.git
```

`git push` でソースコードをアップロードすると、デプロイが始まります。
Dockerイメージのビルドが成功すると、Dockerコンテナが起動します。
( `tsuru app-info` でUnitのStatusがstartingになっていれば :ok_hand: です。)

```
$ git push tsuru master
...
remote: ---- Pulling image to node ----
remote: latest: Pulling from tsuru/nodejs
remote: Digest: sha256:e00eafac96ce34028f33277ad4c84ce51e8dc2eb9552bf58cb05ddb775af1ced
remote: Status: Image is up to date for 127.0.0.1:5000/tsuru/nodejs:latest
remote: Downloading and installing node v4.0.0...
...
remote: ---- Setting router healthcheck (Path: /) ----
remote: 
remote: OK
$ tsuru app-info
...
+--------------+----------+-----------+-------+
| Unit         | Status   | Host      | Port  |
+--------------+----------+-----------+-------+
| 7ff44d20c1d2 | starting | 127.0.0.1 | 32868 |
+--------------+----------+-----------+-------+
...
```

http://node-js-sample.example.com にアクセスすると「Hello World!」と表示されるはずです!
`tsuru app-log` でログを確認したり、 `tsuru app-shell` で実行中のコンテナに
ログインできたりするので、デバッグの際は使ってみてください。

## その他

MongoDBの中を覗いてみました、データ構造はシンプルな印象です。

```
$ mongo tsurudb
> show collections
apps
builder_app_image
docker_containers
...
> db.teams.find()
{ "_id" : "admin", "creatinguser" : "admin@example.com" }
{ "_id" : "hackathon", "creatinguser" : "admin@example.com" }
```

Redisの中も覗いてみました、URLと転送先が保存されていますね。

```
127.0.0.1:6379> keys *
1) "frontend:ruby-sample.example.com"
2) "healthcheck:ruby-sample.example.com"
127.0.0.1:6379> lrange frontend:ruby-sample.example.com 0 -1
1) "ruby-sample"
2) "http://127.0.0.1:32868"
```

## 参考文献

本記事の作成に当たり、下記のページを参考にさせて頂きました。

- [DockerでオープンソースPaaS - Part3: tsuruインストール | masato's blog](http://masato.github.io/2014/07/04/docker-opensource-paas-tsuru-install/)
- [tsuru でプライベート PaaS を構築し操作してみるメモ - Qiita](https://qiita.com/rerofumi/items/cc56abe6e43b95f75320)