Hadoopで完全分散モードを試す on VMWareFusion


##やりたいこと
Hadoopの完全分散モードの環境を最短（1時間以内）で構築したい。

Hadoopのマスター、スレーブは、多くの要素が共通なので、共通部分の構築を1つのVMで行った後、必要な数だけVMをコピーし、可能な限り作業の重複を無くしたい。プロビジョニングツール等も考えたが、結局Hadoop以外のノウハウに依存するので、今回は原始的手法で。

>正直、めんどくさいのはVMをコピーした際にMacアドレスを振り直したりするのくらいです。

##利用する環境

###ホスト側
* 2009 lateのiMac（古い）32GB RAM
* Mac OS X El Capitan
* VMWareFusion8

###ゲストOS
* CentOS6.7（7でもいい）構成はRAM1G,20GB HDの最小構成で作成。

##Hadoopクラスタ構成
3台構成にします。

* master（ネームノード：リソースマネージャ、ノードマネージャも）
* slave1（データノード）
* slave1（データノード）

##手順（概要）

まずは、1台のVM(master)に共通部分まで構築したら、そのVMファイルをコピーしてslave1,slave3とし、各VMに対して必要な設定を行って行きます。

###共通部分
* OSインストール
* 必要ツールのインストール
* SSHの設定
* JavaのインストールとHOME, PATH等の設定
* HadoopのインストールとHOME, PATH等の設定（各種設定ファイルの設定はせず）
* テストが目的ならfirewall offにしてもいいかも（service iptables stop）

###VMのコピー

* VMをコピーするとネットワーク設定が死ぬので再設定します（VMWareFusion依存）

###設定ファイルの編集と転送

masterにて設定ファイルを編集し、必要に応じてslaveに転送します。

* core-site.xml
* hdfs-site.xml（共通部、masterのみ部）
* mapred-site.xml
* yarn-site.xml
* slaves

##注意点！

なお、以下の作業は全てrootで行ないます（useraddさえめんどうなので）。
必要に応じてhadoop専用ユーザーを追加するなどして下さい。

##共通部分の設定

###ゲストOSのインストール

難しいことはありませんので、他の情報に譲ります。インストールのタイプはMinimalとしました。

###SELinxのDisabled

SELinuxの設定をDisabledにしておきましょう。

/etc/selinux/configのSELINUX=enforcingをdisabledにしておきましょう。そして再起動。

###必要ツールのインストール
開発系ツールとwgetだけインストールしておきます。

```bash
yum install 'Development tools'
yum wget
```
###SSHの設定
クラスターを組むには相互にパスフレーズ無しでsshログインできる必要があります。とりあえずlocalhostにsshできるようにしておけば、コピーすれば相互ログインできるはずです。

```bash
mkdir ~/.ssh
chmod 700 .ssh
cd .ssh
ssh-keygen -t rsa
.
.
cp id_rsa.pub authorized_keys

ssh localhost
```
という感じ。いろいろメッセージがでたり、初回はyes/no聞かれたりする。その場合はyes。

###JavaのインストールとHOME, PATH等の設定
Javaは6以上ならなんでもいいらしいですが、とりあえず、本家の最新を入れておきます。
wgetでrpmをダウンロードし、インストールします。

```bash
wget --no-check-certificate --no-cookies --header "Cookie: oraclelicense=accept-securebackup-cookie" http://download.oracle.com/otn-pub/java/jdk/8u66-b17/jdk-8u66-linux-x64.rpm

rpm -ivh jdk-8u66-linux-x64.rpm
```
インストールしたら、JAVA_HOMEの設定をし、必要に応じて$JAVA_HOME/binへのPATH通しなどしておきましょう。
とりあえず.bashrcに、

```bash
export JAVA_HOME=/usr/java/jdk1.8.0_66
```
を追記しておきます（PATH通しは、次のhadoopの設定で一緒にするので割愛）。

###HadoopのインストールとHOME, PATH等の設定

Hadoopをダウンロードして、インストールします。といってもhadoopはjavaアプリなので、解凍して配置するだけ。配置は/usr/以下にしてみます。

