IDCFクラウドのDebian JessieでMulti-Host Docker Networking - Part 5: AmbariとZeppelinをDocker Swarmにセットアップ


　これまで[Ambari on Docker](https://github.com/sequenceiq/docker-ambari)は[シングルホスト](http://qiita.com/masato/items/911e06fd31202181f0fd)で使っていました。ようやく[Multi-host newtwork](http://qiita.com/masato/items/6a1fa797b6c25d4c5745)と[Docker Swarmクラスタ](http://qiita.com/masato/items/a047798e48ccc1e56eb8)に慣れてきたので、[Ambari](https://ambari.apache.org/)と[Zeppelin](https://zeppelin.incubator.apache.org/)に[Spark](http://spark.apache.org/)の学習環境を移行していきます。


## このシリーズ

* [IDCFクラウドのDebian JessieでMulti-Host Docker Networking - Part 1: Overlayネットワークの作成](http://qiita.com/masato/items/6a1fa797b6c25d4c5745)
* [IDCFクラウドのDebian JessieでMulti-Host Docker Networking - Part 2: Docker Swarmクラスタの作成](http://qiita.com/masato/items/a047798e48ccc1e56eb8)
* [IDCFクラウドのDebian JessieでMulti-Host Docker Networking - Part 3: OverlayネットワークとDocker SwarmとDocker ComposeでRethinkDBをスケールさせる](http://qiita.com/masato/items/bd3d50b31f16a00eac47)
* [IDCFクラウドのDebian JessieでMulti-Host Docker Networking - Part 4: Couchbase Serverをスケールしてみる](http://qiita.com/masato/items/0be8b7da012f1180c281)


## Docker Network

　[Part 3](http://qiita.com/masato/items/bd3d50b31f16a00eac47)のRethinkDBや[Part 4](http://qiita.com/masato/items/0be8b7da012f1180c281)のCouchbase ServerではDocker Composeを使っていたので自動的にプロジェクト名のネットワークが作成されました。今回はDocker Composeを使わないため、直接ネットワークを作成します。`zeppelin`という名前で、サブネットをフラグをつけて指定しました。

```bash
$ docker network create \
  --subnet=192.168.0.0/24 \
  --driver=overlay \
  zeppelin
```

## ambari-functions

　[ambari-functions](https://github.com/sequenceiq/docker-ambari/blob/master/ambari-functions)はAmbari on Dockerのセットアップ用関数などが入っています。[Apache Zeppelinでデータ分析を分散処理する - Part 4: Ambari on Dockerのambari-functionsを使ってみる](http://qiita.com/masato/items/b879b84486aeb7d3d6d8)で中身を確認しました。

　リポジトリから`git clone`して`abari-functions`ファイルをDocker SwarmとDocker Networkの環境で動くように編集していきます。

```
$ git clone https://github.com/sequenceiq/docker-ambari/
$ cd docker-ambari
```

### ネットワークを指定する

　ネットワーク名を環境変数に定義します。クリア用の`amb-clean`にも追加します。　

```bash
: ${NETWORK:="zeppelin"}
...
amb-clean() {
  unset NODE_PREFIX AMBARI_SERVER_NAME IMAGE DOCKER_OPTS CONSUL CONSUL_IMAGE DEBUG SLEEP_TIME AMBARI_SERVER_IP EXPOSE_DNS DRY_RUN NETWORK
}
```

　`docker run`は`--net $NETWORK`フラグをつけてコンテナを起動するようにします。

```bash
_amb_run_shell() {
...
  run-command docker run --net $NETWORK -it --rm -e EXPECTED_HOST_COUNT=$((NODES-1)) -e BLUEPRINT=$BLUEPRINT -e AMBARI_HOST=$AMBARI_SERVER_NAME --entrypoint /bin/sh $IMAGE -c $COMMAND
}
...
amb-start-first() {
...
  run-command docker run -d --net $NETWORK $dns_port_command --name $CONSUL -h $CONSUL.service.consul $CONSUL_IMAGE -server -bootstrap
  sleep 5

  run-command docker run -d --net $NETWORK -e BRIDGE_IP=$(get-consul-ip) $DOCKER_OPTS --name $AMBARI_SERVER_NAME -h $AMBARI_SERVER_NAME.service.consul $IMAGE /start-server
...
amb-start-node() {
...
  run-command docker run $MORE_OPTIONS --net $NETWORK -e BRIDGE_IP=$(get-consul-ip) $DOCKER_OPTS --name ${NODE_PREFIX}$NUMBER -h ${NODE_PREFIX}${NUMBER}.service.consul $IMAGE /start-agent
```

　`--net`フラグをつけて作成したコンテナは`docker inspect`すると`NetworkSettings`フィールドの階層が増えます。コンテナのIPアドレスを取得する`get-host-ip`を追加された階層に合わせて編集してます。

```bash
get-host-ip() {
  HOST=$1
  docker inspect --format="{{.NetworkSettings.Networks.$NETWORK.IPAddress}}" ${HOST}
}
```

### コンテナの中でcurlを使う

　デフォルトの`docker0` bridgeを使わないのでコンテナのIPアドレスには直接Dockerホストからアクセス出来ません。`amb-members`など`curl`でConsulのAPIを実行していた箇所は`docker exec $CONSUL curl`のようにコンテナの中で使うようにします。

```bash
amb-members() {
  docker exec $CONSUL curl http://$(get-consul-ip):8500/v1/catalog/nodes | sed -e 's/,{"Node":"ambari-8080.*}//g' -e 's/,{"Node":"consul.*}//g'
}
...
_consul-register-service() {
  docker exec $CONSUL curl -X PUT -d "{
    \"Node\": \"$1\",
    \"Address\": \"$2\",
    \"Service\": {
      \"Service\": \"$1\"
    }
  }" http://$(get-consul-ip):8500/v1/catalog/register
}
```

　編集した箇所の`diff`は以下のようになりました。　

```bash
$ git diff ambari-functions
diff --git a/ambari-functions b/ambari-functions
index 8b07152..6e2f077 100644
--- a/ambari-functions
+++ b/ambari-functions
@@ -18,6 +18,7 @@ USAGE
 : ${DNS_PORT:=53}
 : ${EXPOSE_DNS:=false}
 : ${DRY_RUN:=false}
+: ${NETWORK:="zeppelin"}

 run-command() {
   CMD="$@"
@@ -30,7 +31,7 @@ run-command() {
 }

 amb-clean() {
-  unset NODE_PREFIX AMBARI_SERVER_NAME IMAGE DOCKER_OPTS CONSUL CONSUL_IMAGE DEBUG SLEEP_TIME AMBARI_SERVER_IP EXPOSE_DNS DRY_RUN
+  unset NODE_PREFIX AMBARI_SERVER_NAME IMAGE DOCKER_OPTS CONSUL CONSUL_IMAGE DEBUG SLEEP_TIME AMBARI_SERVER_IP EXPOSE_DNS DRY_RUN NETWORK
 }

 get-ambari-server-ip() {
@@ -43,11 +44,11 @@ get-consul-ip() {

 get-host-ip() {
   HOST=$1
-  docker inspect --format="{{.NetworkSettings.IPAddress}}" ${HOST}
+  docker inspect --format="{{.NetworkSettings.Networks.$NETWORK.IPAddress}}" ${HOST}
 }

 amb-members() {
-  curl http://$(get-consul-ip):8500/v1/catalog/nodes | sed -e 's/,{"Node":"ambari-8080.*}//g' -e 's/,{"Node":"consul.*}//g'
+  docker exec $CONSUL curl http://$(get-consul-ip):8500/v1/catalog/nodes | sed -e 's/,{"Node":"ambari-8080.*}//g' -e 's/,{"Node":"consul.*}//g'
 }

 amb-settings() {
@@ -95,7 +96,7 @@ _amb_run_shell() {
   : ${COMMAND:? required}
   get-ambari-server-ip
   NODES=$(docker inspect --format="{{.Config.Image}} {{.Name}}" $(docker ps -q)|grep $IMAGE|grep $NODE_PREFIX|wc -l|xargs)
-  run-command docker run -it --rm -e EXPECTED_HOST_COUNT=$((NODES-1)) -e BLUEPRINT=$BLUEPRINT --link ${AMBARI_SERVER_NAME}:ambariserver --entrypoint /bin/sh $IMAGE -c $COMMAND
+  run-command docker run --net $NETWORK -it --rm -e EXPECTED_HOST_COUNT=$((NODES-1)) -e BLUEPRINT=$BLUEPRINT -e AMBARI_HOST=$AMBARI_SERVER_NAME --entrypoint /bin/sh $IMAGE -c $COMMAND
 }

 amb-shell() {
@@ -123,10 +125,11 @@ amb-start-first() {
   if [[ "$EXPOSE_DNS" == "true" ]]; then
      dns_port_command="-p 53:$DNS_PORT/udp"
   fi
-  run-command docker run -d $dns_port_command --name $CONSUL -h $CONSUL.service.consul $CONSUL_IMAGE -server -bootstrap
+  run-command docker run -d --net $NETWORK $dns_port_command --name $CONSUL -h $CONSUL.service.consul $CONSUL_IMAGE -server -bootstrap
   sleep 5

-  run-command docker run -d -e BRIDGE_IP=$(get-consul-ip) $DOCKER_OPTS --name $AMBARI_SERVER_NAME -h $AMBARI_SERVER_NAME.service.consul $IMAGE /start-server
+  run-command docker run -d --net $NETWORK -e BRIDGE_IP=$(get-consul-ip) $DOCKER_OPTS --name $AMBARI_SERVER_NAME -h $AMBARI_SERVER_NAME.service.consul $IMAGE /start-server
+

   get-ambari-server-ip

@@ -169,13 +172,13 @@ amb-start-node() {
     MORE_OPTIONS="$@"
   fi

-  run-command docker run $MORE_OPTIONS -e BRIDGE_IP=$(get-consul-ip) $DOCKER_OPTS --name ${NODE_PREFIX}$NUMBER -h ${NODE_PREFIX}${NUMBER}.service.consul $IMAGE /start-agent
+  run-command docker run $MORE_OPTIONS --net $NETWORK -e BRIDGE_IP=$(get-consul-ip) $DOCKER_OPTS --name ${NODE_PREFIX}$NUMBER -h ${NODE_PREFIX}${NUMBER}.service.consul $IMAGE /start-agent

   _consul-register-service ${NODE_PREFIX}${NUMBER} $(get-host-ip ${NODE_PREFIX}$NUMBER)
 }
 _consul-register-service() {
-  curl -X PUT -d "{
+  docker exec $CONSUL curl -X PUT -d "{
     \"Node\": \"$1\",
     \"Address\": \"$2\",
     \"Service\": {
```


## Zeppelinのインストール

　AmbariクラスタとZeppelinをインンストール方法は[こちら](http://qiita.com/masato/items/911e06fd31202181f0fd)とほぼ同じです。あとで[Hiveの設定](http://qiita.com/masato/items/78a45cf9b6984552d4d9)も行います。


### Swarm Manager

　`docker run`はSwarm Managerを指定して実行する必要があるので`DOCKER_HOST`環境変数にexportして使います。`3333`ポートは[Part 2](http://qiita.com/masato/items/a047798e48ccc1e56eb8)で作成したSwarm Managerのポートです。


```bash
$ export DOCKER_HOST=tcp://10.3.0.101:3333
```

### Ambariクラスタの作成

　`ambari-functions`を読み込み`amb-start-cluster`を実行してAmbariクラスタをセットアップします。

```bash
$ source ambari-functions
$ amb-start-cluster 4
```

　`minion[1-3]`のDockerホストにそれぞれコンテナが作成されました。

```bash
$ docker ps
CONTAINER ID        IMAGE                         COMMAND                  CREATED             STATUS              PORTS                                                              NAMES
f2a8699786d7        sequenceiq/ambari:2.2.0-v1    "/start-agent"           10 seconds ago      Up 7 seconds        8080/tcp                                                           minion-1/amb3
43b8edf67263        sequenceiq/ambari:2.2.0-v1    "/start-agent"           11 seconds ago      Up 10 seconds       8080/tcp                                                           minion-2/amb2
93b610b677a6        sequenceiq/ambari:2.2.0-v1    "/start-agent"           13 seconds ago      Up 11 seconds       8080/tcp                                                           minion-3/amb1
3ba95ef16526        sequenceiq/ambari:2.2.0-v1    "/start-server"          15 seconds ago      Up 12 seconds       8080/tcp                                                           minion-3/amb-server
b7c46370dba6        sequenceiq/consul:v0.5.0-v6   "/bin/start -server -"   21 seconds ago      Up 19 seconds       53/tcp, 53/udp, 8300-8302/tcp, 8400/tcp, 8301-8302/udp, 8500/tcp   minion-2/amb-consul
```

### DockerネットワークとConsul DNS API

　Hadoopクラスタなどでは各ノードの名前解決が必要になります。Docker SwarmとMulti-Host network環境での名前解決は`/etc/hosts`を使います。`-h`フラグでホスト名をつけてをコンテナを起動すると自分のhostnameはランダムのコンテナ名でなく指定したホスト名になります。

```bash
$ docker exec amb1 cat /etc/hosts
192.168.0.4	amb1.service.consul amb1
127.0.0.1	localhost
::1	localhost ip6-localhost ip6-loopback
fe00::0	ip6-localnet
ff00::0	ip6-mcastprefix
ff02::1	ip6-allnodes
ff02::2	ip6-allrouters
192.168.0.6	amb3
192.168.0.6	amb3.zeppelin
192.168.0.3	amb-server.zeppelin
192.168.0.2	amb-consul
192.168.0.2	amb-consul.zeppelin
192.168.0.3	amb-server
192.168.0.5	amb2
192.168.0.5	amb2.zeppelin
```

　Consulの[DNS API](https://www.consul.io/intro/getting-started/services.html)を使うと[gliderlabs/registrator
](https://hub.docker.com/r/gliderlabs/registrator/)などを使いConsulに登録したサービス名は`service.consul`をプリフィックスしてクエリすることができます。`ambari-functions`では`-h ${NODE_PREFIX}${NUMBER}.service.consul`のように`-h`フラグで指定するホスト名はあらかじめ`service.consul`をつけてコンテナを作成しています。ただし他のノードは上記のようにDockerネットワーク名がドメイン名としてプリフィックスされます。`amb1.service.consul`からは`amb2.service.consul`でなく`amb2.zeppelin`になってしまいます。


### /etc/resolv.conf

　通常DockerコンテナはDockerホストの`/etc/resolv.conf`コピーされます。以下はIDCFクラウドの場合です。

```bash
$ docker run -d -P --name=redis redis
$ docker exec redis cat /etc/resolv.conf
domain cs3d0idcfcloud.internal
search cs3d0idcfcloud.internal
nameserver 10.3.0.1
nameserver 158.205.237.131
nameserver 158.205.229.244
```

　`Ambari on Docker`ではConsul DNS APIを使いノード間の名前解決をするため`/etc/resolv.conf`にConsulのノードを指定します。コンテナのCOMMANDに指定する[start-agent]
(https://github.com/sequenceiq/docker-ambari/blob/master/ambari-server/start-agent)スクリプトの中で`/etc/resolv.conf`を上書きしています。

```bash
$ docker exec amb1 cat /etc/resolv.conf
nameserver 192.168.0.2
search service.consul node.dc1.consul
```

　ややこしいですがDNS用のConsulはDocker Swarmで使うため各Dockerホストに[セットアップ](http://qiita.com/masato/items/6a1fa797b6c25d4c5745)したConsulクラスタとは異なり、Docker Swarm上にある独立したConsulコンテナです。Consul DNS API用にDNSが8600でなく53ポートで使えるようにするなど、[gliderlabs/docker-consul](https://github.com/gliderlabs/docker-consul)からforkした[sequenceiq/docker-consul](https://github.com/sequenceiq/docker-consul)を使っています。


### public-hostname.sh

　Multi-host network環境でのDNSは次の課題です。`/etc/hosts`の本来の使い方はノードに閉じられているので、` $(hostname -f)`などで取得したホスト名をノードの外で使うのは良くないらしいのです。

　[update amb functions to use ambari 2.2.0
](https://github.com/sequenceiq/docker-ambari/commit/37452290667f22298d913a6333e64ffd09d3f1b9)のコミットで`ambari-functions`が使う[Ambari on Docker](https://github.com/sequenceiq/docker-ambari)のバージョンが`2.2.0`になりました。


```bash
${IMAGE:="sequenceiq/ambari:2.2.0-v1"}
```

　この変更でAmbari Agentの設定ファイル(/etc/ambari-agent/conf/ambari-agent.ini)で使う[public-hostname.sh](https://github.com/sequenceiq/docker-ambari/blob/master/ambari-server/public-hostname.sh)がパブリックIPアドレスを使うようになりました。

```bash:/etc/ambari-agent/conf/ambari-agent.ini
[agent]
hostname_script=/etc/ambari-agent/conf/internal-hostname.sh
public_hostname_script=/etc/ambari-agent/conf/public-hostname.sh
```

```bash:/etc/ambari-agent/conf/public-hostname.sh
#!/bin/bash

STATUS=$(curl -s -m 5 -w "%{http_code}" http://169.254.169.254/latest/meta-data/public-ipv4 -o /dev/null)
if [ "$STATUS" == "200" ]; then
        curl -s -m 5 http://169.254.169.254/latest/meta-data/public-ipv4 
else
        dig +short myip.opendns.com @resolver1.opendns.com
fi
```

　このスクリプトはAWS、GCE、Azureなどのクラウドではhostnameが取得できます。残念ながらIDCFクラウドでは動きません。IDCFクラウドのCloudStackの実装の場合は仮想マシンごとにパブリックIPアドレスが付いていません。`dig`コマンドは仮想ルーターのパブリックIPアドレスが返ります。そのためAmbari AgentごとにIPアドレスが一意にならず、Ambari Shellを使いホストグループのアサインで失敗してしまいます。

　IDCFクラウド用にDockerイメージをビルドしようと思いましたが、コンテナを起動した後に`docker exec`で入り修正することにしました。

```bash
$ docker exec -it amb1 bash
```

　`public-hostname.sh`を編集して`hostname -f`を返すようにします。

```bash:/etc/ambari-agent/conf/public-hostname.sh
#!/bin/bash

STATUS=$(curl -s -m 5 -w "%{http_code}" http://169.254.169.254/latest/meta-data/public-ipv4 -o /dev/null)
if [ "$STATUS" == "200" ]; then
	curl -s -m 5 http://169.254.169.254/latest/meta-data/public-ipv4
else
#	dig +short myip.opendns.com @resolver1.opendns.com
    echo $(hostname -f)
fi
```

　コンテナを再起動します。

```bash
$ docker restart amb1 amb2 amb3
```

　この感じだと[Cloudbreak](http://hortonworks.com/hadoop/cloudbreak/)をIDCFクラウドに対応させるのは難しそうな気がしてきました。クラウドで簡単にHadoopクラスタを構築できるので便利なのですが。。

## Ambari Shell

　[Ambari Shell](https://github.com/sequenceiq/ambari-shell)を起動して[Blueprints](https://cwiki.apache.org/confluence/display/AMBARI/Blueprints)を使いZeppelinをセットアップしていきます。

　`ambari-functions`の`amb-shell`を使い起動します。

```bash
$ amb-shell
```

　Ambari Shellで利用できるBlueprintの書き方は`'slave_'`ではじまるホストグループが必要など[制約](https://github.com/sequenceiq/ambari-rest-client/blob/master/src/main/groovy/com/sequenceiq/ambari/client/AmbariClient.groovy)があります。


```groovy:AmbariClient.groovy
  private static final String SLAVE = 'slave_'

        def slaves = groups.findAll { it.name.toLowerCase().startsWith(SLAVE) }
        if (slaves) {
          int k = 0
          for (int j = i; j < hostSize; j++) {
            result[slaves[k].name] = result[slaves[k].name] ?: []
            result[slaves[k].name] << hostNames[j]
            result << [(slaves[k].name): result[slaves[k++].name]]
            k = k == slaves.size ? 0 : k
          }
        } else {
          throw new InvalidHostGroupHostAssociation("At least one '$SLAVE' is required", groupSize)
        }
```

　同じBlueprintでも[Hortonworks Gallery](https://github.com/hortonworks-gallery/ambari-zeppelin-service)にある[Zeppelin Service](https://github.com/hortonworks-gallery/ambari-zeppelin-service)は利用できません。[Cloudbreak](http://hortonworks.com/hadoop/cloudbreak/)の[Blueprint](https://github.com/sequenceiq/cloudbreak/tree/master/core/src/main/resources/defaults/blueprints)のような書き方でないと実行時にエラーになります。


```bash
ambari-shell> blueprint add --url https://raw.githubusercontent.com/sequenceiq/cloudbreak/master/core/src/main/resources/defaults/blueprints/datascientist.bp
```

　Ambariクラスタを構成するためのコンテナを確認します。

```bash
ambari-shell>host list
amb1.service.consul [HEALTHY] 192.168.0.4 centos6:x86_64
amb2.service.consul [HEALTHY] 192.168.0.5 centos6:x86_64
amb3.service.consul [HEALTHY] 192.168.0.6 centos6:x86_64
```

　`cluster build`コマンドで表示する`HOSTNAME`は`public-hostname.sh`を使っているようです。

```bash
ambari-shell>cluster build --blueprint datascientist
  HOSTNAME             STATE
  -------------------  -------------------
  amb3.service.consul  amb3.service.consul
  amb1.service.consul  amb1.service.consul
  amb2.service.consul  amb2.service.consul
```

　`autoAssign`でなく個別にホストをアサインしていきます。

```bash
CLUSTER_BUILD:datascientist>cluster assign --hostGroup master_1 --host amb1.service.consul
amb1.service.consul has been added to master_1
CLUSTER_BUILD:datascientist>cluster assign --hostGroup slave_1 --host amb2.service.consul
amb2.service.consul has been added to slave_1
CLUSTER_BUILD:datascientist>cluster assign --hostGroup client --host amb3.service.consul
amb3.service.consul has been added to client
```

　`create`してAmbariクラスタが完成されるのを待ちます。

```bash
CLUSTER_BUILD:datascientist>cluster create --exitOnFinish true
```

## consul-templateとNginxのリバースプロキシ

　Ambari on DockerではDockerコンテナのポートはDockerホストにマップしません。AmbariとZeppelinの管理画面にアクセスできるように[consul-template](https://github.com/hashicorp/consul-template)を使ってNginxのリバースプロキシを作ります。


　シングルノードの時はローカルでビルドしたイメージを使い、consul-template用のテンプレートもDockerホストからボリュームをマウントしていました。Docker SwarmクラスタになるとローカルでビルドしたイメージやDockerホストのボリュームをマウントできなくなります。各ノードから`docker pull`できるようにリポジトリにイメージをおきます。

　Docker Swarmで`docker pull`をするとすべてのノードでDockerイメージをダウンロードしてくれます。

```bash
$ export DOCKER_HOST=tcp://10.3.0.101:3333
$ docker pull masato/nginx-consul
Using default tag: latest
minion-2: Pulling masato/nginx-consul:latest... : downloaded
minion-1: Pulling masato/nginx-consul:latest... : downloaded
minion-3: Pulling masato/nginx-consul:latest... : downloaded
```

　IDCFクラウドのパブリックIPアドレスのポートフォワードを特定の仮想マシンに固定したいので、`-e constraint:node==minion-2`の制約を入れます。

　NginxコンテナはAmbariクラスタ用のConsulコンテナを`--dns`フラグの先頭に指定して起動します。

```bash
$ AMB_CONSUL=$(docker inspect --format="{{.NetworkSettings.Networks.zeppelin.IPAddress}}" amb-consul)
$ echo $AMB_CONSUL
192.168.0.2
$ docker run -d \
  --name nginx \
  --env constraint:node==minion-2 \
  --env CONSUL_URL=$AMB_CONSUL:8500 \
  --net zeppelin \
  -p 8080:8080 -p 9995:9995 -p 9996:9996 \
  --dns $AMB_CONSUL \
  --dns 172.17.0.1 \
  --dns 8.8.8.8 \
  --dns-search service.consul \
  masato/nginx-consul 
```

　`ps`でDocker Swarmのコンテナの状態を確認します。

```bash
$ docker ps
CONTAINER ID        IMAGE                         COMMAND                  CREATED              STATUS              PORTS                                                                             NAMES
a81a30d32213        masato/nginx-consul           "/bin/start.sh"          About a minute ago   Up About a minute   80/tcp, 10.3.0.102:8080->8080/tcp, 443/tcp, 10.3.0.102:9995-9996->9995-9996/tcp   minion-2/berserk_swartz
b770b58d4b05        sequenceiq/ambari:2.2.0-v1    "/start-agent"           27 minutes ago       Up 25 minutes       8080/tcp                                                                          minion-3/amb3
df84975d8196        sequenceiq/ambari:2.2.0-v1    "/start-agent"           27 minutes ago       Up 25 minutes       8080/tcp                                                                          minion-2/amb2
7443b0b8c6ba        sequenceiq/ambari:2.2.0-v1    "/start-agent"           27 minutes ago       Up 25 minutes       8080/tcp                                                                          minion-1/amb1
52118d892cb1        sequenceiq/ambari:2.2.0-v1    "/start-server"          27 minutes ago       Up 27 minutes       8080/tcp                                                                          minion-2/amb-server
383f3c220e8f        sequenceiq/consul:v0.5.0-v6   "/bin/start -server -"   28 minutes ago       Up 28 minutes       53/tcp, 53/udp, 8300-8302/tcp, 8400/tcp, 8500/tcp, 8301-8302/udp                  minion-3/amb-consul
```

## Zeppelinの設定

　ZeppwlinのHDFSとHiveの設定は以下を参考にして、NoteBookを実行する準備をします。

* [Apache Zeppelinでデータ分析を分散処理する - Part 2: Ambari on DockerにZeppelinをセットアップする](http://qiita.com/masato/items/911e06fd31202181f0fd)
* [Apache Zeppelinでデータ分析を分散処理する - Part 3: ZeppelinでHiveを使えるようにする](http://qiita.com/masato/items/78a45cf9b6984552d4d9)