HadoopをDockerコンテナで動かす

公式ドキュメントを見ながらDockerイメージをセットアップしていく。

Javaをインストールする

+FROM openjdk:8
  • openjdkをベースイメージにする。
  • ドキュメントを見ると、Hadoop 3.xだとJava 8しかサポートしていないとのことだったので、openjdk:8を使う。

sshdを起動する

Required Softwareの項目を見ると、Javaの他にsshを必要としている。また、pdshも推奨されている。

 FROM openjdk:8
+RUN apt-get update \
+  && apt-get install -y --no-install-recommends ssh pdsh \
+  && apt-get clean \
+  && rm -rf /var/lib/apt/lists/*
+RUN mkdir /run/sshd
+CMD ["/usr/sbin/sshd"]
  • apt-getでsshとpdshをインストールする。イメージサイズを減らす工夫もしてある。
  • sshdが必要とするディレクトリを作ってからsshdを起動する。

Hadoopをダウンロードする

 FROM openjdk:8
 RUN apt-get update \
   && apt-get install -y --no-install-recommends ssh pdsh \
   && apt-get clean \
   && rm -rf /var/lib/apt/lists/*
 RUN mkdir /run/sshd
+RUN wget -q -O - http://ftp.yz.yamagata-u.ac.jp/pub/network/apache/hadoop/common/hadoop-3.2.1/hadoop-3.2.1.tar.gz | tar zxf -
+ENV PATH=/hadoop-3.2.1/bin:$PATH
 CMD ["/usr/sbin/sshd"]
  • ミラーサイトからHadoopをダウンロードする。

スタンドアロンモード

この時点でスタンドアロンモードで動作確認ができる。

% docker build -t naoty/hello-hadoop .
% docker run --rm -it naoty/hello-hadoop bash

ドキュメントに載っているスタンドアロンモードの動作確認をおこなう。

% cd /hadoop-3.2.1
% mkdir input
% cp etc/hadoop/*.xml input
% bin/hadoop jar share/hadoop/mapreduce/hadoop-mapreduce-examples-3.2.1.jar grep input output 'dfs[a-z.]+'
% cat output/*

疑似分散モード

設定

疑似分散モードに必要な設定を追加する。設定ファイルをコンテナからローカルにコピーして編集する。

<!-- config/core-site.xml -->
<configuration>
  <property>
    <name>fs.defaultFS</name>
    <value>hdfs://localhost:9000</value>
  </property>
</configuration>
<!-- config/hdfs-site.xml -->
<configuration>
  <property>
    <name>dfs.replication</name>
    <value>1</value>
  </property>
</configuration>
 FROM openjdk:8
 RUN apt-get update \
   && apt-get install -y --no-install-recommends ssh pdsh \
   && apt-get clean \
   && rm -rf /var/lib/apt/lists/*
 RUN mkdir /run/sshd
 RUN wget -q -O - http://ftp.yz.yamagata-u.ac.jp/pub/network/apache/hadoop/common/hadoop-3.2.1/hadoop-3.2.1.tar.gz | tar zxf -
 ENV PATH=/hadoop-3.2.1/bin:/hadoop-3.2.1/sbin:$PATH
+COPY config /hadoop-3.2.1/etc/hadoop/
 CMD ["/usr/sbin/sshd"]

localhostにsshできるようにする

 FROM openjdk:8
 RUN apt-get update \
   && apt-get install -y --no-install-recommends ssh pdsh \
   && apt-get clean \
   && rm -rf /var/lib/apt/lists/*
-RUN mkdir /run/sshd
+RUN mkdir /run/sshd \
+  && ssh-keygen -t rsa -P '' -f ~/.ssh/id_rsa \
+  && cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys \
+  && chmod 0600 ~/.ssh/authorized_keys
 RUN wget -q -O - http://ftp.yz.yamagata-u.ac.jp/pub/network/apache/hadoop/common/hadoop-3.2.1/hadoop-3.2.1.tar.gz | tar zxf -
 ENV PATH=/hadoop-3.2.1/bin:$PATH
 COPY config /hadoop-3.2.1/etc/hadoop/
 CMD ["/usr/sbin/sshd"]

動作確認

% docker build -t naoty/hello-hadoop .
% docker run --rm -it naoty/hello-hadoop bash

公式ドキュメントにある通りに疑似分散モードの動作確認をおこなう。

% /usr/sbin/sshd
% hdfs namenode -format
% start-dfs.sh
Starting namenodes on [localhost]
ERROR: Attempting to operate on hdfs namenode as root
ERROR: but there is no HDFS_NAMENODE_USER defined. Aborting operation.
Starting datanodes
ERROR: Attempting to operate on hdfs datanode as root
ERROR: but there is no HDFS_DATANODE_USER defined. Aborting operation.
Starting secondary namenodes [2ce45712f331]
ERROR: Attempting to operate on hdfs secondarynamenode as root
ERROR: but there is no HDFS_SECONDARYNAMENODE_USER defined. Aborting operation.

Hadoopが利用する環境変数を設定するため、コンテナからhadoop-env.shをコピーして環境変数を追加する。

% docker cp xxxxxxx:/hadoop-3.2.1/etc/hadoop/hadoop-env.sh config/
+export HDFS_NAMENODE_USER=root
+export HDFS_DATANODE_USER=root
+export HDFS_SECONDARYNAMENODE_USER=root

もう一回動作確認する。

% start-dfs.sh
Starting namenodes on [localhost]
ERROR: JAVA_HOME is not set and could not be found.

JAVA_HOMEをOpenJDKのホームディレクトリに設定する。

+export JAVA_HOME=/usr/local/openjdk-8

もう一回動作確認する。

% start-dfs.sh
Starting namenodes on [localhost]
pdsh@098622af1ce0: localhost: connect: Connection refused

stack overflowによると、pdshを使わなければエラーにならないとのことなので、pdshは削除する。

 FROM openjdk:8
 RUN apt-get update \
-  && apt-get install -y --no-install-recommends ssh pdsh \
+  && apt-get install -y --no-install-recommends ssh \
   && apt-get clean \
   && rm -rf /var/lib/apt/lists/*
 RUN mkdir /run/sshd
 RUN mkdir /run/sshd \
   && ssh-keygen -t rsa -P '' -f ~/.ssh/id_rsa \
   && cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys \
   && chmod 0600 ~/.ssh/authorized_keys
 RUN wget -q -O - http://ftp.yz.yamagata-u.ac.jp/pub/network/apache/hadoop/common/hadoop-3.2.1/hadoop-3.2.1.tar.gz | tar zxf -
 ENV PATH=/hadoop-3.2.1/bin:$PATH
 COPY config /hadoop-3.2.1/etc/hadoop/
 CMD ["/usr/sbin/sshd"]

動作確認する。

% start-dfs.sh
Starting namenodes on [localhost]
Starting datanodes
Starting secondary namenodes [098622af1ce0]
098622af1ce0: Host key verification failed.

stack overflowによると、HADOOP_OPTSに手を加えるとよいとのことだったのでhadoop-env.shを修正する。

+export HADOOP_OPTS="${HADOOP_OPTS} -XX:-PrintWarnings -Djava.net.preferIPv4Stack=true"

動作確認する。

% start-dfs.sh
Starting namenodes on [localhost]
localhost: Warning: Permanently added 'localhost' (ECDSA) to the list of known hosts.
Starting datanodes
Starting secondary namenodes [1a7271d1d014]
1a7271d1d014: Warning: Permanently added '1a7271d1d014,172.17.0.2' (ECDSA) to the list of known hosts.

うまくいった。動作確認を続ける。

% bin/hdfs dfs -mkdir /user
% bin/hdfs dfs -mkdir /user/root
% bin/hdfs dfs -mkdir input
% bin/hdfs dfs -put etc/hadoop/*.xml input
% bin/hadoop jar share/hadoop/mapreduce/hadoop-mapreduce-examples-3.2.1.jar grep input output 'dfs[a-z.]+'
% bin/hdfs dfs -cat output/*

動作確認ができた。

起動スクリプト

Hadoopの起動にはsshdとNameNode, DataNodeの起動が必要になるため、それらを起動するためのスクリプトをつくる。

#!/bin/bash

/usr/sbin/sshd
start-dfs.sh

# daemonize
while true; do
  sleep 1000
done

start-dfs.shはデーモンを起動するだけのスクリプトなので、無限ループを実行してコンテナが終了しないようにしている。

また、NameNodeのフォーマットはビルド時におこなうようにする。

 FROM openjdk:8
 RUN apt-get update \
   && apt-get install -y --no-install-recommends ssh \
   && apt-get clean \
   && rm -rf /var/lib/apt/lists/*
 RUN mkdir /run/sshd \
   && ssh-keygen -t rsa -P '' -f ~/.ssh/id_rsa \
   && cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys \
   && chmod 0600 ~/.ssh/authorized_keys
 RUN wget -q -O - http://ftp.yz.yamagata-u.ac.jp/pub/network/apache/hadoop/common/hadoop-3.2.1/hadoop-3.2.1.tar.gz | tar zxf -
 ENV PATH=/hadoop-3.2.1/bin:/hadoop-3.2.1/sbin:$PATH
 COPY config /hadoop-3.2.1/etc/hadoop/
+RUN hdfs namenode -format
+COPY start /
-CMD ["/usr/sbin/sshd"]
+CMD ["/start"]
% docker build -t naoty/hello-hadoop .
% docker run --rm -it -p 9870:9870 naoty/hello-hadoop

NameNodeは9870番ポートでUIを提供しているのでポートフォワーディングを設定してlocalhost:9870から確認できるようになった。