virtualbox、vagrant、ubuntuを使ってhadoopを動かす

# やること
macにvirtualboxとvagrantを入れてubuntuを動かす、その上でhadoopを動かしてみる。
本読んだりサイト見たりしてても、書いてあることがバラバラでどれを写経していいのか分からないので備忘録として残しておく。

# 環境
Mac OS X 10.11.3
Vagrant 1.8.1
- ubuntu 14.04
Hadoop 2.7.2

# 始める前に
後先考えずに行くとhadoopって単語が山ほど出てきてこんがらがるので、判別できるようにする。ユーザー名とかディレクトリ名とか。

* hdtest1
* testdir2
* hduser3

ターミナルの入力も、どの環境で、誰を操作しているのか、混同しないようにする

# 実践

## 準備
vagrantでubuntuを用意する。事前にhadoopをダウンロードしておく。

```
mac$ mkdir hdtest1
mac$ mv hadoo-2.7.2.tar.gz hdtest1/
mac$ cd hdtest1
mac$ vagrant init ubuntu/trusty64
mac$ vagrant up
mac$ vagrant ssh

vagrant$ vi .profile
```

とりあえずやっておく

```bash:.profile
# 本題と関係ないけどメモ
export HISTSIZE=10000
export HISTFILESIZE=10000
export HISTCONTROL=ignoredups
export HISTIGNORE=ls:ll:lla:pwd:history
```

```
# 必要に応じて実行
vagrant$ sudo apt-get autoremove -y
vagrant$ sudo apt-get update -y
vagrant$ sudo apt-get upgrade -y
vagrant$ sudo apt-get install -y default-jdk
```

## スタンドアロンモードで動かす

