使用Docker搭建Hadoop集群

前言

我是按照docker環(huán)境下搭建hadoop集群(ubuntu16.04 LTS系統(tǒng))這篇博客來搭建的,然后遇到了不少的坑,所以我就把自己的搭建過程寫了出了,順便補(bǔ)充了一些注意事項(xiàng)。非常感謝原博主的創(chuàng)作。ヾ(?°?°?)??

目標(biāo)

我們的目標(biāo)是,使用Docker的Ubuntu鏡像,在計(jì)算機(jī)上搭建一個(gè)“One-Master-Two-Slaves”的Hadoop集群模型,并且將容器保存為鏡像,以便后面能夠復(fù)用。

工具

我使用Windows7操作系統(tǒng),因此Docker是使用toolbox運(yùn)行的。此外,使用XShell來連接Docker,方便操作和文件互傳。

總體步驟

  1. 使用XShell連通Docker服務(wù)器進(jìn)程
  2. 使用Docker安裝Ubuntu鏡像
  3. 安裝jdk1.8,配置好Java環(huán)境
  4. 更換apt源,使用阿里源,方便安裝軟件
  5. 安裝ssh工具,使得容器間可以互聯(lián)
  6. 安裝vim,可以進(jìn)行文本文件操作
  7. 安裝hadoop
  8. 構(gòu)建一個(gè)Master、二個(gè)Slave容器
  9. 配置hosts文件,以及配置公鑰,使得三個(gè)容器可以互相ssh連通
  10. 配置相關(guān)集群節(jié)點(diǎn),嘗試配置結(jié)果

詳細(xì)步驟

1. 使用XShell連接Docker

Docker默認(rèn)的賬戶名是docker,密碼是tcuser。其ip地址可以在Docker啟動頁面上看到

Docker啟動頁面

如上圖,可以看到ip地址是192.168.99,100,因此在XShell中鍵入ssh 192.168.99,100,然后按照提示輸入賬戶名和密碼,即可連接成功。或者可以使用XShell的圖形用戶界面來永久配置連接信息,在此不再贅述。

2. 使用Docker安裝Ubuntu鏡像

2.1 安裝鏡像

使用docker search ubuntu來檢索本地倉庫或Docker Hub中的ubuntu鏡像,然后使用docker pull命令來獲取。在這里我直接使用官方發(fā)布的最新ubuntu鏡像:

docker@default:~$ docker pull ubuntu

使用docker images命令可以查看安裝情況:

docker@default:~$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
ubuntu              latest              775349758637        2 weeks ago         64.2MB

2.2 在Docker本地構(gòu)建一個(gè)項(xiàng)目文件夾

在Docker本地構(gòu)建一個(gè)項(xiàng)目文件夾。因?yàn)樵赪indows上使用Docker,它本身就是運(yùn)行在一個(gè)小的虛擬機(jī)中,我們在這個(gè)模擬機(jī)中構(gòu)建一個(gè)文件夾作為軟件包、數(shù)據(jù)的中轉(zhuǎn),即將該文件夾掛載到容器中,這樣,宿主機(jī)(Win7系統(tǒng))的數(shù)據(jù)可以先用XShell的Xftp文件傳輸功能推送到虛擬機(jī)的該文件夾中,從而在容器中可以直接訪問。

docker@default:~$ mkdir /home/docker/azur_wxj/

2.3 構(gòu)建容器

我們將以此為基礎(chǔ)鏡像來構(gòu)建容器。構(gòu)建容器的命令是docker run,具體命令可以參考官方文檔:docker run。在這里,我使用如下命令:

docker run -it -h hdpnode -v /home/docker/azur_wxj:/home/azur_wxj --name hdpnode ubuntu /bin/bash
  • -it:表示創(chuàng)建的容器是可交互式的(終端命令行模式),是-t-i的簡寫
  • -h hdpnode:指定容器的宿主名(container host name)為hdpnode
  • -v /home/docker/azur_wxj:/home/azur_wxj:表示將虛擬機(jī)的目錄/home/docker/azur_wxj掛載到容器的目錄/home/azur_wxj
  • --name hdpnode:表示創(chuàng)建的容器名為hdpnode
  • ubuntu /bin/bash:表示使用ubuntu作為基礎(chǔ)鏡像,創(chuàng)建的容器立刻運(yùn)行/bin/bash命令呼出交互式終端。如果沒有額外的標(biāo)簽信息,ubuntu就是ubuntu:latest,即默認(rèn)最新的鏡像。

現(xiàn)在,如果沒有問題,將會進(jìn)入創(chuàng)建的容器的交互式界面:

docker@default:~$ docker run -it -h hdpnode -v /home/docker/azur_wxj:/home/azur_wxj --name hdpnode ubuntu /bin/bash
root@hdpnode:/# ls /home/
azur_wxj
root@hdpnode:/#

如果想要退出容器返回Docker界面,可以使用Ctrl+p+q快捷鍵(按順序鍵入),此時(shí)容器保持運(yùn)行而不會停止。如果使用exit命令,則容器終止,退回Docker界面,此時(shí),必須使用docker start hdpnode來啟動容器,然后使用docker attach hdpnode來附著到容器上,簡單理解就是,重新進(jìn)入容器的交互式終端界面。

3. 安裝jdk1.8,配置好Java環(huán)境

3.1 下載jdk包

