那么,问题来了!
有没有更有可行性的办法?提到虚拟化, Docker 最近很是火热!不妨拿来在本地做虚拟化,搭建Hadoop的伪分布式集群环境。虽然有点大材小用,但是学习学习,练练手也是极好的。
文章比较长,建议先倒杯水,听我慢慢到来……
先说一下我的思路吧:
先使用Docker构建一个Hadoop运行环境的镜像然后使用这个镜像分别启动3个容器:1个Master节点,两个Slave节点在Master节点上配置Slave节点信息在Master上启动Hadoop使用Docker搭建Hadoop环境什么是 Docker?
Docker 是一个开源项目,诞生于 2013 年初,最初是 dotCloud 公司内部的一个业余项目。它基于 Google 公司推出的 Go 语言实现。 项目后来加入了 Linux 基金会,遵从了 Apache 2.0 协议,项目代码在 GitHub 上进行维护。
Docker 自开源后受到广泛的关注和讨论,以至于 dotCloud 公司后来都改名为 Docker Inc。Redhat 已经在其 RHEL6.5 中集中支持 Docker;Google 也在其 PaaS 产品中广泛应用。
Docker 项目的目标是实现轻量级的操作系统虚拟化解决方案。 Docker 的基础是 Linux 容器(LXC)等技术。
在 LXC 的基础上 Docker 进行了进一步的封装,让用户不需要去关心容器的管理,使得操作更为简便。用户操作 Docker 的容器就像操作一个快速轻量级的虚拟机一样简单。
Docker安装我使用的是Ubuntu14.04,命令如下:
$ sudo apt-get install apt-transport-https$ sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 36A1D7869245C8950F966E92D8576A8BA88D21E9$ sudo bash -c "echo deb https://get.docker.io/ubuntu docker main > /etc/apt/sources.list.d/docker.list"$ sudo apt-get update$ sudo apt-get install lxc-docker其余系统或其他版本,请参考 这里 。
Docker常用命令介绍docker images :列出所有镜像(images)docker ps :列出正在运行的(容器)containersdocker pull ubuntu :下载镜像docker run -i -t ubuntu /bin/bash :运行ubuntu镜像docker commit 3a09b2588478 ubuntu:mynewimage :提交你的变更,并且把容器保存成Tag为mynewimage的新的ubuntu镜像.(注意,这里提交只是提交到本地仓库,类似git)其他常用命令,参考 这里 。
Docker去sudo在Ubuntu下,在执行Docker时,每次都要输入sudo,同时输入密码,这里把当前用户执行权限添加到相应的docker用户组里面。
# 添加一个新的docker用户组sudo groupadd docker# 添加当前用户到docker用户组里,注意这里的king为ubuntu登录用户名sudo gpasswd -a king docker# 重启Docker后台监护进程sudo service docker restart# 重启之后,尝试一下,是否生效docker version#若还未生效,则系统重启,则生效sudo reboot下载Ubuntu镜像docker pull ubuntu:14.04这条命令的作用是从Docker仓库中获取ubuntu的镜像,参考 这里 。
下载完成以后,使用 docker images ,可以列出所有本地的镜像:
king@king:~$ docker images REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZEubuntu 14.04 5ba9dab47459 4 weeks ago 188.3 MBubuntu 14.04.1 5ba9dab47459 4 weeks ago 188.3 MBubuntu latest 5ba9dab47459 4 weeks ago 188.3 MBubuntu trusty 5ba9dab47459 4 weeks ago 188.3 MB启动第一个容器下面,我们准备以ubuntu镜像作为基准镜像,构建我们的Hadoop运行环境镜像。
先使用命令如下命令启动容器:
docker run -ti ubuntu注意:我们在不指定Tag的情况下,默认选择Tag为 latest 的镜像启动容器。 指定Tag启动命令为:
docker run -ti ubuntu:14.04另外,每次容器启动的时候需要指定一个命令,容器启动后便会执行这个命令。例如执行下面的命令:
king@king:~$ docker run ubuntu /bin/echo 'Hello world'Hello worldking@king:~$可以看到,容器启动了马上又退出了,因为容器之做了一件事情:就是打印 Hello world ,打印完了,自然就退出了。
如果你想做多件事情,可以自己写一个shell脚本,把你要的操作写入进去,然后在 run 后面指定这个脚本路径。
我们刚刚的 docker run -ti ubuntu 命令中没有指定执行程序,Docker默认执行 /bin/bash 。
其他启动参数,大家可以自己在网上查,这里不再陈述了。好了我们回到刚刚 docker run -ti ubuntu 启动的容器,可以看到容器几乎瞬间就启动起来了,比虚拟机不知快了多少倍!!
king@king:~$ docker run -ti ubunturoot@009fe5728aba:/#容器启动起来了,接下来就是安装Java、Hadoop及相关配置了。
Java安装依次执行如下命令:
sudo apt-get install software-properties-common python-software-propertiessudo add-apt-repository ppa:webupd8team/javasodu apt-get updateapt-get install oracle-java7-installerjava -version注意:
这里安装的Java7(JDK1.7),如需其他版本请自行修改 apt-get install oracle-java7-installer 为 apt-get install oracle-java6-installer默认使用的是Ubuntu的官方源,如果下载比较慢,请自行修改更新源,不知道如何使用命令行修改的,参考 这里 。另外,大家可以将装好java的镜像保存为一个副本,他日可以在此基础上构建其他镜像。命令如下:
root@122a2cecdd14:~# exitdocker commit -m "java install" 122a2cecdd14 ubuntu:java上面命令中 122a2cecdd14 为当前容器的ID, ubuntu:java 是为新的镜像指定一个标识, ubuntu 为 仓库名 , java 是 Tag 。
如何获取容器ID:
有个简便的办法找到此ID,就是命令行用户名 @ 后面的那一串字符。这个方法只在容器启动时没有指定hostname时才能用。使用 docker ps 列出所有运行的容器,在命令结果中查看Hadoop安装渐渐切入正题了O(∩_∩)O~
使用刚刚已经安装了Java的容器镜像启动:
docker run -ti ubuntu:java启动成功了,我们开始安装Hadoop。这里,我们直接使用wget下载安装文件。
1.先安装wget:
sudo apt-get install -y wget2.下载并解压安装文件:
root@8ef06706f88d:cd ~root@8ef06706f88d:~# mkdir softroot@8ef06706f88d:~# cd soft/root@8ef06706f88d:~/soft# mkdir apacheroot@8ef06706f88d:~/soft# cd apache/root@8ef06706f88d:~/soft/apache# mkdir hadooproot@8ef06706f88d:~/soft/apache# cd hadoop/root@8ef06706f88d:~/soft/apache/hadoop# wget http://mirrors.sonic.net/apache/hadoop/common/hadoop-2.6.0/hadoop-2.6.0.tar.gzroot@8ef06706f88d:~/soft/apache/hadoop# tar xvzf hadoop-2.6.0.tar.gz注意:这里我们安装的Hadoop版本是2.6.0,如果需要其他版本,请在 这里 找到链接地址后修改命令即可。
3.配置环境变量
修改 ~/.bashrc 文件。在文件末尾加入下面配置信息:
export JAVA_HOME=/usr/lib/jvm/java-7-oracleexport HADOOP_HOME=/root/soft/apache/hadoop/hadoop-2.6.0export HADOOP_CONFIG_HOME=$HADOOP_HOME/etc/hadoopexport PATH=$PATH:$HADOOP_HOME/binexport PATH=$PATH:$HADOOP_HOME/sbin注意:我们使用 apt-get 安装java,不知道java装在什么地方的话可以使用下面的命令查看:
root@8ef06706f88d:~# update-alternatives --config javaThere is only one alternative in link group java (providing /usr/bin/java): /usr/lib/jvm/java-7-oracle/jre/bin/javaNothing to configure.root@8ef06706f88d:~#4.配置Hadoop
下面,我们开始修改Hadoop的配置文件。主要配置 core-site.xml 、 hdfs-site.xml 、 mapred-site.xml 这三个文件。
开始配置之前,执行下面命令:
root@8ef06706f88d:~# cd $HADOOP_HOME/root@8ef06706f88d:~/soft/apache/hadoop/hadoop-2.6.0# mkdir tmproot@8ef06706f88d:~/soft/apache/hadoop/hadoop-2.6.0# cd tmp/root@8ef06706f88d:~/soft/apache/hadoop/hadoop-2.6.0/tmp# pwd/root/soft/apache/hadoop/hadoop-2.6.0/tmproot@8ef06706f88d:~/soft/apache/hadoop/hadoop-2.6.0/tmp# cd ../root@8ef06706f88d:~/soft/apache/hadoop/hadoop-2.6.0# mkdir namenoderoot@8ef06706f88d:~/soft/apache/hadoop/hadoop-2.6.0# cd namenode/root@8ef06706f88d:~/soft/apache/hadoop/hadoop-2.6.0/namenode# pwd/root/soft/apache/hadoop/hadoop-2.6.0/namenoderoot@8ef06706f88d:~/soft/apache/hadoop/hadoop-2.6.0/namenode# cd ../root@8ef06706f88d:~/soft/apache/hadoop/hadoop-2.6.0# mkdir datanoderoot@8ef06706f88d:~/soft/apache/hadoop/hadoop-2.6.0# cd datanode/root@8ef06706f88d:~/soft/apache/hadoop/hadoop-2.6.0/datanode# pwd/root/soft/apache/hadoop/hadoop-2.6.0/datanoderoot@8ef06706f88d:~/soft/apache/hadoop/hadoop-2.6.0/datanode# cd $HADOOP_CONFIG_HOME/root@8ef06706f88d:~/soft/apache/hadoop/hadoop-2.6.0/etc/hadoop# cp mapred-site.xml.template mapred-site.xmlroot@8ef06706f88d:~/soft/apache/hadoop/hadoop-2.6.0/etc/hadoop# nano hdfs-site.xml这里创建了三个目录,后续配置的时候会用到:
tmp:作为Hadoop的临时目录namenode:作为NameNode的存放目录datanode:作为DataNode的存放目录1).core-site.xml配置注意:
hadoop.tmp.dir 配置项值即为此前命令中创建的临时目录路径。fs.default.name 配置为 hdfs://master:9000 ,指向的是一个Master节点的主机(后续我们做集群配置的时候,自然会配置这个节点,先写在这里)2).hdfs-site.xml配置使用命令 nano hdfs-site.xml 编辑 hdfs-site.xml 文件:
注意:
我们后续搭建集群环境时,将配置一个Master节点和两个Slave节点。所以 dfs.replication 配置为2。dfs.namenode.name.dir 和 dfs.datanode.data.dir 分别配置为之前创建的NameNode和DataNode的目录路径3).mapred-site.xml配置Hadoop安装文件中提供了一个mapred-site.xml.template,所以我们之前使用了命令 cp mapred-site.xml.template mapred-site.xml ,创建了一个mapred-site.xml文件。下面使用命令 nano mapred-site.xml 编辑这个文件:
这里只有一个配置项 mapred.job.tracker ,我们指向master节点机器。
4)修改JAVA_HOME环境变量使用命令 .nano hadoop-env.sh ,修改如下配置:
# The java implementation to use.export JAVA_HOME=/usr/lib/jvm/java-7-oracle5.格式化 namenode
这是很重要的一步,执行命令 hadoop namenode -format
4.安装SSH
搭建集群环境,自然少不了使用SSH。这可以实现无密码访问,访问集群机器的时候很方便。
root@8ef06706f88d:~# sudo apt-get install sshSSH装好了以后,由于我们是Docker容器中运行,所以SSH服务不会自动启动。需要我们在容器启动以后,手动通过 /usr/sbin/sshd 手动打开SSH服务。未免有些麻烦,为了方便,我们把这个命令加入到 ~/.bashrc 文件中。通过 nano ~/.bashrc 编辑 .bashrc 文件(nano没有安装的自行安装,也可用vi),在文件后追加下面内容:
#autorun/usr/sbin/sshd5.生成访问密钥
root@8ef06706f88d:/# cd ~/root@8ef06706f88d:~# ssh-keygen -t rsa -P '' -f ~/.ssh/id_dsaroot@8ef06706f88d:~# cd .sshroot@8ef06706f88d:~/.ssh# cat id_dsa.pub >> authorized_keys注意: 这里,我的思路是直接将密钥生成后写入镜像,免得在买个容器里面再单独生成一次,还要相互拷贝公钥,比较麻烦。当然这只是学习使用,实际操作时,应该不会这么搞,因为这样所有容器的密钥都是一样的!!
6.保存镜像副本
这里我们将安装好Hadoop的镜像保存为一个副本。
root@8ef06706f88d:~# exitking@king:~$ docker commit -m "hadoop install" 8ef06706f88d ubuntu:hadoopHadoop分布式集群搭建重点来了!
按照 hadoop 集群的基本要求,其 中一个是 master 结点,主要是用于运行 hadoop 程序中的 namenode、secondorynamenode 和 jobtracker(新版本名字变了) 任务。用外两个结点均为 slave 结点,其中一个是用于冗余目的,如果没有冗 余,就不能称之为 hadoop 了,所以模拟 hadoop 集群至少要有 3 个结点。
前面已经将Hadoop的镜像构建好了,下面就是使用这个镜像搭建Master节点和Slave节点了:
节点 | hostname | ip | 用途 | Docker启动脚本 |
Master | master | 10.0.0.5 |
namenode secondaryNamenode jobTracker |
docker run -ti -h master ubuntu:hadoop |
Slave | slave1 | 10.0.0.6 |
datanode taskTracker |
docker run -ti -h slave1 ubuntu:hadoop |
Slave | slave2 | 10.0.0.7 |
datanode taskTracker |
docker run -ti -h slave2 ubuntu:hadoop |
回顾一下,Docker启动容器使用的是 run 命令:
docker run -ti ubuntu:hadoop这里有几个问题:
Docker容器中的ip地址是启动之后自动分配的,且不能手动更改hostname、hosts配置在容器内修改了,只能在本次容器生命周期内有效。如果容器退出了,重新启动,这两个配置将被还原。且这两个配置无法通过 commit 命令写入镜像我们搭建集群环境的时候,需要指定节点的hostname,以及配置hosts。hostname可以使用Docker run 命令的 h 参数直接指定。但hosts解析有点麻烦,虽然可以使用 run 的 --link 参数配置hosts解析信息,但我们搭建集群时要求两台机器互相能够 ping 通,其中一个容器没有启动,那么ip不知道,所以 --link 参数对于我们的这个场景不实用。要解决这个问题,大概需要专门搭建一个域名解析服务,即使用 --dns 参数(参考 这里 )。
我们这里只为学习,就不整那么复杂了,就手动修改hosts吧。只不过每次都得改,我Docker知识浅薄,一时还没有解决这个问题。相信肯定有更好的办法。如果有高人能指定一下,感激不尽!!
启动master容器
docker run -ti -h master ubuntu:hadoop启动slave1容器
docker run -ti -h slave1 ubuntu:hadoop启动slave2容器
docker run -ti -h slave2 ubuntu:hadoop配置hosts通过 ifconfig 命令获取各节点ip。环境不同获取的ip可能不一样,例如我本机获取的ip如下:master:10.0.0.5slave1:10.0.0.6slave2:10.0.0.7
使用 sudo nano /etc/hosts 命令将如下配置写入各节点的hosts文件,注意修改ip地址:
10.0.0.5 master10.0.0.6 slave110.0.0.7 slave2配置slaves
下面我们来配置哪些节点是slave。在较老的Hadoop版本中有一个masters文件和一个slaves文件,但新版本中只有slaves文件了。
在master节点容器中执行如下命令:
root@master:~# cd $HADOOP_CONFIG_HOME/root@master:~/soft/apache/hadoop/hadoop-2.6.0/etc/hadoop# nano slaves将如下slave节点的hostname信息写入该文件:
slave1slave2启动Hadoop在master节点上执行 start-all.sh 命令,启动Hadoop。
激动人心的一刻……
如果看到如下信息,则说明启动成功了:
root@master:~/soft/apache/hadoop/hadoop-2.6.0/etc/hadoop# start-all.sh This script is Deprecated. Instead use start-dfs.sh and start-yarn.shStarting namenodes on [master]master: starting namenode, logging to /root/soft/apache/hadoop/hadoop-2.6.0/logs/hadoop-root-namenode-master.outslave1: starting datanode, logging to /root/soft/apache/hadoop/hadoop-2.6.0/logs/hadoop-root-datanode-slave1.outslave2: starting datanode, logging to /root/soft/apache/hadoop/hadoop-2.6.0/logs/hadoop-root-datanode-slave2.outStarting secondary namenodes [0.0.0.0]0.0.0.0: starting secondarynamenode, logging to /root/soft/apache/hadoop/hadoop-2.6.0/logs/hadoop-root-secondarynamenode-master.outstarting yarn daemonsstarting resourcemanager, logging to /root/soft/apache/hadoop/hadoop-2.6.0/logs/yarn--resourcemanager-master.outslave1: starting nodemanager, logging to /root/soft/apache/hadoop/hadoop-2.6.0/logs/yarn-root-nodemanager-slave1.outslave2: starting nodemanager, logging to /root/soft/apache/hadoop/hadoop-2.6.0/logs/yarn-root-nodemanager-slave2.out在个节点上执行 jps 命令,结果如下:
master节点root@master:~/soft/apache/hadoop/hadoop-2.6.0/etc/hadoop# jps1223 Jps992 SecondaryNameNode813 NameNode1140 ResourceManagerslave1节点root@slave1:~/soft/apache/hadoop/hadoop-2.6.0/etc/hadoop# jps258 NodeManager352 Jps159 DataNodeslave2节点root@slave2:~/soft/apache/hadoop/hadoop-2.6.0/etc/hadoop# jps371 Jps277 NodeManager178 DataNode下面,我们在master节点上通过命令 hdfs dfsadmin -report 查看DataNode是否正常启动:
root@master:~/soft/apache/hadoop/hadoop-2.6.0/etc/hadoop# hdfs dfsadmin -reportConfigured Capacity: 167782006784 (156.26 GB)Present Capacity: 58979344384 (54.93 GB)DFS Remaining: 58979295232 (54.93 GB)DFS Used: 49152 (48 KB)DFS Used%: 0.00%Under replicated blocks: 0Blocks with corrupt replicas: 0Missing blocks: 0-------------------------------------------------Live datanodes (2):Name: 10.0.0.7:50010 (slave2)Hostname: slave2Decommission Status : NormalConfigured Capacity: 83891003392 (78.13 GB)DFS Used: 24576 (24 KB)Non DFS Used: 54401331200 (50.67 GB)DFS Remaining: 29489647616 (27.46 GB)DFS Used%: 0.00%DFS Remaining%: 35.15%Configured Cache Capacity: 0 (0 B)Cache Used: 0 (0 B)Cache Remaining: 0 (0 B)Cache Used%: 100.00%Cache Remaining%: 0.00%Xceivers: 1Last contact: Sat Feb 28 07:27:05 UTC 2015Name: 10.0.0.6:50010 (slave1)Hostname: slave1Decommission Status : NormalConfigured Capacity: 83891003392 (78.13 GB)DFS Used: 24576 (24 KB)Non DFS Used: 54401331200 (50.67 GB)DFS Remaining: 29489647616 (27.46 GB)DFS Used%: 0.00%DFS Remaining%: 35.15%Configured Cache Capacity: 0 (0 B)Cache Used: 0 (0 B)Cache Remaining: 0 (0 B)Cache Used%: 100.00%Cache Remaining%: 0.00%Xceivers: 1Last contact: Sat Feb 28 07:27:05 UTC 2015还可以通过Web页面看到查看DataNode和NameNode的状态: http://10.0.0.5:50070/ (由于我宿主机器上没有配置master的hosts解析,所以只能用ip地址访问,大家将ip改为各自的master节点容器的ip即可):
执行WordCount实例
(待续……)