[Standalone Operation](http://hadoop.apache.org/docs/current/hadoop-project-dist/hadoop-common/SingleCluster.html#Standalone_Operation)

```
# macのディレクトリをマウントできているものとする
vagrant$ cp /vagrant/hadoop-2.7.2.tar.gz .
vagrant$ tar zxvf hadoop-2.7.2.tar.gz
vagrant$ cd hadoop-2.7.2

# ディレクトリ作って、サンプルのデータを用意しているだけ
vagrant$ mkdir testdir2
vagrant$ mkdir testdir2/input
vagrant$ cp etc/hadoop/*.xml testdir2/input

# 実行
vagrant$ bin/hadoop jar share/hadoop/mapreduce/hadoop-mapreduce-examples-2.7.2.jar grep testdir2/input testdir2/output 'dfs[a-z.]+'
Error: JAVA_HOME is not set and could not be found.

# JAVA_HOMEがないと言われた
# リンクではうまく行かなかった気がするので本体を探す
vagrant$ ls /usr/lib/jvm/
default-java  java-1.7.0-openjdk-amd64  java-7-openjdk-amd64

# JAVA_HOMEを設定して実行
vagrant$ JAVA_HOME=/usr/lib/jvm/java-7-openjdk-amd64/ bin/hadoop jar share/hadoop/mapreduce/hadoop-mapreduce-examples-2.7.2.jar grep testdir2/input testdir2/output 'dfs[a-z.]+'

vagrant$ ls testdir2/output/
part-r-00000  _SUCCESS

vagrant$ cat testdir2/output/part-r-00000 
1	dfsadmin
```

動いた

## 擬似分散モードで動かす

[Pseudo-Distributed Operation](http://hadoop.apache.org/docs/current/hadoop-project-dist/hadoop-common/SingleCluster.html#Pseudo-Distributed_Operation)

いろいろ準備

```
# 専用のユーザを追加する
# useraddでなくてadduserする
vagrant$ adduser hduser3

# hadoopのインストール先を変えて、先のユーザの所有とする
vagrant$ cd ~
vagrant$ sudo mv hadoop-2.7.2 /usr/local/
vagrant$ sudo chown -R hduser3:hduser3 /usr/local/hadoop-2.7.2/

# hduser3でログインする
vagrant$ ssh hduser3@localhost

# 初回はknown_hostsに追加するのを聞かれる
# パスワード入力が面倒なら鍵認証にするが省略

# 先にvagrantユーザーでもやった.profileの追加をしたりした

# 自分用の鍵認証を設定する
hduser3$ ssh-keygen -t rsa -P ''
hduser3$ cat .ssh/id_rsa.pub >> .ssh/authorized_keys
hduser3$ chmod 0600 .ssh/authorized_keys

hduser3$ cd /usr/local/hadoop-2.7.2
```

設定ファイルを編集する。core-site.xmlは注意。サイトとか本とかと異なるので公式サイトを参照。

```xml:etc/hadoop/core-site.xml
<configuration>
  <property>
    <name>fs.defaultFS</name>
    <value>hdfs://localhost:9000</value>
  </property>
</configuration>
```

```xml:etc/hadoop/hdfs-site.xml
<configuration>
  <property>
    <name>dfs.replication</name>
    <value>1</value>
  </property>
</configuration>
```

hdfsのフォーマット

```
hduser3$ bin/hdfs namenode -format
Error: JAVA_HOME is not set and could not be found.

# またJAVA_HOMEがないと言われた
```

設定ファイルを編集する

```bash:etc/hadoop/hadoop-env.sh
# The java implementation to use.
#export JAVA_HOME=${JAVA_HOME}
export JAVA_HOME=/usr/lib/jvm/java-7-openjdk-amd64
```

再度実行

```
hduser3$ bin/hdfs namenode -format
hduser3$ sbin/start-dfs.sh 
hduser3$ jps
12244 Jps
11936 DataNode
12135 SecondaryNameNode
11771 NameNode

hduser3$ bin/hdfs dfs -mkdir /user
hduser3$ bin/hdfs dfs -mkdir /user/hduser3
hduser3$ bin/hdfs dfs -put etc/hadoop input

hduser3$ bin/hadoop jar share/hadoop/mapreduce/hadoop-mapreduce-examples-2.7.2.jar grep input output 'dfs[a-z.]+'
...
OpenJDK 64-Bit Server VM warning: INFO: os::commit_memory(0x00000000e0ebb000, 104861696, 0) failed; error='Cannot allocate memory' (errno=12)
#
# There is insufficient memory for the Java Runtime Environment to continue.
# Native memory allocation (malloc) failed to allocate 104861696 bytes for committing reserved memory.
# An error report file with more information is saved as:
# /usr/local/hadoop-2.7.2/hs_err_pid12520.log
```

メモリが足りないらしいので、メモリを増やしてくる

```
hduser3$ exit
vagrant$ exit
mac$ vi Vagrantfile
```

```ruby:Vagrantfile
  # config.vm.provider "virtualbox" do |vb|
  #   # Display the VirtualBox GUI when booting the machine
  #   vb.gui = true
  #
  #   # Customize the amount of memory on the VM:
  #   vb.memory = "1024"
  # end
  config.vm.provider "virtualbox" do |vb|
  #   # Customize the amount of memory on the VM:
    vb.memory = "2048"
  end
```

再度実行

```
mac$ vagrant ssh
vagrant$ ssh hduser3@localhost

hduser3$ cd /usr/local/hadoop-2.7.2
hduser3$ sbin/start-dfs.sh
hduser3$ bin/hadoop jar share/hadoop/mapreduce/hadoop-mapreduce-examples-2.7.2.jar grep input output 'dfs[a-z.]+'
16/02/16 15:01:44 INFO Configuration.deprecation: session.id is deprecated. Instead, use dfs.metrics.session-id
16/02/16 15:01:44 INFO jvm.JvmMetrics: Initializing JVM Metrics with processName=JobTracker, sessionId=
java.net.ConnectException: Call From vagrant-ubuntu-trusty-64/10.0.2.15 to localhost:9000 failed on connection exception: java.net.ConnectException: Connection refused; For more details see:  http://wiki.apache.org/hadoop/ConnectionRefused
...

hduser3$ jps
1835 DataNode
2029 SecondaryNameNode
2168 Jps
```

こけた。何か足りない。  
一旦hdfsのディレクトリを削除してやり直す。

```
hduser3$ sbin/stop-dfs.sh
hduser3$ rm -rf /tmp/hadoop-hduser3/
hduser3$ bin/hdfs namenode -format
hduser3$ sbin/start-dfs.sh
hduser3$ jps
3080 DataNode
3285 SecondaryNameNode
3394 Jps
2909 NameNode

hduser3$ bin/hdfs dfs -mkdir /user
hduser3$ bin/hdfs dfs -mkdir /user/hduser3
hduser3$ bin/hdfs dfs -put etc/hadoop input

hduser3$ bin/hadoop jar share/hadoop/mapreduce/hadoop-mapreduce-examples-2.7.2.jar grep input output 'dfs[a-z.]+'

hduser3$ bin/hdfs dfs -ls /user/hduser3
Found 2 items
drwxr-xr-x   - hduser3 supergroup          0 2016-02-16 15:05 /user/hduser3/input
drwxr-xr-x   - hduser3 supergroup          0 2016-02-16 15:06 /user/hduser3/output

hduser3$ bin/hdfs dfs -get output output
hduser3$ ls output/
part-r-00000  _SUCCESS

hduser3$ cat output/part-r-00000 
4	dfs.class
4	dfs.audit.logger
3	dfs.server.namenode.
2	dfs.period
2	dfs.audit.log.maxfilesize
2	dfs.audit.log.maxbackupindex
1	dfsmetrics.log
1	dfsadmin
1	dfs.servers
1	dfs.replication
1	dfs.file
```

動いた。

## 備考
* 仮想マシンのメモリ割当を先にやっておくと、途中の手戻りがない
* adduserじゃなくてuseraddの場合、コマンドにオプションをつけないとホームディレクトリが作成されなかったりする(debian系の場合)
* 作業ディレクトリを外にするなら、hadoopインストールディレクトリのパスを通したりする
* start-dfs.shすると http://localhost:50070/ でwebのインターフェイスも参照できるが、Vagrantfileでport forwardの設定が必要

## 参考サイト
[Hadoop](http://hadoop.apache.org/)

[MapReduce Tutorial](http://hadoop.apache.org/docs/r2.7.2/hadoop-mapreduce-client/hadoop-mapreduce-client-core/MapReduceTutorial.html)