不同Hadoop版本支持的jdk版本不同,可以在 Hadoop Java Versions查看。簡單來說,Apache Hadoop 3.x 目前只支持Java 8,而 Apache Hadoop 2.7.x2.x 支持Java 7和8。方便起見,我直接安裝了jdk1.8。

此外,因?yàn)镺racle更改了用戶協(xié)議,新的協(xié)議生效后,下載Oracle jdk需要注冊登錄,非常麻煩。可以選擇安裝openjdk,但是這里我選擇安裝了舊協(xié)議的最后一版“免費(fèi)”jdk1.8。CSDN一位博主在《jdk下載/Linux64位 jdk1.8 jdk-8u161下載》博客中貼出了百度網(wǎng)盤的資源地址(拜謝~orz),選擇 linux 64 jdk1.8 jdk-8u161-linux-x64.tar.gz 下載即可。(Docker好像只支持64位計(jì)算機(jī),所以選擇x64就可以)

下載完成的壓縮包,使用xshell的Xftp推送到我們剛剛在虛擬機(jī)創(chuàng)建的 /home/docker/azur_wxj 目錄中(關(guān)于Xftp功能用法可以自行檢索,非常簡單)

因?yàn)槟夸洅燧d,此時(shí)我們可以在hdpnode容器中查看 /home/azur_wxj 目錄了:

root@hdpnode:/# ls /home/azur_wxj/
jdk-8u161-linux-x64.tar.gz
root@hdpnode:/# 

3.2 解壓jdk包

使用tar命令解壓jdk包

root@hdpnode:/# tar -zxvf /home/azur_wxj/jdk-8u161-linux-x64.tar.gz
root@hdpnode:/# ls
bin  boot  dev  etc  home  jdk1.8.0_161  lib  lib64  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var
root@hdpnode:/# 

我將安裝的所有軟件都移動到 /usr/local 目錄下,所以

root@hdpnode:/# mv jdk1.8.0_161/ /usr/local/jdk1.8
root@hdpnode:/# ls /usr/local/jdk1.8/
COPYRIGHT  LICENSE  README.html  THIRDPARTYLICENSEREADME-JAVAFX.txt  THIRDPARTYLICENSEREADME.txt  bin  db  include  javafx-src.zip  jre  lib  man  release  src.zip
root@hdpnode:/# 

3.3 配置環(huán)境變量

環(huán)境變量的配置是在 /etc/profile 文件中,因?yàn)樯形窗惭bvim,所以我使用echo命令將環(huán)境變量追加到 /etc/profile 文件末尾(使用追加重定向符>>),不過在此之前,為了保險(xiǎn)起見,將原來的文件做一個(gè)備份:

root@hdpnode:/# cp /etc/profile /etc/profile.backup
root@hdpnode:/# echo 'export JAVA_HOME=/usr/local/jdk1.8/'>>/etc/profile
root@hdpnode:/# echo 'export JRE_HOME=${JAVA_HOME}/jre'>>/etc/profile
root@hdpnode:/# echo 'export CLASSPATH=.:${JAVA_HOME}/lib:${JRE_HOME}/lib'>>/etc/profile
root@hdpnode:/# echo 'export PATH=.:${JAVA_HOME}/bin:$PATH'>>/etc/profile

然后使用source命令來更新環(huán)境變量,最后檢查java是否安裝成功

root@hdpnode:/# source /etc/profile
root@hdpnode:/# java -version
java version "1.8.0_161"
Java(TM) SE Runtime Environment (build 1.8.0_161-b12)
Java HotSpot(TM) 64-Bit Server VM (build 25.161-b12, mixed mode)
root@hdpnode:/# 

3.4 問題:重入容器時(shí)環(huán)境變量失效

這里有一個(gè)問題,就是如果將容器退出停止,下次再重啟容器時(shí),會發(fā)現(xiàn),盡管添加的Java環(huán)境變量還在,但是java命令提示找不到,需要重新執(zhí)行source /etc/profile命令才可以:

root@hdpnode:/# exit
exit
docker@default:~$ docker start hdpnode   #重啟容器
hdpnode
docker@default:~$ docker attach hdpnode  #附著容器,進(jìn)入容器終端頁
root@hdpnode:/# java -version  #?找不到j(luò)ava命令
bash: java: command not found
root@hdpnode:/# source /etc/profile  #重新source
root@hdpnode:/# java -version  #java命令可以正常運(yùn)行
java version "1.8.0_161"
Java(TM) SE Runtime Environment (build 1.8.0_161-b12)
Java HotSpot(TM) 64-Bit Server VM (build 25.161-b12, mixed mode)
root@hdpnode:/# 

這種原因是:

