このシリーズ
- Apache Zeppelinでデータ分析を分散処理する - Part 1: データ分析のライフサイクル
- Apache Zeppelinでデータ分析を分散処理する - Part 2: Ambari on DockerにZeppelinをセットアップする
- Apache Zeppelinでデータ分析を分散処理する - Part 3: ZeppelinでHiveを使えるようにする
- Apache Zeppelinでデータ分析を分散処理する - Part 4: Ambari on Dockerのambari-functionsを使ってみる
ambari-functions
Part 2ではAmbari on Dockerのsequenceiq/ambariイメージからAmbariクラスターをセットアップしました。ここで利用したambari-functionsにはDockerとAmbariの管理に便利な関数がいくつか定義されています。リポジトリからcloneしてambari-functions
を読み込むとamb-*
関数が利用できるようになります。
$ git clone https://github.com/sequenceiq/docker-ambari.git
$ cd !$
$ source ambari-functions
Docker操作系
docker-ps
docker ps
をラップしてAmbari管理に有用な情報を1行に見やすくしてくれます。コンテナ名、IPアドレス、Dockerイメージ名が一覧できます。
$ docker-ps
/nginx 172.17.0.7 nginx-consul <nil> {[/bin/start.sh]}
/amb3 172.17.0.6 sequenceiq/ambari:2.1.2-v1 <nil> {[/start-agent]}
/amb2 172.17.0.5 sequenceiq/ambari:2.1.2-v1 <nil> {[/start-agent]}
/amb1 172.17.0.4 sequenceiq/ambari:2.1.2-v1 <nil> {[/start-agent]}
/amb-server 172.17.0.3 sequenceiq/ambari:2.1.2-v1 <nil> {[/start-server]}
/amb-consul 172.17.0.2 sequenceiq/consul:v0.5.0-v6 {[/bin/start]} {[-server -bootstrap]}
現在のZeppelinは以下のように5台のコンテナで構成されています。
- Ambari Server x 1
- Ambari Worker Node x 3
- Consul x 1
- Nginx x 1
docker-psa
docker ps -a
と同じです。起動していないコンテナも表示します。
$ docker-psa
/nginx 172.17.0.7 nginx-consul <nil> {[/bin/start.sh]}
/amb3 172.17.0.6 sequenceiq/ambari:2.1.2-v1 <nil> {[/start-agent]}
/amb2 172.17.0.5 sequenceiq/ambari:2.1.2-v1 <nil> {[/start-agent]}
/amb1 172.17.0.4 sequenceiq/ambari:2.1.2-v1 <nil> {[/start-agent]}
/amb-server 172.17.0.3 sequenceiq/ambari:2.1.2-v1 <nil> {[/start-server]}
/amb-consul 172.17.0.2 sequenceiq/consul:v0.5.0-v6 {[/bin/start]} {[-server -bootstrap]}
Ambari操作系
amb-start-cluster
Part 2でamb-start-cluster
関数を使いDockerコンテナを4つ作成しました。
$ amb-start-cluster 4
関数の内部ではamb-start-first
を実行し最初の1ノードのAmbari Serverと追加でConsulのコンテナを作成します。今回の場合残り3ノードがワーカーノードになります。
amb-start-cluster() {
local act_cluster_size=$1
: ${act_cluster_size:=$CLUSTER_SIZE}
echo starting an ambari cluster with: $act_cluster_size nodes
amb-start-first
[ $act_cluster_size -gt 1 ] && for i in $(seq $((act_cluster_size - 1))); do
amb-start-node $i
done
}
amb-start-first
最初にConsulコンテナとAmbari Serverコンテナを作成します。
amb-start-first() {
local dns_port_command=""
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
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
get-ambari-server-ip
_consul-register-service $AMBARI_SERVER_NAME $AMBARI_SERVER_IP
_consul-register-service ambari-8080 $AMBARI_SERVER_IP
}
amb-start-node
この関数ではAmbariワーカーノードのコンテナを作成して、Consulにサービスとして登録しています。
amb-start-node() {
get-ambari-server-ip
: ${AMBARI_SERVER_IP:?"AMBARI_SERVER_IP is needed"}
NUMBER=${1:?"please give a <NUMBER> parameter it will be used as node<NUMBER>"}
if [[ $# -eq 1 ]]; then
MORE_OPTIONS="-d"
else
shift
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
_consul-register-service ${NODE_PREFIX}${NUMBER} $(get-host-ip ${NODE_PREFIX}$NUMBER)
}
Ambariワーカーノードのコンテナで実行されるstart-agentへBRIDGE_IP
環境変数としてConsulコンテナのIPアドレスを渡しています。--net="host"
フラグをつけてコンテナを起動した場合/etc/resolv.conf
がホストのファイルが使われるため、--dns
フラグが利用できません。ワークアラウンドとしてコンテナのコマンドでConsulをnameserverに指定して/etc/resolv.conf
を上書きしています。
# --dns isn't available for: docker run --net=host
# sed -i /etc/resolf.conf fails:
# sed: cannot rename /etc/sedU9oCRy: Device or resource busy
# here comes the tempfile workaround ...
local-nameserver() {
cat>/etc/resolv.conf<<EOF
nameserver $BRIDGE_IP
search service.consul node.dc1.consul
EOF
}
amb-start-node関数を直接使い、現在3台あるワーカーノードに1台のコンテナを追加してみます。関数の中でAmbari ServerやConsulのIPアドレスを設定してくれます。NODE_PREFIX
を引数の数字を追加した名前がコンテナ名になります。docker-ps
関数で確認したように現在amb3
まであるので4
を追加します。
$ amb-start-node 4
出力結果は以下です。ホスト名にamb4.service.consul
が指定されました。
[DEBUG] docker run -d -e BRIDGE_IP=172.17.0.2 --name amb4 -h amb4.service.consul sequenceiq/ambari:2.1.2-v1 /start-agent
78353cc44a93693a331357ba15b08d4015f88d7fc509ce06ab39295a6972de3e
Consulのサービスカタログにもamb4
が登録されています。
$ amb-members | jq .
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 308 100 308 0 0 304k 0 --:--:-- --:--:-- --:--:-- 300k
[
{
"Node": "amb-consul.service.consul",
"Address": "172.17.0.2"
},
{
"Node": "amb-server",
"Address": "172.17.0.3"
},
{
"Node": "amb1",
"Address": "172.17.0.4"
},
{
"Node": "amb2",
"Address": "172.17.0.5"
},
{
"Node": "amb3",
"Address": "172.17.0.6"
},
{
"Node": "amb4",
"Address": "172.17.0.8"
}
]
amb-shell
Part 2ではsequenceiq/ambariに入っている/tmp/ambari-shell.shスクリプトを直接実行してAmbari Shellを起動しました。今回はambari-functionsに入っているamb-shell
関数を経由して使ってみます。どちらも同じ/tmp/ambari-shell.sh
を実行します。
_amb_run_shell() {
COMMAND=$1
: ${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
}
amb-shell() {
_amb_run_shell /tmp/ambari-shell.sh
}
Ambari Shellが起動しました。
[DEBUG] docker run -it --rm -e EXPECTED_HOST_COUNT=4 -e BLUEPRINT=--link amb-server:ambariserver --entrypoint /bin/sh sequenceiq/ambari:2.1.2-v1 -c /tmp/ambari-shell.sh
AMBARI_HOST=172.17.0.3
[DEBUG] waits for ambari server: 172.17.0.3 RUNNING ...
[DEBUG] waits until 4 hosts connected to server ...
[DEBUG] connected hosts: 4
_ _ _ ____ _ _ _
/ \ _ __ ___ | |__ __ _ _ __ (_)/ ___| | |__ ___ | || |
/ _ \ | '_ ` _ \ | '_ \ / _` || '__|| |\___ \ | '_ \ / _ \| || |
/ ___ \ | | | | | || |_) || (_| || | | | ___) || | | || __/| || |
/_/ \_\|_| |_| |_||_.__/ \__,_||_| |_||____/ |_| |_| \___||_||_|
Welcome to Ambari Shell. For command and param completion press TAB, for assistance type 'hint'.
ambari-shell>
Ambariが利用可能なホストの一覧を表示します。
ambari-shell>host list
amb4.service.consul [HEALTHY] 172.17.0.8 centos6:x86_64
amb1.service.consul [HEALTHY] 172.17.0.4 centos6:x86_64
amb2.service.consul [HEALTHY] 172.17.0.5 centos6:x86_64
amb3.service.consul [HEALTHY] 172.17.0.6 centos6:x86_64
残念ながらAmbari Shellを使ってノードの追加はできません。Cloudbreakなどでも使っているambari-rest-clientのAmbariClientMain.groovyを直接使うと可能らしいので試してみようと思います。
package com.sequenceiq.ambari.main
import com.sequenceiq.ambari.client.AmbariClient
class AmbariClientMain {
public static void main(String[] args) {
def host = 'localhost'
def port = '8080'
if (args.size == 2) {
host = args[0]
port = args[1]
}
AmbariClient client = new AmbariClient(host, port)
println "\n clusterList: \n${client.showClusterList()}"
println "\n hostsList: \n${client.showHostList()}"
println "\n tasksList: \n${client.showTaskList()}"
println "\n serviceList: \n${client.showServiceList()}"
println "\n blueprintList: \n${client.showBlueprints()}"
println "\n clusterBlueprint: \n${client.showClusterBlueprint()}"
}
}
Hadoop操作系
WebHDFS REST API経由でHDFSの操作ができます。
amb-create-hdfs-dir
HDFSにディレクトリを作成する関数です。
amb-create-hdfs-dir() {
get-ambari-server-ip
DIR=$1
curl -X PUT "http://$AMBARI_SERVER_IP:50070/webhdfs/v1$DIR?user.name=hdfs&op=MKDIRS" > /dev/null 2>&1
}
Ambariの設定からWebHDFSのチェックを確認します。
HDFS > Configs > Advanced > General > WebHDFS enabled
2.1. Getting Correct Configuration Values for Manually-Deployed ClustersのドキュメントにWebHDFSのURIの設定場所が書いてあります。
HDFS > Configs > Advanced > Advanced hdfs-site > dfs.namenode.http-address
この環境ではamb1.service.consul:50070
がWebHDFSのURIに設定されていますが、amb-create-hdfs-dir
関数の中でAMBARI_SERVER_IP
環境変数にAmbari ServerのIPアドレスが指定されてしまいます。WebHDFSを使う場合は直接curlから実行します。
$ WEB_HDFS_IP=$(docker inspect --format="{{ .NetworkSettings.IPAddress }}" amb1)
$ curl -X PUT "http://$WEB_HDFS_IP:50070/webhdfs/v1/user/root/test?user.name=root&op=MKDIRS"
{"boolean":true}
amb1コンテナに入ってHDFSにディレクトリが作成されたか確認してみます。
$ docker exec -it amb1 hadoop fs -ls
Found 3 items
drwxr-xr-x - root hdfs 0 2015-12-10 08:45 .sparkStaging
-rw-r--r-- 3 root hdfs 4610348 2015-12-10 08:49 bank-full.csv
drwxr-xr-x - root hdfs 0 2015-12-11 18:50 test
amb-copy-to-hdfs
WebHDFSのAPI経由でローカルのファイルをコピーできるようです。こちらも同様にAMBARI_SERVER_IP
環境変数を使っているのでこの環境では利用できません。
amb-copy-to-hdfs() {
get-ambari-server-ip
FILE_PATH=${1:?"usage: <FILE_PATH> <NEW_FILE_NAME_ON_HDFS> <HDFS_PATH>"}
FILE_NAME=${2:?"usage: <FILE_PATH> <NEW_FILE_NAME_ON_HDFS> <HDFS_PATH>"}
DIR=${3:?"usage: <FILE_PATH> <NEW_FILE_NAME_ON_HDFS> <HDFS_PATH>"}
amb-create-hdfs-dir $DIR
DATANODE=$(curl -si -X PUT "http://$AMBARI_SERVER_IP:50070/webhdfs/v1$DIR/$FILE_NAME?user.name=hdfs&op=CREATE" |grep Location | sed "s/\..*//; s@.*http://@@")
DATANODE_IP=$(get-host-ip $DATANODE)
curl -T $FILE_PATH "http://$DATANODE_IP:50075/webhdfs/v1$DIR/$FILE_NAME?op=CREATE&user.name=hdfs&overwrite=true&namenoderpcaddress=$AMBARI_SERVER_IP:8020"
}
まとめ
ambari-functionsを見てきました。Ambari ShellでできないことやHadoopのサービスとコンポーネントの構成によっては実行できない関数があります。Dockerやクラウドへのプロビジョンングを考えると同じDockerイメージを使うHadoopk管理ツールのCloudbreakを選択した方が良さそうです。Groovyのambari-rest-clientがAmbariやCloudbreakで共通して利用されているクライアントライブラリでした。AmbariClientMain.groovyのMainメソッドも直接試してみようと思います。