前言
之前在学Hadoop基础的时候,需要部署环境进行测试,其实那个时候部署遇到了不少的坑,今天突然想起来,所以跟大家分享下,让大家少踩点坑。我的Ubuntu版本是18.10
1. 安装Docker
安装Docker的话基本上没有遇到什么坑,我是按照官方文档去做的,官方文档连接如下: https://docs.docker.com/install/linux/docker-ce/ubuntu/
下面我还是简单说说文档里面的步骤吧,如果说大家看的懂英文的就直接跳过这一part吧
// 删除掉之前安装过的docker版本
sudo apt-get remove docker docker-engine docker.io containerd runc
// 安装以下包,让apt支持https
sudo apt-get install \
apt-transport-https \
ca-certificates \
curl \
gnupg-agent \
software-properties-common
//添加Docker官方的Key
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
//根据版本增加库地址
sudo add-apt-repository \
"deb [arch=amd64] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) \
stable"
//安装
sudo apt-get update && sudo apt-get install docker-ce docker-ce-cli containerd.io
其实上面的命令用 && 可以直接一次性安装的,不过官网分开了步骤说明每一步的作用,我这里也是简单的搬运而已。用上这些命令之后,安装是没有遇到坑的。
2. 安装JDK 8 和 Hadoop 3.2
因为Hadoop最新版是3.2,所以我这里也装了最新版,对了,先要在这里说一下一个坑,那就是 ubuntu 的 14.04,我尝试过网上 ubuntu 14.04 安装 jdk8 的大多数教程,发现好多都不太行,所以我这里用了另外一个办法,在宿主机上下载好 jdk8 的压缩包,再复制进去镜像里面,接着再改里面的环境变量就行了,同理 Hadoop 也是,接下来我来说下Dockerfile的编写
FROM ubuntu:14.04
# Step 1 安装ssh-server,因为Hadoop的NameNode和DataNode之间是靠ssh进行节点确认和传输的
# 第一步安装这个的原因是它时间长,但成功率高,这步成功之后,会有一层image cache,如果往后的
# 执行失败了,调整后再执行docker build 的时候就不用再执行这步,减少时间
RUN apt-get update -y \
&& apt-get install -y openssh-client openclient-server \
&& apt-get autoclean
# Step 2 复制tar文件到指定目录,并且自动解压,这个就是ADD的好处
# 注意,执行docker build 所在的目录是工作目录,要注意根据实际情况
# 更改压缩包的位置
ADD ./java.tar.gz /usr/lib/jvm
ADD ./hadoop.tar.gz /usr/local/
# Step 3 创建hdfs的tmp,name,data目录
RUN mkdir /usr/local/hadoop/hdfs \
&& mkdir /usr/local/hadoop/hdfs/name \
&& mkdir /usr/local/hadoop/hdfs/data
# Step 4 修改环境变量,这个命令用到的都是绝对路径,不要用下面的变量
# 来填充path路径,因为没有生效,所以会出错
RUN echo "export JAVA_HOME=/usr/lib/jvm/java" >> ~./bashrc \
&& echo "export HADOOP_HOME=/usr/local/hadoop" >> ~./bashrc \
&& ehco "export HADOOP_CONF_DIR=/usr/local/hadoop/etc/hadoop" >> ./bashrc \
&& ehco "export PATH=$PATH:/usr/lib/jvm/java/bin:/usr/local/hadoop/bin" >> ./bashrc \
###Dockerfile end
接着,在对应的目录执行
## -t 后面跟的是镜像标签 -f 后面跟的是Dockerfile所在文件目录
docker build -t hadoop:3.2 -f "Dockerfile所在文件目录"
3. 配置Hadoop的相关配置文件
3.1 Master配置
首先,新建 master 文件目录,并放置如下几个文件夹
config //用于映射config文件
hdfs //用于映射hdfs的tmp,name,data目录
ssh //用于映射镜像里面的.ssh文件
在 config 文件目录里面,新建如下目录
etc ## 基本配置文件
sbin ## 部分脚本,因为需要更改脚本才能正常运行
etc 文件夹
里面包含如下文件,这些文件都可以在 hadoop 的 /etc 里面可以找到
core-site.xml
hoodoop-env.sh
hdfs-site.xml
mapred-site.xml
workers
yarn-env.sh
yarn-site.xml
core-site.xml 主要设置 tmp 目录以及 master 网络地址
<configuration>
<property>
<!--tmp 目录地址 -->
<name>hadoop.tmp.dir</name>
<value>file:/home/hadoop/hdfs/tmp</value>
<description>A base for other temporary directories.</description>
</property>
<property>
<name>io.file.buffer.size</name>
<value>131072</value>
</property>
<property>
<!-- 默认FS地址 -->
<name>fs.defaultFS</name>
<value>hdfs://master:9000</value>
</property>
</configuration>
hsfs-site.xml 设置 replication 为1 ,因为我现在只部署一个 NameNode, 接着 NameNode 和 DataNode 存放的路径,具体更改如下
<configuration>
<property>
<name>dfs.replication</name>
<value>1</value>
</property>
<property>
<name>dfs.namenode.name.dir</name>
<value>file:/usr/local/hadoop/hdfs/name</value>
<final>true</final>
</property>
<property>
<name>dfs.datanode.data.dir</name>
<value>file:/usr/local/hadoop/hdfs/data</value>
<final>true</final>
</property>
<property>
<name>dfs.namenode.secondary.http-address</name>
<value>master:9001</value>
</property>
<property>
<name>dfs.webhdfs.enabled</name>
<value>true</value>
</property>
<property>
<name>dfs.permissions</name>
<value>false</value>
</property>
</configuration>
mapred-site.xml MapReduce 用上的 yarn 配置:
<configuration>
<property>
<name>mapreduce.framework.name</name>
<value>yarn</value>
</property>
</configuration>
yarn-site.xml 用上的配置(这个主要是 yarn 对应的 ResourceManger 和 NodeMananger 配置):
<configuration>
<property>
<name>yarn.resourcemanager.address</name>
<value>master:18040</value>
</property>
<property>
<name>yarn.resourcemanager.scheduler.address</name>
<value>master:18030</value>
</property>
<property>
<name>yarn.resourcemanager.webapp.address</name>
<value>master:18088</value>
</property>
<property>
<name>yarn.resourcemanager.resource-tracker.address</name>
<value>master:18025</value>
</property>
<property>
<name>yarn.resourcemanager.admin.address</name>
<value>master:18141</value>
</property>
<property>
<name>yarn.nodemanager.aux-services</name>
<value>mapreduce_shuffle</value>
</property>
<property>
<name>yarn.nodemanager.auxservices.mapreduce.shuffle.class</name>
<value>org.apache.hadoop.mapred.ShuffleHandler</value>
</property>
</configuration>
workers 文件也需要更改一下
worker1 ## 表示DataNode的网络名称
export JAVA_HOME=/usr/lib/jvm/java
同理 yarn-env.sh
sbin 文件夹
我的是包含以下脚本
start-dfs.sh
stop-dfs.sh
start-yarn.sh
stop-yarn.sh
HDFS_DATANODE_USER=root
HADOOP_SECURE_DN_USER=hdfs
HDFS_NAMENODE_USER=root
HDFS_SECONDARYNAMENODE_USER=root
YARN_RESOURCEMANAGER_USER=root
HADOOP_SECURE_DN_USER=yarn
YARN_NODEMANAGER_USER=root
3.2 Worker配置
Worker的配置也很简单,直接把 master 文件目录复制一下,把 改成 worker
4. Docker-Compose 集群配置
首先得安装 docker-compose 命令:
pip3 install docker-compose
我的 Docker Compose 文件如下
version: "3"
services:
master:
image: hadoop:3.2
networks:
hadoop:
ipv4_address: 172.16.172.2
volumes:
- "/etc/localtime:/etc/localtime:ro"
- "/home/anderw/docker/container/hadoop/master/hdfs/tmp:/usr/local/hadoop/hdfs/tmp"
- "/home/anderw/docker/container/hadoop/master/hdfs/name:/usr/local/hadoop/hdfs/name"
- "/home/anderw/docker/container/hadoop/master/hdfs/data:/usr/local/hadoop/hdfs/data"
- "/home/andrew/docker/container/hadoop/master/config/etc/core-site.xml:/usr/local/hadoop/etc/hadoop/core-site.xml"
- "/home/andrew/docker/container/hadoop/master/config/etc/hdfs-site.xml:/usr/local/hadoop/etc/hadoop/hdfs-site.xml"
- "/home/andrew/docker/container/hadoop/master/config/etc/mapred-site.xml:/usr/local/hadoop/etc/hadoop/mapred-site.xml"
- "/home/andrew/docker/container/hadoop/master/config/etc/yarn-site.xml:/usr/local/hadoop/etc/hadoop/yarn-site.xml"
- "/home/andrew/docker/container/hadoop/master/config/etc/hadoop-env.sh:/usr/local/hadoop/etc/hadoop/hadoop-env.sh"
- "/home/andrew/docker/container/hadoop/master/config/etc/hadoop-env.sh:/usr/local/hadoop/etc/hadoop/yarn-env.sh"
- "/home/andrew/docker/container/hadoop/master/config/etc/workers:/usr/local/hadoop/etc/hadoop/workers"
- "/home/andrew/docker/container/hadoop/master/config/sbin/start-dfs.sh:/usr/local/hadoop/sbin/start-dfs.sh"
- "/home/andrew/docker/container/hadoop/master/ssh/:/root/.ssh/"
command:
- /bin/sh
- -c
- |
rm /root/.ssh/known_hosts
/etc/init.d/ssh start
/usr/local/hadoop/bin/hdfs namenode -format
./usr/local/hadoop/sbin/start-dfs.sh
tail -f /dev/null
expose:
- "22"
- "9000"
worker1:
image: hadoop:3.2
networks:
hadoop:
ipv4_address: 172.16.172.3
volumes:
- "/etc/localtime:/etc/localtime:ro"
- "/home/anderw/docker/container/hadoop/worker1/hdfs/tmp:/usr/local/hadoop/hdfs/tmp"
- "/home/anderw/docker/container/hadoop/worker1/hdfs/name:/usr/local/hadoop/hdfs/name"
- "/home/anderw/docker/container/hadoop/worker1/hdfs/data:/usr/local/hadoop/hdfs/data"
- "/home/andrew/docker/container/hadoop/worker1/config/etc/core-site.xml:/usr/local/hadoop/etc/hadoop/core-site.xml"
- "/home/andrew/docker/container/hadoop/worker1/config/etc/hdfs-site.xml:/usr/local/hadoop/etc/hadoop/hdfs-site.xml"
- "/home/andrew/docker/container/hadoop/worker1/config/etc/mapred-site.xml:/usr/local/hadoop/etc/hadoop/mapred-site.xml"
- "/home/andrew/docker/container/hadoop/worker1/config/etc/yarn-site.xml:/usr/local/hadoop/etc/hadoop/yarn-site.xml"
- "/home/andrew/docker/container/hadoop/worker1/config/etc/hadoop-env.sh:/usr/local/hadoop/etc/hadoop/hadoop-env.sh"
- "/home/andrew/docker/container/hadoop/worker1/config/etc/hadoop-env.sh:/usr/local/hadoop/etc/hadoop/yarn-env.sh"
- "/home/andrew/docker/container/hadoop/worker1/config/etc/workers:/usr/local/hadoop/etc/hadoop/workers"
- "/home/andrew/docker/container/hadoop/worker1/config/sbin/start-dfs.sh:/usr/local/hadoop/sbin/start-dfs.sh"
- "/home/andrew/docker/container/hadoop/worker1/ssh/:/root/.ssh/"
command:
- /bin/sh
- -c
- |
rm /root/.ssh/known_hosts
/etc/init.d/ssh start
./usr/local/hadoop/sbin/start-dfs.sh
tail -f /dev/null
expose:
- "22"
networks:
hadoop:
ipam:
driver: default
config:
- subnet: "172.16.172.0/24"
注意:
- 首次启动的时候就会 format namenode, 在第二次启动的时候要把 usr/local/hadoop/bin/hdfs namenode -format 这个命令给删除
- 我已经把 .ssh 的文件目录映射到外面了,大家必须按照自己的情况做出更改,映射出来的目的是方便下面步骤,更改 ssh 的设置
- server 名字必须是 master 和 worker1,如果要自定义,必须更改上面的配置文件
5. ssh 免登录设置
首先,在上面的docker-compose 中,删除调用 start-dfs.sh
docker-compose -f "docker-compose 文件的绝对路径" up -d
然后找到 master 和 worker 容器的id, 可以通过 docker container ps 查看,接着进入容器,用以下命令
docker exec -it "容器id" /bin/bash
这样就可以在 root 的用户下操作镜像,这个时候就可以生成自己用的公钥秘钥
ssh-keygen -t rsa -C "用户名称"
一路按 enter, 就可以生成默认的免密码的公钥和秘钥了,默认地址就是在 /root/.ssh 下面有个 id_rsa 和 id_rsa.pub,在 master 的容器中把它改成 master, master.pub, 在 worker1 的容器中把它改成 worker1, worker1.pub。在宿主机上确保 master , worker1 的 .ssh 映射文件里面都有这两个秘钥( master 和 worker1 )。同时 authorized_key 中 也必须含有这两个对应的 pub。如果没有authorized_key 要创建,并且确保文件访问权限为 600。接着在他们 .ssh 文件目录中添加 config 文件,内容如下
Host worker1
HostName worker1
IdentityFile "对应worker1的秘钥路径"
User root
Host master
HostName master
IdentityFile "对应master的秘钥路径"
PreferredAuthentications publickey
User root
接着,用
docker-compose -f "docker-compose 文件的绝对路径" down
关掉容器,在 docker-compose 的 command 上添加执行的脚本
./usr/local/hadoop/sbin/start-dfs.sh
再重新执行
docker-compose -f "docker-compose 文件的绝对路径" up -d
如无意外, Hadoop 集群就可以跑起来了
6 后记
还好写了这篇笔记,6.2号的时候发现昨天好好的笔记本来不了机了..........可能得重新部署环境。由于最近在复习java,所以没有怎么更新文章,在这里我补充下构建镜像以及使用这几个容器需要避开的坑吧。
6.1 构建镜像注意的地方
- Dockerfile 的每一个命令,都会在本机上留下中间镜像,只有 docker image ls -a 才能看到,所以为了避免出现过多的冗余,最好指令少一点
- 除了指令少一点,当然最好就是每一条指令只做一件事情,而且还得记住,构建镜像的时候必须记得用命令删除不必要的内容,以免镜像过大
- 成功率高,但耗时大的命令尽量往前放,因为后面即使失败,第二次构建也会从成功的命令开始,这样避免重复构建镜像的时候花费过多的时间
6.2 构建容器注意的地方
在我搭建上面的环境时, ssh 密码登录卡了我两天时间,到最后排查到的问题是,当你进入容器新建目录的时候,如果宿主机有跟该目录做映射,在宿主机不存在对应目录的情况下,目录的用户权限是跟容器一致的;如果在宿主创建对应目录,那么容器内的目录权限以宿主机的为准。因为当时没有注意到这个细节,导致映射出来的 .ssh 文件中的秘钥,配置全都不可用,所以大家在搭建环境的时候务必注意这一点。