/etc/profile中的變量不是自動就export的,完整的os在啟動過程會有啟動程序依次讀取系統(tǒng)和用戶的配置文件,但在容器里就沒有這一步了,所以要自己導(dǎo)出才可以。(使用docker exec進(jìn)入容器,無法讀取環(huán)境變量問題

解決辦法是,要么修改 ~/.bashrc 文件,添加命令,使得進(jìn)入終端時(shí)自動執(zhí)行;要么是對容器修改,使得進(jìn)入容器時(shí)由docker代為執(zhí)行命令(例如entrypoint選項(xiàng))。在這里我選擇修改 ~/.bashrc 文件:

root@hdpnode:/# echo 'source /etc/profile' >> ~/.bashrc
root@hdpnode:/# exit
exit
docker@default:~$ docker start hdpnode
hdpnode
docker@default:~$ docker attach hdpnode
root@hdpnode:/# java -version
java version "1.8.0_161"
Java(TM) SE Runtime Environment (build 1.8.0_161-b12)
Java HotSpot(TM) 64-Bit Server VM (build 25.161-b12, mixed mode)
root@hdpnode:/# 

4. 更換apt源

apt源定義在 /etc/apt/sources.list 文件中,如果不更換國內(nèi)源,則安裝使用國內(nèi)網(wǎng)絡(luò)進(jìn)行軟件下載會非常的慢而且經(jīng)常會出錯(cuò)失敗。先將原來的源文件備份

root@hdpnode:/# mv /etc/apt/sources.list /etc/apt/sources.list.backup

然后我使用了阿里源

# deb cdrom:[Ubuntu 16.04 LTS _Xenial Xerus_ - Release amd64 (20160420.1)]/ xenial main restricted
deb-src http://archive.ubuntu.com/ubuntu xenial main restricted #Added by software-properties
deb http://mirrors.aliyun.com/ubuntu/ xenial main restricted
deb-src http://mirrors.aliyun.com/ubuntu/ xenial main restricted multiverse universe #Added by software-properties
deb http://mirrors.aliyun.com/ubuntu/ xenial-updates main restricted
deb-src http://mirrors.aliyun.com/ubuntu/ xenial-updates main restricted multiverse universe #Added by software-properties
deb http://mirrors.aliyun.com/ubuntu/ xenial universe
deb http://mirrors.aliyun.com/ubuntu/ xenial-updates universe
deb http://mirrors.aliyun.com/ubuntu/ xenial multiverse
deb http://mirrors.aliyun.com/ubuntu/ xenial-updates multiverse
deb http://mirrors.aliyun.com/ubuntu/ xenial-backports main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ xenial-backports main restricted universe multiverse #Added by software-properties
deb http://archive.canonical.com/ubuntu xenial partner
deb-src http://archive.canonical.com/ubuntu xenial partner
deb http://mirrors.aliyun.com/ubuntu/ xenial-security main restricted
deb-src http://mirrors.aliyun.com/ubuntu/ xenial-security main restricted multiverse universe #Added by software-properties
deb http://mirrors.aliyun.com/ubuntu/ xenial-security universe
deb http://mirrors.aliyun.com/ubuntu/ xenial-security multiverse

把它保存為 sources.list 文件,然后使用Xftp推送到 /home/docker/azur_wxj 文件夾中去,然后在ubuntu中使用如下命令進(jìn)行移動:

root@hdpnode:/# cp /home/azur_wxj/sources.list /etc/apt/sources.list

最后使用

root@hdpnode:/# apt-get update

進(jìn)行更新。這需要花幾分鐘的時(shí)間。

5. 安裝ssh工具

使用命令:

root@hdpnode:/# apt-get install ssh

安裝ssh,此時(shí)需要輸入y來確認(rèn)安裝。這需要花費(fèi)幾分鐘的時(shí)間。

關(guān)于SSH的信息,參見 附錄1:SSH服務(wù)。

6. 安裝vim

方便后面的終端編輯文本,我們使用apt-get來安裝vim:

root@hdpnode:~# apt-get install vim

7. 安裝hadoop

7.1 下載安裝包

現(xiàn)在開始安裝hadoop。因?yàn)閡buntu容器沒有安裝wget,所以還是在Win7宿主機(jī)上下好壓縮包,再傳送到容器中。

可以在 Apache Download Mirrors中選擇方便的鏡像網(wǎng)站來下載hadoop。這里我選擇使用清華大學(xué)的鏡像,我選擇Hadoop-2.7.7版本,如果網(wǎng)頁下載慢的話,可以復(fù)制地址使用迅雷或其他下載軟件下載。

下載好后的壓縮包使用Xftp推送到掛載目錄中去。

7.2 解壓安裝

使用tar命令解壓,然后移動到 /usr/local/hadoop 目錄中

root@hdpnode:~# tar -zxvf /home/azur_wxj/hadoop-2.7.7.tar.gz
....
root@hdpnode:~# mv hadoop-2.7.7/ /usr/local/hadoop
root@hdpnode:~# ls /usr/local/hadoop/
LICENSE.txt  NOTICE.txt  README.txt  bin  etc  include  lib  libexec  sbin  share
root@hdpnode:~# 

7.3 配置Java環(huán)境變量

現(xiàn)在需要在hadoop配置文件中指定Java目錄地址:

  • 配置文件目錄是 /usr/local/hadoop/etc/hadoop/hadoop-env.sh
  • 需要添加的環(huán)境變量是 export JAVA_HOME=/usr/local/jdk1.8(即jdk目錄)

直接使用echo命令來追加

root@hdpnode:~# echo 'export JAVA_HOME=/usr/local/jdk1.8' >> /usr/local/hadoop/etc/hadoop/hadoop-env.sh

7.4 將hadoop命令添加到環(huán)境變量

hadoop命令位于 /usr/local/hadoop/bin 目錄中,我們可以將該目錄加到環(huán)境變量PATH中,這樣下次直接輸入hadoop即可啟動。

使用vim來編輯 /etc/profile , 將最后的PATH改為:

export PATH=.:/usr/local/hadoop/bin:${JAVA_HOME}/bin:$PATH

保存退出后,使用

root@hdpnode:~# source /etc/profile

更新一次?,F(xiàn)在,輸入hadoop應(yīng)該能看到該命令的說明

