MesosをDocker Composeを使い起動する - Part 1: 1つの仮想マシンにセットアップする

　Mesos on Dockerをセットアップしてみます。DockerでMesosクラスタを構築するためMesosが管理するコンテナにDockerは使えませんが、MesosやMarathon、ZooKeeperをDocker Composeの設定ファイル1つでオーケストレーションできます。Mesosを試してみたり勉強する環境を簡単にセットアップすることができます。

## 仮想マシン

　今回はIDCFクラウドのDebian Jessieの仮想マシンを用意します。

```bash
$ cat /etc/debian_version
8.2
```

　1つの仮想マシンに複数のサービスを起動します。パブリックIPアドレスはスタティックNAT設置をするとポート番号を使った接続が簡単になります。

## DockerとDocker Compose

　DockerとDocker Composeはワンライナーで簡単にインストールできます。root権限で実行してください。

Docker

```bash
$ curl -sSL https://get.docker.com/ | sh
```

Docker Compose

```bash
$ curl -L https://github.com/docker/compose/releases/download/1.5.1/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose; chmod +x /usr/local/bin/docker-compose
```

## docker-compose-link.yml

　適当なディレクトリを作成します。

```bash
$ mkdir ~/mesos-compose
$ cd !$
```

　[docker-compose-link.yml](https://github.com/masato/mesos-compose/blob/master/docker-compose-link.yml)ファイルを作成します。

```docker-compose-link.yml
zk:
  image: garland/zookeeper
  ports:
    - "2181:2181"
    - "2888:2888"
    - "3888:3888"
master:
  image: garland/mesosphere-docker-mesos-master
  ports:
    - "5050:5050"
  links:
    - zk
  environment:
    - MESOS_ZK=zk://zk:2181/mesos
    - MESOS_LOG_DIR=/var/log/mesos
    - MESOS_QUORUM=1
    - MESOS_REGISTRY=in_memory
    - MESOS_WORK_DIR=/var/lib/mesos
marathon:
  image: garland/mesosphere-docker-marathon
  links:
   - zk
   - master
  command: --master zk://zk:2181/mesos --zk zk://zk:2181/marathon
  ports:
   - "8080:8080"
slave:
  image: garland/mesosphere-docker-mesos-master
  ports:
   - "5051:5051"
  links:
   - zk
   - master
  entrypoint: mesos-slave
  environment:
   - MESOS_HOSTNAME=slave
   - MESOS_MASTER=zk://zk:2181/mesos
   - MESOS_LOG_DIR=/var/log/mesos
   - MESOS_LOGGING_LEVEL=INFO
```

　docker-compose.ymlファイルはテスト用に複数使い分けるので`-f`フラグを指定します。`up`コマンドからコンテナをまとめて起動します。

```bash
$ docker-compose -f docker-compose-link.yml up -d
```

　psコマンドを実行してコンテナが4つupしていることを確認します。

```bash
$ docker-compose -f docker-compose-link.yml ps
         Name                     Command                    State                     Ports
-----------------------------------------------------------------------------------------------------
mesoscompose_marathon_1   /opt/marathon/bin/start   Up                        0.0.0.0:8080->8080/tcp
                          -- ...
mesoscompose_master_1     mesos-master              Up                        0.0.0.0:5050->5050/tcp
mesoscompose_slave_1      mesos-slave               Up                        0.0.0.0:5051->5051/tcp
mesoscompose_zk_1         /opt/run.sh               Up                        0.0.0.0:2181->2181/tcp,
                                                                              0.0.0.0:2888->2888/tcp,
                                                                              0.0.0.0:3888->3888/tcp
```


　MesosとMarathonはブラウザから管理画面が使えます。

Mesosの管理画面

http://{パブリックIPアドレス}:5050/

<img width="400" alt="mesos.png" src="https://qiita-image-store.s3.amazonaws.com/0/43745/8a7228f6-3935-7935-15dc-b9b07419c264.png">


Marathon管理画面

http://{パブリックIPアドレス}:8080/

<img width="400" alt="marathon.png" src="https://qiita-image-store.s3.amazonaws.com/0/43745/06775ae6-9902-ce2c-21d2-13312e8cd579.png">


## Marathon

　[Mesosphere Community Documentation](http://open.mesosphere.com/)を読みながら進めていきます。

* [Exercise 4 – Starting Marathon](https://open.mesosphere.com/advanced-course/starting-marathon/)
* [Exercise 5 – Using the Marathon GUI](https://open.mesosphere.com/advanced-course/using-the-marathon-gui/)


### アプリのデフォルトポートを使う

　Marathonの管理画面の右上の「+ New App」ボタンを押してMesosアプリを作成します。CommandフィールドにPythonの[SimpleHTTPServer](http://docs.python.jp/2/library/simplehttpserver.html)を設定します。デフォルトでポート番号は8000です。画面下の「+ Create」ボタンを押すとアプリがデプロイされます。

```
python -m SimpleHTTPServer
```

<img width="400" alt="simple-static.png" src="https://qiita-image-store.s3.amazonaws.com/0/43745/432b451b-49f4-6998-e462-f9c46dd1a4c1.png">


　DockerホストからMesosスレーブのコンテナに入ります。

```bash
$ docker exec -it mesoscompose_slave_1 bash
```

　Mesosのバージョンを確認しておきます。[0.21.1](http://mesos.apache.org/blog/mesos-0-21-1-released/)と少し古いバージョンです。

```bash
$ mesos-slave --version
mesos 0.21.1
```

　netstatコマンドを実行してSimpleHTTPServerが8000ポートでLISTENしていることを確認します。

```bash
$ netstat -nlp | grep 8000
tcp        0      0 0.0.0.0:8000            0.0.0.0:*               LISTEN      37/python
```

　Dockerホストに戻りMesosスレーブコンテナのIPアドレスを調べます。

```bash
$ SLAVE_IP=$(docker inspect --format="{{.NetworkSettings.IPAddress}}" mesoscompose_slave_1)
$ echo $SLAVE_IP
172.17.0.10
```

　curlコマンドからコンテナのIPアドレスを開くとHTTPサーバーが正常に動作していることがわかります。

```bash
$ curl http://$SLAVE_IP:8000/
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"><html>
<title>Directory listing for /</title>
<body>
<h2>Directory listing for /</h2>
<hr>
<ul>
<li><a href="stderr">stderr</a>
<li><a href="stdout">stdout</a>
</ul>
<hr>
</body>
</html>
```

　標準出力と標準エラーはMesosとMarathonがブラウザから直接見えるように設定してくれています。

標準エラー

```bash
$ curl http://$SLAVE_IP:8000/stderr
curl http://$SLAVE_IP:8000/stderr
I1130 11:50:36.306881    26 logging.cpp:172] INFO level logging started!
I1130 11:50:36.378998    26 exec.cpp:132] Version: 0.21.1
I1130 11:50:36.380383    32 exec.cpp:206] Executor registered on slave 20151130-111332-134222252-5050-1-S0
172.17.0.1 - - [30/Nov/2015 12:06:32] "GET / HTTP/1.1" 200 -
172.17.0.1 - - [30/Nov/2015 12:07:36] "GET /stderr HTTP/1.1" 200 -
```

標準出力

```bash
$ curl http://$SLAVE_IP:8000/stdout
Registered executor on master
Starting task simple.8fc5cfc2-9758-11e5-9bb5-0242ac110009
Forked command at 36
sh -c 'python -m SimpleHTTPServer'
```

### $PORTを使い動的にポートを割り当てる

　Marathonの管理画面のCommandフィールドに指定したSimpleHTTPServerの起動コマンドに、`$PORT`変数を渡すと動的にHTTPサーバーのポートを指定することができます。アプリを破棄して再作成します。

```
python -m SimpleHTTPServer $PORT
```

<img width="400" alt="simple-dynamic.png" src="https://qiita-image-store.s3.amazonaws.com/0/43745/5736852e-aed2-2970-0352-c2f6fbf00939.png">

slave:31320がリンクになりました。「slave」はdocker-compose.ymlのslaveサービスの`MESOS_HOSTNAME`環境変数に指定したホスト名ですが名前解決ができないため、このままではDockerホストの外からブラウザで接続することができません。

## まとめ

　MesosスレーブコンテナのポートはDockerホストに公開されていないのでパブリックIPアドレスから見ることができません。
　SimpleHTTPServerのデフォルトポートを静的に公開しても良いですが、アプリを追加するごとにdocker-compose.ymlに追加してMesosクラスタを再構築する必要があります。`$PORT`から動的にポート番号を割り当てる場合はポートの範囲指定になります。
　次回はDockerコンテナをホストネットワークに直接参加させる方法を試してみます。

## 参考

以下のサイトを参考にしました。

* [1 Command to Mesos with Docker Compose](http://sebgoa.blogspot.jp/2015/03/1-command-to-mesos-with-docker-compose.html)
* [mesosphere-docker](https://github.com/sekka1/mesosphere-docker)