Cloudera Quickstart VM に外部からHDFS接続する

Cloudera Quickstart VM (以下VM) は、デフォルトで `127.0.0.1` をホスト名 `quickstart.cloudera` と紐付けているため、このままでは VM 外(例えばMac自身)からの HDFS への接続を行うことができない。すなわち、データの入出力を行うことができない。(REST APIなどを使えば一応可能)
本記事では、VMに外部からHDFS接続する方法について説明する。

問題の背景に興味がなく問題解決だけしたい人は「対処法」まで読めばいい。なぜこういう挙動なのか知りたい人は「技術背景」を参照すること。

# 環境

* OS: Mac OS X 10.10.3
* Cloudera Quickstart VM: C5.4
* VMWare Fusion 6

# 準備

Cloudera Quickstart VM の概要及びインストール方法については、[CodeZineの連載記事「フリーのVM環境を使って、ビッグデータ分析の学習環境をすばやく構築する」](http://codezine.jp/article/detail/8560)を参照のこと。

# 対処法

## ネットワーク設定の変更

`/etc/udev/rules.d/70-persistent-net.rules` を編集し、 eth0 と eth1 を入れ替える。

```Text:変更前
# PCI device 0xXZ:0x100f (e1000)
SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ATTR{address}=="XX:XX:XX:XX:XX:XX", ATTR{type}=="1", KERNEL=="eth*", NAME="eth0"

# PCI device 0x8086:0x100f (e1000)
SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ATTR{address}=="XX:XX:XX:XX:XX:XX", ATTR{type}=="1", KERNEL=="eth*", NAME="eth1"
```

```Text:変更前
# PCI device 0xXZ:0x100f (e1000)
SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ATTR{address}=="XX:XX:XX:XX:XX:XX", ATTR{type}=="1", KERNEL=="eth*", NAME="eth1"

# PCI device 0x8086:0x100f (e1000)
SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ATTR{address}=="XX:XX:XX:XX:XX:XX", ATTR{type}=="1", KERNEL=="eth*", NAME="eth0"
```

## VM再起動

次にVMを再起動する。
再起動後、`ifconfig` コマンドの実行により `eth0` が表示されていて、かつ `/etc/hosts` で　`quickstart.cloudera` がローカルアドレス `127.0.0.1` 以外に紐付けられていれば成功である。

```Text:ifconfigの結果
[cloudera@quickstart ~]$ ifconfig
eth0      Link encap:Ethernet  HWaddr 00:0C:29:F9:A7:2F
          inet addr:172.16.XXX.XXX  Bcast:172.16.146.255  Mask:255.255.255.0
```

```Text:/etc/hosts
127.0.0.1	localhost	localhost.domain
172.16.XXX.XXX	quickstart.cloudera	quickstart
```

## Cloudera Manager のサービス再起動

Cloudera Manager のサービスが `127.0.0.1` として紐付けられている場合があるので、その場合はサービスの再起動を行う。分からない場合は再起動してしまった方が安全。

### Cloudera 管理サービスの再起動

ホームページから添付の図の通りに再起動を行う。

![Cloudera管理サービスの再起動.png](https://qiita-image-store.s3.amazonaws.com/0/17749/5f7453b0-8bdd-4a73-4a17-6f2b15853c92.png)

### CDH サービスの再起動とクライアント設定の展開

下図の通り、サービス再起動及びクライアント設定の展開を行う。順番は前後しても構わないが、**サービス再起動中に設定の展開を行わないこと**。(エラーになる)

![CDHサービスメニュー.png](https://qiita-image-store.s3.amazonaws.com/0/17749/6ae388e6-3b68-e750-062b-fa7132c00c0d.png)


# 技術背景

## データ読み書き時のHDFSの仕組み(概略)

HDFSは、マスターサーバである NameNode (以下NN)1台(HA構成時もアクティブは1台)、ワーカーサーバである DataNode (以下DN)1台以上からなる分散ファイルシステムを提供するためのサービスである。
NNは、分散ファイルシステム上の名前空間とDNに物理的に保存されているデータとのマップ情報をメモリ上に保持している。
このとき、NNはDNのUUIDをマップ情報として記録している。かつてはDNのIPアドレスを直接ブロックに対して紐付けていたが、ヘテロジニアスストレージサポートのための変更の一環である[HDFS-5448](https://issues.apache.org/jira/browse/HDFS-5448)、[HDFS-5233](https://issues.apache.org/jira/browse/HDFS-5233)によってUUIDとブロックを紐付けるようになった。
データの新規書き込み時にはおおまかには以下のようなフローで処理が行われる。

1. クライアントはNNに問い合わせ、書き込み先要求を行う。
2. 書き込み可能だった場合、NNは書き込み先のパスを新たに作成し、そのパスに書き込むデータを保存するDNのIPアドレスをクライアントに返す。
3. クライアントは取得したIPアドレスのDNに対し、データブロックの転送を行う。


### See Also

読み書きの流れの基本については[オライリー・ジャパン「Hadoop」](http://www.oreilly.co.jp/books/9784873116297/)等を参照のこと。UUIDベースではないものの、大体の流れは変わっていない。最新の仕様については[HDFS-2832](https://issues.apache.org/jira/browse/HDFS-2832)の[設計書](https://issues.apache.org/jira/secure/attachment/12615761/20131125-HeterogeneousStorage.pdf)を参照のこと。

## で、なんで外部から接続できないの？

上記の仕組みの通り、DNのIPアドレスがローカルアドレスとして認識されている限り、外部からデータの書き込み要求を行っても必ず失敗する。NATによってNNに接続できるだけでは問題を解決できない。

## Cloudera Quickstart VM におけるネットワーク設定の仕組み

先述の通り、Cloudera Quickstart VM ではデフォルトでホスト名を `127.0.0.1` に紐付ける。これは以下のような仕組みで行われる。

Quickstart VM は、起動時に特別な初期化スクリプト `/etc/init.d/cloudera-quickstart-init` を実行する。このスクリプト内で、 `/usr/bin/cloudera-quickstart-ip` というコマンドを呼び出す。このコマンドは `eth0` のIPアドレスを確認し、そのアドレスにホスト名を紐付けて `/etc/hosts` を生成する。 `eth0` が設定されていない場合は `127.0.0.1` を使う。ところが、Quickstart VM はデフォルトで `eth1` を外部接続用ネットワークとして設定するため、 `eth0` は未設定となっている。これが `127.0.0.1` がホスト名に紐付けられる仕組みである。

## 間違った対処法

上記の仕組みから、 `/etc/hosts` だけを修正しても根本的な解決にならないことがわかる。再起動すれば元に戻ってしまうからだ。


# 謝辞

* [kernel023](http://qiita.com/kernel023)
* [d1ce_](http://qiita.com/d1ce_)