```bash
wget http://ftp.riken.jp/net/apache/hadoop/common/hadoop-2.7.1/hadoop-2.7.1.tar.gz 
tar -xzvf hadoop-2.7.1.tar.gz 

mv hadoop-2.7.1 /usr/
```

HADOOP_HOMEやPATHを設定します。.bashrcを編集します。

```bash
export HADOOP_HOME=/usr/hadoop-2.7.1
export PATH=$HADOOP_HOME/bin:$HADOOP_HOME/sbin:$JAVA_HOME/bin:$PATH
```
ここまでできたら、hadoop(client)が正常に動くか確認しておきましょう。

```bash
hadoop version
```
バージョンが表示されれば、一連の操作は無事に終わったと思っていいでしょう。
ここまでを一旦共通作業とし、後は個別に行ないます。

##VMのコピー

VMをコピーして、slave用のVMを作ります。正直このフェーズが一番面倒です（苦笑）。

>面倒な場合は、1台ずつ、練習も兼ねて上記共通作業をセットアップしても問題ありません。

###手順

*コピー元のVMをいちおうシャットダウンしておく。
* VMを物理的にコピーし、ファイルをリネーム。
* コピーファイルをダブルクリックし一旦起動させる。
* VM上での表示名を変更する(VMareFusionの管理画面上での操作）。
* コピーVMをシャットダウンさせ、ネットワークの設定で新規Macアドレスを生成する（それを覚えておく）。
* 再度コピーVMを起動させ、2つのファイルを編集し、再起動する。

###VMファイルのコピー

標準では、VMWareFusionのファイルはHomeディレクトリ->書類->仮想マシン以下にあります。普通にコピーして、コピーが完了したら、適切なファイル名にリネームします。ダブルクリックすれば起動しますが、このとき、元になったVMは終了させておきましょう（MACアドレスやIPが被るため）。

###VMをVMWareを認識させ、表示名を変更

コピーしたVMを起動させ、VMWareに認識？させます。そして、VMWare上での表示名もリネームしておきます。
なお、この時、ネットワーク情報は元のVMの情報を引き継いでいるため、このまま両方のVMを起動させると正しく動作しません。コピーしたVMのMACアドレス（IP）を変更します。

###VMを終了させ、Macアドレスを生成する

一度、VMを終了させます。
VMの設定画面->ネットワークアダプタを開き、さらに詳細オプションを開きます。そして、MACアドレス「生成」ボタンをクリックし、新規のMacアドレスを生成します。この時、このMacアドレスをコピーして記憶しておきます。

###ネット設定ファイルを編集

VMを起動させます。そうするとネットワーク設定が死んだ状態となっていて、ネットワークに接続できません。
復活させるためには下記2つのファイルを編集します。

/etc/udev/rules.d/70-persistent-net.rules

同じアダプタの記述が重複しているので、一番下の設定以外を削除します。そして、eth1等となっている箇所をeth0に書き換えます。

/etc/sysconfig/network-scripts/ifcfg-eth0

MACアドレスを先ほどコピーしたものに書き換えます。
念のため、マシンを再起動しておきます。

この手順で、マシンのネットワークが復活し、かつ新しいMAC（IP）アドレスが振られるはずです。

##設定ファイルの編集

###はじめに

設定はmaster上で行ない、必要に応じてscp等でコピーする形式をとります。
ですので、masterからslave1,slave2に対してパスフレーズ無しでsshログインできるか試しておくといいでしょう（次のhostsファイルの設定の後でもいいです）。

###hostsファイルの編集

master,slave1,slave2のマシンに振られたIPアドレスをifconfig等で確認し、各VMの/etc/hostsファイルに書いておきましょう。
私の場合、

```bash
192.168.77.136 master
192.168.77.137 slave1
192.168.77.138 slave2
```
としました。これで、ssh slav1とかで入れるはずです。

>なお、VMWareではIPを固定することもできますが、私はDHCPのままでやりました。

###データ用のディレクトリ作成
放っておくとHDFSは/tmpに作成されますが、ここではデータ用のディレクトリを作っておきます。

```bash
mkdir ~/datanode
ssh slave1 "mkdir ~/datanode"
ssh slave2 "mkdir ~/datanode"
```

###core-site.xmlの編集と転送

```bash
<configuration>
        <property>
                <name>fs.defaultFS</name>
                <value>hdfs://master:9000/</value>
        </property>
</configuration>
```

転送します。

```bash
cd $HADOOP_HOME/etc/hadoop
scp core-site.xml slave1:/usr/hadoop-2.7.1/etc/hadoop/
scp core-site.xml slave2:/usr/hadoop-2.7.1/etc/hadoop/
```

###hdfs-site.xmlの編集と転送

レプリケーションの数（標準は3）やら、datanode用のdirとして、先ほど作成したディレクトリを指定しています。

```bash
<configuration>
        <property>
                <name>dfs.replication</name>
                <value>2</value>
        </property>
        <property>
                <name>dfs.datanode.data.dir</name>
                <value>file:///root/datanode</value>
        </property>
</configuration>
```
転送します。

```bash
scp hdfs-site.xml slave1:/usr/hadoop-2.7.1/etc/hadoop/
scp hdfs-site.xml slave2:/usr/hadoop-2.7.1/etc/hadoop/
```
master上にnamenode用のディレクトリを作成し、masterのhdfs-site.xmlだけそれを利用する記述を追記する。

```bash
mkdir ~/namenode
```

```hdfs
<configuration>
        <property>
                <name>dfs.replication</name>
                <value>2</value>
        </property>
        <property>
                <name>dfs.datanode.data.dir</name>
                <value>file:///root/datanode</value>
        </property>
        <property>
                <name>dfs.namenode.name.dir</name>
                <value>file:///root/namenode</value>
        </property>
</configuration>
```

###hadoop-env.shの編集と転送
hadoop-env.sh内のexport JAVA_HOMEの箇所を、適切に設定します。

ここでは、

```bash
export JAVA_HOME=/usr/java/jdk1.8.0_66
```
です。そして、転送します。

```bash
scp hadoop-env.sh slave1:/usr/hadoop-2.7.1/etc/hadoop/
scp hadoop-env.sh slave2:/usr/hadoop-2.7.1/etc/hadoop/
```

###mapred-site.xmlを新規作成

mapred-site.xmlは存在しないので新規に作成します。
mapreduceのフレームワークをyarnに設定しています。

```bash
<configuration>
        <property>
                <name>mapreduce.framework.name</name>
                <value>yarn</value>
        </property>
</configuration>
```

###yarn-site.xmlの編集

```bash
<configuration>
        <property>
                <name>yarn.resourcemanager.hostname</name>
                <value>master</value>
        </property>
        <property>
                <name>yarn.nodemanager.hostname</name>
                <value>master</value>
        </property>
        <property>
                <name>yarn.nodemanager.aux-services</name>
                <value>mapreduce_shuffle</value>
        </property>
</configuration>
```

###slaveの編集
```bash
master
slave1
slave2
```

##Hadoopの起動

では、起動させてみましょう。
まずは、namenodeの初期化等々。

###初期化

```bash
hadoop namenode -format
```

###起動

```bash
start-all.sh
```

###起動の確認

```bash
jps

5488 Jps
3473 SecondaryNameNode
3346 DataNode
3224 NameNode
3662 ResourceManager
3759 NodeManager
```

###終了

```bash
stop-all.sh
```

##動作確認

では、お馴染みWordCountで動作確認をしてみます。

```bash
echo "a b c a b" > test.txt

hadoop fs -mkdir /input
hadoop fs -put test.txt /input

hadoop jar $HADOOP_HOME/share/hadoop/mapreduce/hadoop-mapreduce-examples-2.7.1.jar wordcount /test /output

hadoop fs -cat /output/part-r-00000

a 2
b 2
c 1
```
動いているようです。

##管理画面

管理画面はmaster上にありますので、確認してみます。
なお、CentOS6.7ではiptablesがONになっていて設定しないと外から見れないのですが、めんどいのでOFFにしましょう。

```bash
service iptables stop
```

http://192.168.77.136:50070/
http://192.168.77.136:8088/