root@hdpnode:~# hadoop
Usage: hadoop [--config confdir] [COMMAND | CLASSNAME]
  CLASSNAME            run the class named CLASSNAME
 or
  where COMMAND is one of:
  fs                   run a generic filesystem user client
  version              print the version
  jar <jar>            run a jar file
                       note: please use "yarn jar" to launch
                             YARN applications, not this command.
  checknative [-a|-h]  check native hadoop and compression libraries availability
  distcp <srcurl> <desturl> copy file or directories recursively
  archive -archiveName NAME -p <parent path> <src>* <dest> create a hadoop archive
  classpath            prints the class path needed to get the
  credential           interact with credential providers
                       Hadoop jar and the required libraries
  daemonlog            get/set the log level for each daemon
  trace                view and modify Hadoop tracing settings

Most commands print help when invoked w/o parameters.
root@hdpnode:~# 

8. 構(gòu)建Master和Slave容器

8.1 提交為鏡像

現(xiàn)在,一切都配置好了,我們需要將這個(gè)容器進(jìn)行提交為一個(gè)鏡像。接下來將使用這個(gè)鏡像作為基礎(chǔ)鏡像來構(gòu)成我們的節(jié)點(diǎn)容器。

提交鏡像使用命令docker commit,不過在此之前需要退出容器并停止容器。

root@hdpnode:/# exit    #退出并終止hdpnode容器
exit
docker@default:~$ docker ps -a    #查看所有容器
CONTAINER ID        IMAGE                    COMMAND                  CREATED             STATUS                      PORTS               NAMES
4f0f1383b82c        ubuntu                   "/bin/bash"              3 hours ago         Exited (0) 13 seconds ago                       hdpnode

然后提交:

docker@default:~$ docker commit -m="image with vim,java and hadoop" hdpnode azur_wxj/hdpnode
sha256:dc00fcf803bea1f9346ff8ced7d16c3184e8fbeddd48b79f8f096ef5bb52981f

提交的容器名是 hdpnode(也可以使用容器ID:4f0f),保存的鏡像為 azur_wxj/hdpnode,默認(rèn)標(biāo)簽是 lastest?,F(xiàn)在可以來看看本地鏡像了

docker@default:~$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
azur_wxj/hdpnode    latest              dc00fcf803be        20 seconds ago      922MB
ubuntu              latest              775349758637        2 weeks ago         64.2MB
docker@default:~$ 

8.2 創(chuàng)建主從容器

現(xiàn)在我們要?jiǎng)?chuàng)建三個(gè)容器(hadoop節(jié)點(diǎn)),一個(gè)主容器(master),以及兩個(gè)從容器(slave1和slave2):

docker@default:~$ docker run -it --name master -h master -v /home/docker/azur_wxj:/home/azur_wxj azur_wxj/hdpnode /bin/bash
#[Ctrl+P+Q]保持容器運(yùn)行,退出到Docker界面
docker@default:~$ docker run -it --name slave1 -h slave1 -v /home/docker/azur_wxj:/home/azur_wxj azur_wxj/hdpnode /bin/bash
#[Ctrl+P+Q]保持容器運(yùn)行,退出到Docker界面
docker@default:~$ docker run -it --name slave2 -h slave2 -v /home/docker/azur_wxj:/home/azur_wxj azur_wxj/hdpnode /bin/bash
#[Ctrl+P+Q]保持容器運(yùn)行,退出到Docker界面

由于每一次創(chuàng)建交互式容器都會自動切換到容器的交互式界面,所以為了創(chuàng)建下一個(gè)容器,需要用快捷鍵Ctrl+P+Q來退出容器到Docker,同時(shí)保持容器在后臺運(yùn)行而不終止?,F(xiàn)在,我們可以看看活動中的三個(gè)容器:

docker@default:~$ docker ps
CONTAINER ID        IMAGE                    COMMAND             CREATED             STATUS              PORTS               NAMES
17ed290a06c1        azur_wxj/hdpnode         "/bin/bash"         3 minutes ago       Up 3 minutes                            slave2
cb8aca513704        azur_wxj/hdpnode         "/bin/bash"         3 minutes ago       Up 3 minutes                            slave1
8009ae423f13        azur_wxj/hdpnode         "/bin/bash"         4 minutes ago       Up 3 minutes                            master
docker@default:~$ 

9. 配置hosts文件以及公鑰

9.1 獲取容器的ip地址

在Docker界面,鍵入如下命令來查找容器的ip地址

docker@default:~$ docker inspect -f '{{.Name}} - {{.NetworkSettings.IPAddress }}' $(docker ps -aq) 
/slave2 - 172.17.0.7
/slave1 - 172.17.0.6
/master - 172.17.0.5
docker@default:~$ 

9.2 配置hosts文件

如果需要使用ssh命令來連接其他容器,命令參數(shù)需要時(shí)容器的ip地址。但是每次輸入ip地址會非常繁瑣且容易出錯(cuò)。我們可以配置hosts文件(/etc/hosts),用一個(gè)名稱來指代ip地址。

對于每一個(gè)容器,我們執(zhí)行如下操作(以master容器為例):

docker@default:~$ docker attach master  #切換到master容器
root@master:/# vim /etc/hosts  #修改hosts文件

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.5      master  #ip-名稱 鍵值對
172.17.0.6      slave1
172.17.0.7      slave2

保存退出。

