ちょっと後に使うかなと思いまして、CDHを使ってHDFS+YARNのDockerイメージを作ってみることにしました。
目標は、
- HDFSをインストール&起動
- YARNをインストール&起動
- クライアントもインストールし、HDFS/YARNが起動中のコンテナへ、別コンテナで起動したクライアントから接続できる
- ClouderaManagerは今回はパスして、自分でインストールする(ムダに頑張る)
という環境と手順の確立するところまで、とします。
Dockerの勉強も兼ねて、ということで…。
こういうのもあるらしいんですけどね。
https://github.com/sequenceiq/hadoop-docker
CDHを使ってのインストール手順
で、今回CDHを使ってインストールすると言ったわけですが、その前提条件をちょっと確認…。
Java Development Kit Installation
http://www.cloudera.com/content/cloudera/en/documentation/core/latest/topics/cdh_ig_jdk_installation.html
CDH Download Information
http://www.cloudera.com/content/cloudera/en/documentation/core/latest/topics/cdh_vd_cdh_download.html
OSは、CentOS 6.6のDockerイメージを選ぶことにします。
https://registry.hub.docker.com/_/centos/
今回は、「centos:6.6」を選びました。
あと、CDHでのHDFSおよびYARNのインストール方法自体は、こちらを参考に。
CDH4でhadoopのクラスタを構築する
http://qiita.com/toshiro3/items/cc3771735195b07cc00e
CDH自体は、5.4.4を選択します。
Dockerfileの作成
いろいろあって、作成したDockerfileはこのようになりました。
Dockerfile
FROM centos:6.6 ENV JDK_VERSION 7u79 ENV JDK_BUILD_NO b15 ENV JDK_RPM jdk-${JDK_VERSION}-linux-x64.rpm ENV JAVA_HOME /usr/java/default EXPOSE 8020 8030 8031 8032 8033 8040 8042 8089 10020 10033 13562 19888 40906 50010 50020 50070 50075 # -p 8020:8020 -p 8030:8030 -p 8031:8031 -p 8032:8032 -p 8033:8033 -p 8040:8040 -p 8042:8042 -p 8089:8089 -p 10020:10020 -p 10033:10033 -p 13562:13562 -p 19888:19888 -p 40906:40906 -p 50010:50010 -p 50020:50020 -p 50070:50070 -p 50075:50075 RUN yum install -y wget \ sudo && \ sed -ri 's/Defaults requiretty/Defaults:root !requiretty/' /etc/sudoers && \ wget -q -O /tmp/jdk.rpm --no-check-certificate --no-cookies --header "Cookie: oraclelicense=accept-securebackup-cookie" http://download.oracle.com/otn-pub/java/jdk/${JDK_VERSION}-${JDK_BUILD_NO}/${JDK_RPM} && \ rpm -ivh /tmp/jdk.rpm && \ wget -q -O /etc/yum.repos.d/cloudera-cdh5.repo http://archive.cloudera.com/cdh5/redhat/6/x86_64/cdh/cloudera-cdh5.repo && \ sed -ri 's/cdh\/5/cdh\/5.4.4/' /etc/yum.repos.d/cloudera-cdh5.repo && \ yum install -y hadoop \ hadoop-hdfs \ hadoop-hdfs-namenode \ hadoop-hdfs-secondarynamenode \ hadoop-hdfs-datanode \ hadoop-yarn \ hadoop-yarn-resourcemanager \ hadoop-yarn-nodemanager \ hadoop-mapreduce \ hadoop-mapreduce-historyserver \ hadoop-client RUN cp -Rp /etc/hadoop/conf.empty /etc/hadoop/conf.mine && \ alternatives --install /etc/hadoop/conf hadoop-conf /etc/hadoop/conf.mine 50 && \ alternatives --set hadoop-conf /etc/hadoop/conf.mine && \ mkdir -p /var/lib/hadoop-hdfs/cache/hdfs/name && \ chown -R hdfs.hdfs /var/lib/hadoop-hdfs/cache/hdfs/name && \ chmod 775 /var/lib/hadoop-hdfs/cache/hdfs/name && \ mkdir -p /var/lib/hadoop-hdfs/cache/hdfs/dfs && \ chown -R hdfs.hdfs /var/lib/hadoop-hdfs/cache/hdfs/dfs && \ chmod 775 /var/lib/hadoop-hdfs/cache/hdfs/dfs && \ mkdir -p /var/lib/hadoop-hdfs/cache/hdfs/tmp && \ chown -R hdfs.hdfs /var/lib/hadoop-hdfs/cache/hdfs/dfs && \ chmod 775 /var/lib/hadoop-hdfs/cache/hdfs/dfs ADD core-site.xml /etc/hadoop/conf.mine/core-site.xml ADD hdfs-site.xml /etc/hadoop/conf.mine/hdfs-site.xml ADD mapred-site.xml /etc/hadoop/conf.mine/mapred-site.xml ADD yarn-site.xml /etc/hadoop/conf.mine/yarn-site.xml ADD fix-hostname.sh fix-hostname.sh ADD init-and-start.sh init-and-start.sh RUN chmod a+x fix-hostname.sh RUN chmod a+x init-and-start.sh CMD ./init-and-start.sh && tail -f /dev/null
やっていることは、まずはOracle JDKのインストール、Clouderaのyumリポジトリの追加。
インストールされるCDHは、5.4.4固定にしました。
sed -ri 's/cdh\/5/cdh\/5.4.4/' /etc/yum.repos.d/cloudera-cdh5.repo && \
それから各種インストール。
yum install -y hadoop \ hadoop-hdfs \ hadoop-hdfs-namenode \ hadoop-hdfs-secondarynamenode \ hadoop-hdfs-datanode \ hadoop-yarn \ hadoop-yarn-resourcemanager \ hadoop-yarn-nodemanager \ hadoop-mapreduce \ hadoop-mapreduce-historyserver \ hadoop-client
設定ファイルは、/etc/hadoop/conf.emptyから/etc/hadoop/conf.mineというディレクトリにコピーして、こちらを使うように設定しました。
RUN cp -Rp /etc/hadoop/conf.empty /etc/hadoop/conf.mine && \ alternatives --install /etc/hadoop/conf hadoop-conf /etc/hadoop/conf.mine 50 && \ alternatives --set hadoop-conf /etc/hadoop/conf.mine && \
設定ファイルと起動スクリプトの追加。
ADD core-site.xml /etc/hadoop/conf.mine/core-site.xml ADD hdfs-site.xml /etc/hadoop/conf.mine/hdfs-site.xml ADD mapred-site.xml /etc/hadoop/conf.mine/mapred-site.xml ADD yarn-site.xml /etc/hadoop/conf.mine/yarn-site.xml ADD fix-hostname.sh fix-hostname.sh ADD init-and-start.sh init-and-start.sh RUN chmod a+x fix-hostname.sh RUN chmod a+x init-and-start.sh
利用ポートをEXPOSE。
EXPOSE 8020 8030 8031 8032 8033 8040 8042 8089 10020 10033 13562 19888 40906 50010 50020 50070 50075
デフォルトはNameNodeなどの各種サービスを起動するようにしていますが、bashでログインして使ったりもするのでENTRYPOINTは今回はやめておくことにします。
CMD ./init-and-start.sh && tail -f /dev/null
「tail -f /dev/null」しているのは、フォアグラウンドなっていて欲しいから…。
Dockerfileはここまで。
設定ファイルと起動スクリプト
Dockerfileの中でADDしていた各種設定ファイルは、こんな感じ。
core-site.xml
<?xml version="1.0" encoding="UTF-8"?> <?xml-stylesheet type="text/xsl" href="configuration.xsl"?> <configuration> <property> <name>fs.defaultFS</name> <value>hdfs://localhost:8020</value> </property> </configuration>
<?xml version="1.0" encoding="UTF-8"?> <?xml-stylesheet type="text/xsl" href="configuration.xsl"?> <configuration> <property> <name>dfs.replication</name> <value>1</value> </property> <property> <name>hadoop.tmp.dir</name> <value>file:///var/lib/hadoop-hdfs/cache/hdfs/dfs/tmp</value> </property> <property> <name>dfs.namenode.name.dir</name> <value>file:///var/lib/hadoop-hdfs/cache/hdfs/dfs/name</value> </property> <property> <name>dfs.datanode.data.dir</name> <value>file:///var/lib/hadoop-hdfs/cache/hdfs/dfs/data</value> </property> </configuration>
mapred-site.xml
<?xml version="1.0" encoding="UTF-8"?> <?xml-stylesheet type="text/xsl" href="configuration.xsl"?> <configuration> <property> <name>mapreduce.framework.name</name> <value>yarn</value> </property> <property> <name>mapreduce.jobhistory.address</name> <value>localhost:10020</value> </property> <property> <name>mapreduce.jobhistory.webapp.address</name> <value>localhost:19888</value> </property> <property> <name>yarn.app.mapreduce.am.staging-dir</name> <value>/tmp/hadoop-yarn/staging</value> </property> </configuration>
yarn-site.xml
<?xml version="1.0" encoding="UTF-8"?> <?xml-stylesheet type="text/xsl" href="configuration.xsl"?> <configuration> <property> <name>yarn.nodemanager.aux-services</name> <value>mapreduce_shuffle</value> </property> <property> <name>yarn.nodemanager.aux-services.mapreduce_shuffle.class</name> <value>org.apache.hadoop.mapred.ShuffleHandler</value> </property> <property> <name>yarn.log-aggregation-enable</name> <value>true</value> </property> <property> <name>yarn.resourcemanager.address</name> <value>localhost:8032</value> </property> <property> <name>yarn.resourcemanager.scheduler.address</name> <value>localhost:8030</value> </property> <property> <name>yarn.resourcemanager.resource-tracker.address</name> <value>localhost:8031</value> </property> <property> <name>yarn.resourcemanager.admin.address</name> <value>localhost:8033</value> </property> <property> <name>yarn.resourcemanager.webapp.address</name> <value>localhost:8089</value> </property> <property> <description>List of directories to store localized files in.</description> <name>yarn.nodemanager.local-dirs</name> <value>file:///var/lib/hadoop-yarn/cache/${user.name}/nm-local-dir</value> </property> <property> <description>Where to store container logs.</description> <name>yarn.nodemanager.log-dirs</name> <value>file:///var/log/hadoop-yarn/containers</value> </property> <property> <description>Where to aggregate logs to.</description> <name>yarn.nodemanager.remote-app-log-dir</name> <value>hdfs://localhost:8020/var/log/hadoop-yarn/apps</value> </property> <property> <description>Classpath for typical applications.</description> <name>yarn.application.classpath</name> <value> $HADOOP_CONF_DIR, $HADOOP_COMMON_HOME/*,$HADOOP_COMMON_HOME/lib/*, $HADOOP_HDFS_HOME/*,$HADOOP_HDFS_HOME/lib/*, $HADOOP_MAPRED_HOME/*,$HADOOP_MAPRED_HOME/lib/*, $HADOOP_YARN_HOME/*,$HADOOP_YARN_HOME/lib/* </value> </property> </configuration>
ほとんど参考サイトのまんまなんですけど。意味がよくわかっていないところも多いので、不要な設定が入っているかも…。
ホスト名は「localhost」としていますが、後のスクリプトで書き換えます。
CMDで指定していた起動スクリプト。HDFSのフォーマットも含めています。
init-and-start.sh
#!/bin/bash sh fix-hostname.sh ## Initialize HDFS. sudo -u hdfs hdfs namenode -format ## Startup HDFS Process. service hadoop-hdfs-namenode start service hadoop-hdfs-datanode start # service hadoop-hdfs-secondarynamenode start ## Startup Yarn Process. service hadoop-yarn-resourcemanager start service hadoop-yarn-nodemanager start ## create tmp directory. sudo -u hdfs hdfs dfs -mkdir /tmp sudo -u hdfs hdfs dfs -chmod 777 /tmp service hadoop-mapreduce-historyserver start
SecondaryNameNodeは、うちの環境ではメモリ不足でYARNと合わせると足かせになったので、やめました…。
tmpディレクトリだけは、しれっと作っています。
## create tmp directory. sudo -u hdfs hdfs dfs -mkdir /tmp sudo -u hdfs hdfs dfs -chmod 777 /tmp
あと、ホスト名を修正するスクリプトを仕込んでいます。
fix-hostname.sh
#!/bin/bash if [ "$1" == "" ]; then TARGET_HOSTNAME=$HOSTNAME else TARGET_HOSTNAME=$1 fi # fix hostname sed -ri s/localhost/$TARGET_HOSTNAME/ /etc/hadoop/conf.mine/core-site.xml sed -ri s/localhost/$TARGET_HOSTNAME/ /etc/hadoop/conf.mine/hdfs-site.xml sed -ri s/localhost/$TARGET_HOSTNAME/ /etc/hadoop/conf.mine/mapred-site.xml sed -ri s/localhost/$TARGET_HOSTNAME/ /etc/hadoop/conf.mine/yarn-site.xml
Dockerイメージのビルド
以下のコマンドで、ビルド。
$ docker build -t kazuhira/centos6-cdh5:5.4.4 .
HDFS&YARNの起動
では、ビルドしたDockerイメージからコンテナを起動してみます。
$ docker run -d --name cdh-yarn -p 8020:8020 -p 8030:8030 -p 8031:8031 -p 8032:8032 -p 8033:8033 -p 8040:8040 -p 8042:8042 -p 8089:8089 -p 10020:10020 -p 10033:10033 -p 13562:13562 -p 19888:19888 -p 40906:40906 -p 50010:50010 -p 50020:50020 -p 50070:50070 -p 50075:50075 kazuhira/centos6-cdh5:5.4.4
めっちゃポートの指定がありますが…。
コンテナの名前は、「cdh-yarn」としました。このコンテナ内で、NameNode、DataNode、ResourceManager、NodeManagerが起動しています。
クライアントから接続する
続いて、クライアント側から接続してみます。別のコンテナからつなぎますよ、と。
$ docker run -it --rm --link cdh-yarn --name cdh-yarn-client kazuhira/centos6-cdh5:5.4.4 bash
クライアントでは、HDFSやYARNは起動しません。
この時、先ほど起動しておいたコンテナとlinkしておきます。
--link cdh-yarn
linkしておくと、hostsファイルにlinkしたホストの情報が書かれるらしいので
# cat /etc/hosts 172.17.0.13 e7ab9b1da65d 127.0.0.1 localhost ::1 localhost ip6-localhost ip6-loopback fe00::0 ip6-localnet ff00::0 ip6-mcastprefix ff02::1 ip6-allnodes ff02::2 ip6-allrouters 172.17.0.12 cdh-yarn 4935efc1c6cc
この情報を使って、クライアント側の設定ファイル内のホスト名を修正します。
# ./fix-hostname.sh 4935efc1c6cc
ちょっとディレクトリを作ってみます。
# su - hdfs $ hdfs dfs -mkdir /user $ hdfs dfs -chmod 777 /user
1度hdfsユーザーを抜けて、今度はmapredユーザーへ。
# su - mapred
サンプルを実行してみましょう。
$ yarn jar /usr/lib/hadoop-mapreduce/hadoop-mapreduce-examples-2.6.0-cdh5.4.4.jar pi 5 300
なんか、動き出します…。
Number of Maps = 5 Samples per Map = 300 Wrote input for Map #0 Wrote input for Map #1 Wrote input for Map #2 Wrote input for Map #3 Wrote input for Map #4 Starting Job 15/07/30 12:37:14 INFO client.RMProxy: Connecting to ResourceManager at 4935efc1c6cc/172.17.0.12:8032 15/07/30 12:37:15 INFO input.FileInputFormat: Total input paths to process : 5 15/07/30 12:37:15 INFO mapreduce.JobSubmitter: number of splits:5 15/07/30 12:37:15 INFO mapreduce.JobSubmitter: Submitting tokens for job: job_1438259518400_0001 15/07/30 12:37:16 INFO impl.YarnClientImpl: Submitted application application_1438259518400_0001 15/07/30 12:37:16 INFO mapreduce.Job: The url to track the job: http://4935efc1c6cc:8089/proxy/application_1438259518400_0001/ 15/07/30 12:37:16 INFO mapreduce.Job: Running job: job_1438259518400_0001 15/07/30 12:37:23 INFO mapreduce.Job: Job job_1438259518400_0001 running in uber mode : false 15/07/30 12:37:23 INFO mapreduce.Job: map 0% reduce 0% 15/07/30 12:37:28 INFO mapreduce.Job: map 20% reduce 0% 15/07/30 12:37:29 INFO mapreduce.Job: map 40% reduce 0% 15/07/30 12:37:30 INFO mapreduce.Job: map 60% reduce 0% 15/07/30 12:37:31 INFO mapreduce.Job: map 80% reduce 0% 15/07/30 12:37:32 INFO mapreduce.Job: map 100% reduce 0% 15/07/30 12:37:34 INFO mapreduce.Job: map 100% reduce 100% 15/07/30 12:37:34 INFO mapreduce.Job: Job job_1438259518400_0001 completed successfully 15/07/30 12:37:34 INFO mapreduce.Job: Counters: 49 File System Counters FILE: Number of bytes read=116 FILE: Number of bytes written=654903 FILE: Number of read operations=0 FILE: Number of large read operations=0 FILE: Number of write operations=0 HDFS: Number of bytes read=1345 HDFS: Number of bytes written=215 HDFS: Number of read operations=23 HDFS: Number of large read operations=0 HDFS: Number of write operations=3 Job Counters Launched map tasks=5 Launched reduce tasks=1 Data-local map tasks=5 Total time spent by all maps in occupied slots (ms)=16396 Total time spent by all reduces in occupied slots (ms)=2785 Total time spent by all map tasks (ms)=16396 Total time spent by all reduce tasks (ms)=2785 Total vcore-seconds taken by all map tasks=16396 Total vcore-seconds taken by all reduce tasks=2785 Total megabyte-seconds taken by all map tasks=16789504 Total megabyte-seconds taken by all reduce tasks=2851840 Map-Reduce Framework Map input records=5 Map output records=10 Map output bytes=90 Map output materialized bytes=140 Input split bytes=755 Combine input records=0 Combine output records=0 Reduce input groups=2 Reduce shuffle bytes=140 Reduce input records=10 Reduce output records=0 Spilled Records=20 Shuffled Maps =5 Failed Shuffles=0 Merged Map outputs=5 GC time elapsed (ms)=209 CPU time spent (ms)=3180 Physical memory (bytes) snapshot=1627062272 Virtual memory (bytes) snapshot=8320311296 Total committed heap usage (bytes)=1495793664 Shuffle Errors BAD_ID=0 CONNECTION=0 IO_ERROR=0 WRONG_LENGTH=0 WRONG_MAP=0 WRONG_REDUCE=0 File Input Format Counters Bytes Read=590 File Output Format Counters Bytes Written=97 Job Finished in 19.749 seconds Estimated value of Pi is 3.15200000000000000000
とりあえず、動いたようです。
最初、SecondaryNameNodeがいた状態だとメモリが足りなかったらしくて、サンプルの実行に10分くらいかかっていたのですが…SecondaryNameNodeがなくなったら、とりあえず動くようになりました…。
ギリギリですね。
その他にもいろいろ苦労したのですが、なんとかやってみたかったところまで通せてよかったです。
今度同じようなことをやる時は、ClouderaManagerを使った方がいいのかもしれないなぁと思いました…。