[Docker] Kitematicを使ってみよう！

みなさまこんにちは。[Docker2 Advent Calendar 2016](http://qiita.com/advent-calendar/2016/docker2) の9日目に参加させていただいております @akiko_pusu です。
が！
日付が変わってしまってからの投稿で申し訳ございません...。
さらに、Dockerについてはたくさん語れる立場ではないのですが、とにかく **Kitematic** についてご紹介したいと思います。

内容的にはDockerそのものよりも、Dockerを利用したアプリケーション寄りになってしまいますが、ご容赦くださいませ。

なお、12/8 は @okamu_ さまの [【Docker】もう悩まない！MySQLのフェイルオーバーをdocker-composeで爆速構築](http://qiita.com/okamu_/items/6ab5269662bfeda4875b) でした。
また、12/10 は @mekemo_dao さまの[ElasticBeanstalk Multi-Container Dockerで本番運用したいンゴ](http://qiita.com/mekemo_dao/items/dca7c2429869ea9d8693) です。こちらもどうぞ宜しくお願いいたします！

## Kitematicってなに？

Kitematicとは、こちらの記事でも少し触れましたが、Docker Toolbox についてくる、GUIのDocker操作用のツールです。

- [Mac版 Docker Toolbox を使ってみました](http://qiita.com/akiko-pusu/items/a30db6332a77ed0ded09)
- https://kitematic.com （公式サイト）
- https://docs.docker.com/kitematic/userguide/ （ユーザガイド）

### 発音は？

あまり自信がありませんが、[紹介用の動画](https://www.youtube.com/watch?v=QEr340gjV1Q)を見る限り「かいとまてぃっく」と呼ぶようです。

### 使い方は？

KitematicはDocker Toolboxの一部として提供されています。
アイコンをクリックすると、こんな感じで立ち上がります。

- アプリケーション起動時に、Dockerのデーモンが立ち上がっているか確認
 - Macの場合はネイティブのDocker for Macが動いていればMac自身をDockerのホストとして利用
- ネイティブのDockerデーモンが上がっていなかった場合
 - VMWare上にboot2dockerというDocker専用のVMを作り、そこでDockerサービスを開始
 - 接続先をboot2dockerとして利用

![kitematic-and-docker-for-mac.png](https://qiita-image-store.s3.amazonaws.com/0/27976/6906ccd9-16d7-060c-aa2b-5df563f9c642.png "kitematic-and-docker-for-mac.png")

（なお、初回起動時には、DockerHubへのサインイン・サインアップ画面が出ますが、こちらは特になにもしなくても利用可能です！）

Dockerが利用できる状態になると、画面右側にはDockerHubで提供されている人気のイメージが表示されます。試しに気に入ったものをダブルクリックしたり、検索して簡単に好きなイメージを追加、コンテナを起動することができます。 

一旦作成されて起動したコンテナについては、こんなことができます。

- Start / Stop
- WebアプリケーションでportがExposeされている、コンテナとホスト間のポートフォワードの設定もされている場合は、プレビュー画面が出てくる
- 名前を変更できる
- 必要に応じてポートフォワードの対象のポートを追加変更できる

### 助かっている点

コンテナ起動の際に、上げっぱなしでいつのまにかたくさんコンテナが起動していた...という場合にも、画面で一目で分かります。
また、個人的に間違いやすいポートの設定（コンテナのポートをホストにマップする）も、画面上の設定を見ながら確認できます。

場合によっては、GUIから起動中のコンテナの中に入ったりして、動作を確認することもできます。
（とは言っても、コンテナはサイズを小さくするためエディタが入っていない場合がありますので、中に入ってソースを編集することが出来ないケースや、moreはあるけどlessは無い、といった残念なケースもあります。ソース確認くらいはできるとして...） 

![exec-and-result.png](https://qiita-image-store.s3.amazonaws.com/0/27976/e0ed5096-f494-4295-96e1-6e5cd30b1c9c.png "exec-and-result.png")

以下のようなことも、GUIで設定変更、適用ができます。

- portの変更（フォワード用のポートの変更）
- 環境変数の設定
- ホストとコンテナでシェアするボリュームの設定


## なにでできているの？

さて、Kitematicは、Electronをベースにしたアプリケーションです。
このため、簡単にソースを参照したり、手元でカスタマイズ＆起動することができます。（と、偉そうなことをいいましたが、私はまだなにも出来ません...）
せっかくなので、ソースの中身や動きについてもさらっと触れることにします。

## Kitematicのリポジトリをのぞいてみよう！

Kitematicのリポジトリはこちらになります。

- https://github.com/docker/kitematic.git 

README側にはインストールの手順と、簡単な紹介、ドキュメントや公式サイトへのリンクが記載されています。

KitematicというElectronベースのアプリケーションそのものに興味がある場合は、 [CONTRIBUTING.md](https://github.com/docker/kitematic/blob/master/CONTRIBUTING.md) をご覧いただくと、ビルドやテストの方法について詳しく触れられていますので、ぜひそちらをどうぞ！

また、ここから先はビルド関連になってきますのでご容赦ください。

## buildしてみよう！

CONTRIBUTING.mdにも書かれていますが、node.jsが入っていれば基本的にビルドできる状態になっていますので、今回はソースをcloneしてきて、VSCodeで開いてみました。（VSCodeもElectronベースです）

package.jsonやGruntfile.jsといったファイルがあるので、ターミナルからのbuildも出来ますが、VSCodeの場合は「コマンドパレット」から、npm と入力すると、利用できるタスクの候補が表示されます。

![build-with-vscode.png](https://qiita-image-store.s3.amazonaws.com/0/27976/1d9a2308-9d81-fe82-caf3-60dc7836dbc2.png "build-with-vscode.png")


さっくりbuild & 動かしてみたいという場合には、npm start を選ぶと、Electronのアイコンが表示されて、Kitematicのアプリケーションが立ち上がります。

Gruntfile.js に従ってGruntのタスクを動かしたい場合は、npm install -g grunt でgruntを追加してからタスク起動になります。

![grunt.png](https://qiita-image-store.s3.amazonaws.com/0/27976/56907319-1173-2573-c2a9-03821f6707b0.png "grunt.png")


実際にソースを少しいじってみると、ちゃんと変更されることがわかります。
（こちらは単純にフォントを変えた例ですが....）

![customize-sample.png](https://qiita-image-store.s3.amazonaws.com/0/27976/270541af-8b23-8955-fa9f-f19d53319569.png "customize-sample.png")


## もうちょっと詳しくみてみよう

### どうやって描画してるの？

Electronアプリなので、ソースはHTMLがわかればなんとなく理解できそう、とは言うものの、とくにコンテナのアプリケーションのプレビューなどはどんなふうに実現しているんだろう...？

ざっと作りを眺めて見たい場合は、画面上部のメニューから、「Chrome Developer Tool」を起動すると、パネル上の要素に対応するソースが把握できます。（ブラウザのChromeのDeveloper Toolと同じです）

たしかに、HTML, JavaScript, CSSといったWebの技術で構成されているのが分かりますね。
大部分の動的な情報は、Dockerのホスト側からAPI経由で取得し、それに基づいて画面が構成されています。

ただし、一箇所、Webアプリケーションのコンテナの場合はプレビューの画面も表示されるのですが、DockerのAPIにはそんな画像を飛ばすものなんて無いので、「どうやっているんだろう？」と気になっていたのですが、よくよく見るとWebviewを使ってはめ込んでいるんですね。

![using-webview.png](https://qiita-image-store.s3.amazonaws.com/0/27976/644adf6d-6488-36c8-2af5-90d6d41ddfda.png "using-webview.png")

一方で、「Container Logs」（コンテナのログ）に関しては、WebViewではなくDockerのAPIのlogsを叩いて描画させています。

### どんなふうにDockerコンテナとお話ししてるの？

上記の通り、KitematicはDocker APIを使って画面を構成しています。

残念ながらこの通信についてはDeveloper ToolのNetworkタブでは見ることができません。
ですが、APIには変わりありませんので、こちらも（脱線しますが）ちょっと触れてみます。

## Docker APIを試してみよう

Docker APIは、同一ホスト内であればUnixドメインソケットを通して提供することができますが、外部とのやりとりが必要になる場合はtcp (http/https) を利用する形になります。

### Unix Domain Socketの場合

MacOSで Docker for Macを使ってDockerの環境を利用する場合は、Mac内のdockerコマンド・KitematicはUnixドメインSocketでの通信になります。（/var/run/docker.sock）
実際に、起動中のコンテナに対して、ログを取得するAPIを叩く場合は、以下のようなコマンドになります。

```
$ curl --unix-socket /var/run/docker.sock "http:/containers/b1a7d599d/logs?follow=true&stderr=true&stdout=true&timestamps=true"

# こちらもAPIを叩いている感じになります
$ docker logs b1a7d59

# 出力例（DockerコンテナのWebの画面にアクセスすると、コンテナで起動中のnginxの出力がログとして表示される）
2016-12-09T15:40:43.976694996Z INFO[10650] 172.17.0.1 - - [12/Dec/91243:12:12:12 -1600]  GET "/index.html" HTTP/1.1 200 8056 
2016-12-09T15:40:44.037363718Z INFO[10650] 172.17.0.1 - - [12/Dec/91244:12:12:12 -1600]  GET "/fonts/droid.woff2" HTTP/1.1 200 11304 
2016-12-09T15:40:44.040806479Z INFO[10650] 172.17.0.1 - - [12/Dec/91244:12:12:12 -1600]  GET "/fonts/droid-bold.woff2" HTTP/1.1 200 11480 
2016-12-09T15:41:31.727200261Z INFO[10698] 172.17.0.1 - - [12/Dec/91231:12:12:12 -1600]  GET "/index.html" HTTP/1.1 200 8056 
2016-12-09T15:41:31.818593237Z INFO[10698] 172.17.0.1 - - [12/Dec/91231:12:12:12 -1600]  GET "/fonts/droid.woff2" HTTP/1.1 200 11304 
2016-12-09T15:41:31.818766633Z INFO[10698] 172.17.0.1 - - [12/Dec/91231:12:12:12 -1600]  GET "/fonts/droid-bold.woff2" HTTP/1.1 200 11480 
```

socketの場合だと、通信のキャプチャの方法がよく分からない...。
ということで、boot2dockerを利用してKitematicとDockerホストのtcpでのAPI通信を眺めてみることにしました。

### Docker APIとKitematicの通信は？

Docker for Macを利用していても、そちらを停止して、boot2docker側を利用することができますので、まずは以下の通りDockerを切り替えます。このあたりはKitematicを含むDocker Toolboxをダウンロードすると一緒に必要なものが付いてきます。
また、Kitematicを初回起動した場合は、MacOSのネイティブのDockerが上がっていなければ、boot2dockerを利用してVMを立ち上げる処理が進みます。

- boot2docker: VirtualBoxにLinuxベースのboot2dockerのマシンを追加
 - この中でDockerのデーモンを起動
 - 今回の例では、IPは192.168.99.100 を割り当て

うまくboot2dockerでのDockerデーモンが上がったとしまして。

まずは [Docker Remote API](https://docs.docker.com/engine/reference/api/docker_remote_api/)のドキュメントに従って、APIがちゃんと反応するか確認してみます。
Docker APIのデフォルトポートは2376なので、そちらに対してリクエストを投げてみます。

```
# jsonデータが返るが、たくさんあるので一部のみパースして表示

$ /usr/local/bin/curl -s --insecure --cert $DOCKER_CERT_PATH/cert.pem --key $DOCKER_CERT_PATH/key.pem \
   https://192.168.99.100:2376/containers/json | jq '.[].Names[]'

"/hello-world-nginx"

```

こんな感じで、現在起動しているコンテナの情報が取れました。

### tcpdump してみたら？

Docker APIのデフォルトのポートは2376なので、tcpdumpで通信を拾ってみるとこんな感じです。
Kitematicからコンテナの情報を取得したり、起動・保存を実行するとパケットが流れます。
あまりこの辺深掘りできなくて申し訳ないのですが、KitematicのGUIからコンテナの設定を保存したり、start / stop すると確かに通信が流れるのが確認できます。

```
$ sudo tcpdump port 2376 and host 192.168.99.100 
tcpdump: data link type PKTAP
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on pktap, link-type PKTAP (Apple DLT_PKTAP), capture size 262144 bytes
09:07:52.301770 IP 192.168.99.100.2376 > 192.168.99.1.57608: Flags [S.], seq 34968944, ack 3475486455, win 28960, options [mss 1460,sackOK,TS val 406920 ecr 1142976386,nop,wscale 7], length 0
09:07:52.302279 IP 192.168.99.100.2376 > 192.168.99.1.57608: Flags [.], ack 1449, win 249, options [nop,nop,TS val 406920 ecr 1142976387], length 0
......
```

Wiresharkをつかうとこんな感じです。

![with-wireshark.png](https://qiita-image-store.s3.amazonaws.com/0/27976/93ac842e-4ff0-0618-68cc-db9d5777dc1a.png "with-wireshark.png")

でも、思ってたのと違う...。
そうです、通信が暗号化されているため、TCPのやりとりの流れは追えても、実際どんなプロトコルでどんなデータがやりとりされているのかが見えません... ><
そこまでこだわらなくとも...と思いつつ、せっかくなのでやっぱりtcpdump (or Wireshark)で通信を覗いてみたい！
ということで、調整をしてみました。
(Wiresharkで暗号化された通信を鍵を使って復号化する方法もあるみたいですが、よくわからなかったのでパス）

**1. boot2docker側のAPIを暗号化なしにする**

Docker for Macでもsocket以外にtcpでの通信を受けられるようにできそうかな...とも思ったのですが、うまく行かなかったのでこちらの方法でで。

- ssh でboot2dockerのVMにログインする
- vi /var/lib/boot2docker/profile で設定を編集
 - DOCKER_HOST='-H tcp://0.0.0.0:2375'  # port 2357に変更
 - DOCKER_TLS=no # TLSなしにする
- 保存をして、/etc/init.d/docker restart で再起動

※あまりオススメではないのですが、閉じた環境なのでこのようにしました....。　　　　　　　　　　　　　

**2. Kitematicのソースを修正してhttp:2375で通信させる**

一方のKitematicですが、基本はUnix Socketかhttps://2376/ でAPIと通信するようにソース中に定義されています。
そのまま起動しても、https://2376/ に問い合わせに行ってしまうため、うまくいきません。

ということで、ソースを調整できる環境を利用して、設定を変更してbuild, 起動させてみました。

```source:DockerUtil.js
      this.client = new dockerode({
        protocol: 'http', // httpsだった
        host: ip,
        port: 2375,       // 2376だった
        ca: fs.readFileSync(path.join(certDir, 'ca.pem')),
        cert: fs.readFileSync(path.join(certDir, 'cert.pem')),
        key: fs.readFileSync(path.join(certDir, 'key.pem'))
      });
```

さて、立ち上がったKitematicをポチポチクリックしてみると、ちゃんとhttpで通信しており、通信の中身もWiresharkで確認することができました。

![change-after-http.png](https://qiita-image-store.s3.amazonaws.com/0/27976/ba8c3ba4-39f3-45b6-e3cd-e69d1f61068c.png "change-after-http.png")


こういう時って、ソースを調整できるのって良いなあ...と思います。


### 補足：Kitematicでの設定箇所

Kitematicは、Dockerのデーモンがどんな感じで上がっているかをチェックして、APIの宛先をsocketもしくはhttp（https) に切り替えています。
その辺は、[DockerUtil.js](https://github.com/docker/kitematic/blob/master/src/utils/DockerUtil.js) あたりで確認できます。Docker APIに対応するアクションが概ねこちらに定義されている感じです。

## まとめ

以上、つらつらと、気がつけば興味にひきずられるままに書いてしまって申し訳ございません。
脱線を挟みながらも、こんな点について触れています。

- Kitematicについて 
- Kitematicをソースから起動する
- Docker APIとKitematicの通信を眺める

関連して、Docker for Mac / boot2dockerの違いや、通信のキャプチャ、Electronについても触れました。


これからDockerを（Macをベースに）触ってみようという方や、Electronに触れてみようという方にとっても、Kitematicはなかなか面白い素材なのではないかなと思います。
設定に慣れる、もしくはいろんなイメージを試してみるといった点でも、とても使いやすいツールですので、ぜひ機会があれば利用してみてくださいね!


## おまけ：キャラを描いている方は？

Dockerのクジラさん、エイ、その他のイラストは、[laurelさん](https://twitter.com/laurelcomics) という方がかいていらっしゃいます。こちらも日々可愛いDockerのキャラクターの面々が紹介されたりしています！

個人的に、Kitematicのイメージキャラクター（エイ）の可愛さが気に入っております。Kitematicをインストールされた場合は、about...の画面にこんなキャラクターが出てきますので、こちらも合わせてご覧くださいませ。

![kitematic-and-docker.png](https://qiita-image-store.s3.amazonaws.com/0/27976/f4a60636-b89b-2ff1-a933-67f33298f656.png "kitematic-and-docker.png")

それでは、良い年末年始をお過ごしください！