問題:Docker容器修改hosts文件重啟不變
一個(gè)問題是,如果你關(guān)閉容器,下次重啟容器后,發(fā)現(xiàn)hosts的內(nèi)容由復(fù)原了,我們添加的內(nèi)容都沒有了。對此,在Docker容器修改hosts文件重啟不變問題貼中,有回答指出:


“容器中的 /etc/hosts/etc/resolv.conf/etc/hostname 這三個(gè)文件不存在于鏡像,而是存在于 /var/lib/docker/containers/。在啟動容器的時(shí)候,通過掛載的形式將這些文件掛載到容器內(nèi)部。因此,如果在容器中修改這些文件的話,修改部分不會存在于容器的top layer,而是直接寫入這三個(gè)物理文件中。”

“為什么重啟后修改內(nèi)容不存在了?原因是:每次Docker在啟動容器的時(shí)候,通過重新構(gòu)建新的 /etc/hosts 文件,這又是為什么呢?原因是:容器重啟,IP地址為改變,hosts文件中原來的IP地址無效,因此理應(yīng)修改hosts文件,否則會產(chǎn)生臟數(shù)據(jù)。”

“有沒有什么好的解決方法? 我印象中可以通過docker run命令的--add-host參數(shù)來為容器添加hostip的映射關(guān)系。”

9.3 問題:無法連接22端口

嘗試使用ssh slave1來連接slave1容器時(shí)出現(xiàn)問題:

root@master:/# ssh slave1
ssh: connect to host slave1 port 22: Connection refused

結(jié)果報(bào)錯(cuò):“無法連接到slave1的22端口,連接被拒絕”。

關(guān)于這個(gè)我查閱了一些資料,說是因?yàn)榕渲猛阧osts文件需要執(zhí)行/usr/sbin/sshd命令才能連接。但是當(dāng)輸入這個(gè)指令時(shí)又一個(gè)問題產(chǎn)生:

root@master:/# /usr/sbin/sshd 
Missing privilege separation directory: /var/run/sshd

我又查了資料,據(jù)說是ssh服務(wù)沒有開啟,通過ps -e|grep ssh命令來查詢,發(fā)現(xiàn)確實(shí)沒有ssh服務(wù),所以需要用/etc/init.d/ssh start來開啟,在查詢就有了:

root@master:/# ps -e | grep ssh    #沒有ssh服務(wù)
root@master:/# /etc/init.d/ssh start    #啟動ssh服務(wù)
 * Starting OpenBSD Secure Shell server sshd                                                                                                                                            [ OK ] 
root@master:/# ps -e | grep ssh    #有了ssh服務(wù)
   37 ?        00:00:00 sshd
root@master:/# /usr/sbin/sshd     #執(zhí)行sshd沒有問題

所以對于每個(gè)容器,依次執(zhí)行如下的2個(gè)命令:

root@slave2:/# /etc/init.d/ssh start    #開啟服務(wù)
 * Starting OpenBSD Secure Shell server sshd                                                                                                                                            [ OK ] 
root@slave2:/# /usr/sbin/sshd     #執(zhí)行sshd
root@slave2:/# 

但是還差一步,因?yàn)槲覀冞€沒有配置被認(rèn)證的容器公鑰(見附錄1:SSH服務(wù) - 1.3 公鑰登錄),否則當(dāng)ssh另一個(gè)容器,會讓你輸入容器的登錄密碼,但是我們?nèi)萜鞲緵]有配置密碼,不管怎輸入都是被denied的(′-ι_-`):

root@slave2:/# ssh master  #slave2嘗試連接master
The authenticity of host 'master (172.17.0.5)' can't be established.
ECDSA key fingerprint is SHA256:R9jEjviby0wE1mWlnhnLzNxyAvPLpVhp4qN8b4r6dFA.
Are you sure you want to continue connecting (yes/no)? yesy^H
Warning: Permanently added 'master,172.17.0.5' (ECDSA) to the list of known hosts.
root@master's password: 

Permission denied, please try again.  #不管怎么輸都是錯(cuò)誤的

9.4 配置登錄公鑰

對于每一個(gè)容器,使用ssh-keygen來生成公鑰和私鑰(以master為例):

root@master:~# ssh-keygen -t rsa    #類型為rsa(缺?。?Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa):   #默認(rèn)保存路徑
Created directory '/root/.ssh'.
Enter passphrase (empty for no passphrase):   #不設(shè)置私鑰保護(hù)口令
Enter same passphrase again:   #繼續(xù)回車
Your identification has been saved in /root/.ssh/id_rsa.
Your public key has been saved in /root/.ssh/id_rsa.pub.
The key fingerprint is:
SHA256:qV8XlJh+VwhLndk94Autyg3jrc+jhbQpk3FHTEMLKJ0 root@master
The key's randomart image is:
+---[RSA 2048]----+
|      . o..+oo.+.|
|     . E  ++=++oo|
|      .   o=+o. o|
|         o..o .. |
|       .S=.oo..  |
|       .B @. o   |
|      .+ B.+.    |
|       .o.+o     |
|        .ooo.    |
+----[SHA256]-----+
root@master:~# ls ~/.ssh/    #查看私鑰和公鑰
id_rsa  id_rsa.pub
root@master:~# cat ~/.ssh/id_rsa.pub   #查看公鑰內(nèi)容
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQD6qeWvdxOZYkaj+l+NlZUBPCIYi8sF5AvzhFbZMTysZsljooCiaNbMNC8vk1yrSvpiJwJ6gBlrBwKX3lxn2HFPZWHvkK0EO29NtN83RiCqkcx+28YoNISJ6vye0CP1rADMkmQsJXymWm/NS4bhtBK8LM5DAQmizTWwJZR/4ROSbWAfbBuBssdIcpdNHMHjhg9j5ZtQUYA/IsRJAFnBNnNXoD/c6E3ezAnSvG54vhRDgG4E70jlclfnonT8v6Slbh4OKBl+UqH5NmbDYdkoKQByoaUtj+v2wqP4/UNWCGUlXc1NrPxsdcDx1CZr0W7o8TdHUYCNLu+P9/b8qiuHLPEj root@master
root@master:~# 

現(xiàn)在我們得到了三個(gè)容器的公鑰內(nèi)容:

ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQD6qeWvdxOZYkaj+l+NlZUBPCIYi8sF5AvzhFbZMTysZsljooCiaNbMNC8vk1yrSvpiJwJ6gBlrBwKX3lxn2HFPZWHvkK0EO29NtN83RiCqkcx+28YoNISJ6vye0CP1rADMkmQsJXymWm/NS4bhtBK8LM5DAQmizTWwJZR/4ROSbWAfbBuBssdIcpdNHMHjhg9j5ZtQUYA/IsRJAFnBNnNXoD/c6E3ezAnSvG54vhRDgG4E70jlclfnonT8v6Slbh4OKBl+UqH5NmbDYdkoKQByoaUtj+v2wqP4/UNWCGUlXc1NrPxsdcDx1CZr0W7o8TdHUYCNLu+P9/b8qiuHLPEj root@master
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCwOfPhcnA3EH9Y1GxHk4uFgdq83eG3gl0HKUUi1nndnbF4Sl3MAC1Wg4nQOF2oSI8r0ksiBAU/R6MyUpvlJk/RZxHzCwd/uNsyYF0ExPDbFGbS9OkztkU/y9Co5V21lJl0iocGG8qf3/4CgDWdb7K7H6gsZ1c+oPZ2kFYseki5JUXHbQfbdf6xhdT+4+i6zcspEu34b8mLmwlODv48cvlsJw8SWinXlhWaAKlozOhdgDOnhKSl6IEzoFgi/7i7+zAErVkahZjLk07Mu6nirA5qo3ZAf5fi/OX4OQ2yEy8vQhg0Y8uN00XLcWm+qKfthGxMoALB6+SJN8XM1o+J8xUp root@slave1
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDB6tV+AULHzP6nvGnnU9IyhohAHR5KCgBxN73VL+6UwosdR+dZjN2mKiBxoLS8hJOiuecgXq3khxrj1GODyNEVgrH14kIOwtTrpxFyDEySyHB/Ym1HSl3au0VLLWjpS0tLOOqT9cKKH1fDAM5tu6bht/sBhSKknii2fyY/tMKu65AmWXRn/Oa+XnN4cNUP2oefxsWMEGaIVvDypHs00Frin1Gh10HVBVwQrprr1dY18oMUQYxZEjHtKT58e2xmCYttXIusv9r3I3ESqqzX5C37BeGoYgLQBC7Vo1P2qY9XlNlt05WMKVRbrvZvkABUcm4mdeBTi29gDkjTInJCbJh7 root@slave2

在每一個(gè)容器的 ~/.ssh/ 下建立一個(gè)名為 authorized_keys的文件,然后把三個(gè)公鑰全部寫入。你可以把每一個(gè)公鑰都復(fù)制到一個(gè)文本文件中,然后創(chuàng)建完authorized_keys后一起復(fù)制。不過,我在創(chuàng)建完每一個(gè)容器的公鑰后,將內(nèi)容重定向到了掛載目錄下的 /home/azur_wxj/sshkeys中(root@master:~# cat .ssh/id_rsa.pub >> /home/azur_wxj/sshkeys),這樣,我可以直接將這個(gè)文件復(fù)制為authorized_keys,例如,對于master有:

root@master:~# cp /home/azur_wxj/sshkeys .ssh/authorized_keys
root@master:~# ls -l .ssh/authorized_keys 
-rw-r--r-- 1 root root 1179 Nov 16 08:10 .ssh/authorized_keys

當(dāng)三個(gè)容器都完成,我們來試試互聯(lián):

root@master:~# ssh slave1  #master ssh 連接 slave1
....
Are you sure you want to continue connecting (yes/no)? yes  #第一次連接需要確認(rèn)
....
root@slave1:~#     #連接到slave1
root@slave1:~# exit    #退出連接
logout
Connection to slave1 closed.
root@master:~#     #退回到master

第一次連接會有確認(rèn)信息,輸入yes后連接成功。此后連接就不再需要確認(rèn)信息。至此,三個(gè)容器的互聯(lián)配置完成。

10. 配置相關(guān)集群節(jié)點(diǎn)

現(xiàn)在三個(gè)容器可以互聯(lián)了,我們現(xiàn)在開始配置hadoop,使這三個(gè)節(jié)點(diǎn)成為hadoop節(jié)點(diǎn),其中master為namenode,而slave?為datanode。

以下的代碼全部來自于docker環(huán)境下搭建hadoop集群(ubuntu16.04 LTS系統(tǒng))

10.1 配置core-site.xml、yarn-site.xml和mapred-site.xml文件

每個(gè)容器對這三個(gè)文件的修改都是一致的。這三個(gè)文件都存在于 /usr/local/hadoop/etc/hadoop/ 之下:

  • core-site.xml
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
<!-- Put site-specific property overrides in this file. -->
<configuration>
        <property>
                <name>fs.defaultFS</name>
                <value>hdfs://master:9000</value>
         </property>
        <property>
                <name>io.file.buffer.size</name>
                <value>131072</value>
        </property>
        <property>
                <name>hadoop.tmp.dir</name>
                <value>/usr/local/hadoop/tmp</value>
        </property>
</configuration>
  • yarn-site.xml
<?xml version="1.0"?>
<configuration>
    <property>
        <name>yarn.nodemanager.aux-services</name>
        <value>mapreduce_shuffle</value>
    </property>
    <property>
        <name>yarn.resourcemanager.address</name>
        <value>master:8032</value>
    </property>
    <property>
        <name>yarn.resourcemanager.scheduler.address</name>
        <value>master:8030</value>
    </property>
    <property>
        <name>yarn.resourcemanager.resource-tracker.address</name>
        <value>master:8031</value>
    </property>
    <property>
        <name>yarn.resourcemanager.admin.address</name>
        <value>master:8033</value>
    </property>
    <property>
        <name>yarn.resourcemanager.webapp.address</name>
        <value>master:8088</value>
    </property>
    <property>
        <name>yarn.nodemanager.aux-services.mapreduce.shuffle.class</name>
        <value>org.apache.hadoop.mapred.ShuffleHandler</value>
    </property>
</configuration>
  • mapred-site.xml

事實(shí)上文件夾下只有一個(gè)mapred-site.xml.template 模板文件,可以復(fù)制一個(gè)模板文件為 mapred-site.xml,然后填充信息。

<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
<!-- Put site-specific property overrides in this file. -->
<configuration>
    <property>
        <name>mapreduce.framework.name</name>
        <value>yarn</value>
    </property>
</configuration>

10.2 配置hdfs-site.xml

hdfs-site.xml 的配置稍有不同,因?yàn)樗菂^(qū)分namenode和datanode的。我們指定master為namenode,slave?為datanode,所以:

  • 對于master
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
<!-- Put site-specific property overrides in this file. -->
<configuration>
    <property>
        <name>dfs.replication</name>
        <value>2</value>
    </property>
    <property>
        <name>dfs.namenode.name.dir</name>
        <value>file:/usr/local/hadoop/hdfs/name</value>
    </property>
</configuration>
  • 對于slave?
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
<configuration>
    <property>
        <name>dfs.replication</name>
        <value>2</value>
    </property>
    <property>
        <name>dfs.datanode.data.dir</name>
        <value>file:/usr/local/hadoop/hdfs/data</value>
    </property>
</configuration>

10.3 創(chuàng)建相關(guān)目錄并格式化

我們在上面的 hdfs-site.xml 看到,配置文件制定了兩個(gè)目錄:

  • 對于namenode(master),指定了 /usr/local/hadoop/hdfs/name
  • 對于datanode(slave1、slave2),指定了 /usr/local/hadoop/hdfs/data

分別創(chuàng)建這兩個(gè)目錄。然后針對不同的節(jié)點(diǎn)進(jìn)行格式化:

  • 對于master(NameNode):
root@master:~# hdfs namenode -format
  • 對于slave?(datanoe):
root@slave2:~# hdfs datanode -format

如果沒有異常信息,格式化成功。

10.4 啟動集群

在master中,使用命令

root@master:~# /usr/local/hadoop/sbin/start-all.sh

來啟動集群,按照提示不斷輸入yes

我們可以使用jps來查詢集群情況

root@master:~# jps
1169 Jps
774 ResourceManager
328 NameNode
458 DataNode
877 NodeManager
623 SecondaryNameNode
root@master:~# 

也可以使用如下命令來查詢其他容器節(jié)點(diǎn)情況:

root@master:~# hadoop dfsadmin -report
Configured Capacity: 38390448128 (35.75 GB)
Present Capacity: 28696190976 (26.73 GB)
DFS Remaining: 28696141824 (26.73 GB)
DFS Used: 49152 (48 KB)
DFS Used%: 0.00%
Under replicated blocks: 0
Blocks with corrupt replicas: 0
Missing blocks: 0
Missing blocks (with replication factor 1): 0

-------------------------------------------------
Live datanodes (2):

Name: 172.17.0.5:50010 (master)
Hostname: master
Decommission Status : Normal
Configured Capacity: 19195224064 (17.88 GB)
DFS Used: 24576 (24 KB)
Non DFS Used: 3832627200 (3.57 GB)
DFS Remaining: 14348070912 (13.36 GB)
DFS Used%: 0.00%
DFS Remaining%: 74.75%
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: 1
Last contact: Sat Nov 16 09:14:27 GMT 2019


Name: 172.17.0.7:50010 (slave2)
Hostname: slave2
Decommission Status : Normal
Configured Capacity: 19195224064 (17.88 GB)
DFS Used: 24576 (24 KB)
Non DFS Used: 3832627200 (3.57 GB)
DFS Remaining: 14348070912 (13.36 GB)
DFS Used%: 0.00%
DFS Remaining%: 74.75%
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: 1
Last contact: Sat Nov 16 09:14:27 GMT 2019

至此,我們的Hadoop集群就搭建完成啦!(????)?"""

附錄

1. SSH服務(wù)

1.1 什么是ssh

關(guān)于ssh的相關(guān)介紹,可以參考博客:Linux之ssh服務(wù)介紹。下面綜合該博文做個(gè)簡單解釋。

SSH(Secure Shell Protocol)是一種網(wǎng)絡(luò)協(xié)議,默認(rèn)狀態(tài)下SSH服務(wù)提供倆個(gè)服務(wù)功能:

  • 類似telnet遠(yuǎn)程聯(lián)機(jī)服務(wù)器的服務(wù)(ssh服務(wù))
  • 類似FTP服務(wù)的sftp-server,借助SSH協(xié)議來傳輸數(shù)據(jù)的。

我們最開始使用XShell連接Docker時(shí)使用的命令ssh 192.168.99.100就是用到了第一種遠(yuǎn)程連接服務(wù)。

ssh使用了到了一種被稱為 非對稱加密 的算法。該算法需要兩個(gè)密鑰,任意指定一把為公鑰,則另一把就稱為私鑰。經(jīng)過公鑰加密的信息只能通過私鑰解開。因?yàn)橹付ㄊ侨我獾?,所以由私鑰加密的信息也一定只能由公鑰解開。因此,公鑰、私鑰只是為了區(qū)分而指定的,實(shí)際上兩把秘鑰中的任意一把加密的數(shù)據(jù)只能由另一把解開,反之亦然。

1.2 SSH登錄連接模型與中間人攻擊

服務(wù)器會產(chǎn)生一對公鑰和私鑰,當(dāng)用戶發(fā)起連接時(shí),服務(wù)器將公鑰發(fā)送給用戶,用戶用該公鑰加密自己的密碼,返給服務(wù)器。服務(wù)器用配對的私鑰對其解密,如果正確則允許登錄。

但是這里會有一個(gè)隱患,那就是如果有人冒充服務(wù)器,發(fā)給了用戶一個(gè)偽造的公鑰,用戶將自己密碼用該公鑰加密后返給此中間人,他用私鑰解碼后就能獲取用戶的密碼明文,這就是“中間人攻擊”。

這里防范的關(guān)鍵是,用戶如何鑒別該公鑰是服務(wù)器發(fā)送的。如果是Https協(xié)議,尚有一種名為數(shù)字證書的技術(shù)來保證(關(guān)于數(shù)字證書,可以參考一篇寫的很棒的博客: 一個(gè)故事教你看懂什么是數(shù)字證書,它的原理是什么?它的作用是什么?

但是很遺憾,SSH協(xié)議的公鑰是沒有證書中心(CA)公證的,也就是說,都是服務(wù)器自己簽發(fā)的。所以,沒有好辦法,遠(yuǎn)程主機(jī)必須在自己的網(wǎng)站上貼出公鑰指紋(公鑰指紋指對用RSA算法生成長達(dá)1024位的公鑰執(zhí)行MD5算法而生成的128位摘要信息),以便用戶自行核對。

也就是說,用戶需要自行鑒別服務(wù)器公鑰。所以第一次連接時(shí),系統(tǒng)會給出警告,讓用戶自己評估風(fēng)險(xiǎn)。

當(dāng)遠(yuǎn)程主機(jī)的公鑰被接受以后,它就會被保存在文件 ~/.ssh/known_hosts 之中。下次再連接這臺主機(jī),系統(tǒng)就會認(rèn)出它的公鑰已經(jīng)保存在本地了,從而跳過警告部分,直接提示輸入密碼。

1.3 公鑰登錄

用戶每次ssh連接都需要輸入密碼,用服務(wù)器公鑰加密在返給服務(wù)器,非常麻煩。所以希望有一種能夠輸入一次密碼,下次就再不用輸入的手段。

如何實(shí)現(xiàn)呢?這一次,需要服務(wù)器來識別用戶。我們可以將SSH登錄連接模型中的服務(wù)器和用戶調(diào)換角色來想:在服務(wù)器和用戶已經(jīng)建立了連接時(shí),用戶自己可以生成一對公鑰和私鑰,然后將用戶公鑰告訴服務(wù)器。服務(wù)器將其存儲在用戶目錄下的 ~/.ssh/authorized_keys 文件中。

下一次登錄時(shí),服務(wù)器發(fā)現(xiàn)該用戶在自己這里已經(jīng)存儲了一個(gè)公鑰,于是服務(wù)器生成一個(gè)隨機(jī)字符串給用戶,要求用戶用配對的私鑰加密在返給自己,自己這邊使用公鑰進(jìn)行解密,比對結(jié)果是否一致,如果一致就允許用戶登錄。(這里用到了開始時(shí)我們說的公鑰、私鑰其中任意一把加密的信息可以由、且只能由另一把解開)

用戶需要用命令ssh-keygen來生成一對公鑰和私鑰,默認(rèn)的類型是RSA,也可以顯式指定

ssh-keygen -t rsa

此時(shí)系統(tǒng)可能要求輸入passphrase(口令)保證私鑰安全(因?yàn)楣€和私鑰會用文本文件存儲,因此沒有保護(hù)的私鑰,任何有權(quán)限打開私鑰文件的人都能看到),在本文中,我們不需要對私鑰進(jìn)行保護(hù),也就直接回車跳過。

生成的公鑰私鑰在 ~/.ssh/ 目錄下,分別叫做 id_rsa.pubid_rsa。

下面的事情,就是想辦法讓服務(wù)器端在用戶主目錄下的 ~/.ssh/authorized_keys文件中寫入id_rsa.pub內(nèi)容。這有多種辦法,比如,直接手動復(fù)制進(jìn)去,因?yàn)槭俏谋疚募?。(d(′ω`*))

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容