Ambari自动化离线批量部署Hadoop平台总结


面临的问题

有了Ambari的平台,理论上来说,其实应该很方便的就可以部署Hadoop平台,但是实际上对于一个集群来说,并没有那么简单。
现在,我们是有一堆机器(手动配置非常麻烦),如何将这堆机器利用Ambari快速的搭建成Hadoop平台是我们现在面临的问题。

Client的预配置:对于每台机器,要做很多预先的配置,例如关闭防火墙,更新、安装软件等。
另外,为了实现多个机器之间的无密码访问,我们要设置ssh-key,并且将自己的pub key分发给集群中的各个机器。我们希望这些操作都可以自动化的完成。

每台机器设置hosts:在自动化配置中,机器之间相互通信是根据域名(FQDN, Fully Qualified Domain Name)的,而域名用简单的hostname name命令设置是不对的,这个设置的是hostname命令显示出来的东西,而我们要的是hostname -f命令显示出来的名字,这个需要在hosts文件中或DNS解析中得到。在不自己搭建DNS的情况下,因此我们每台机器都要配置hosts。

没有快速的互联网连接:很多时候集群面临的环境并不是一个和Internet直接相连的环境,因此,对于Ambari这种需要在线从互联网上下载的情况,或者Internet网速不佳的情况,我们就要有相应的办法应对,一个简单的办法就是实现下好离线文件,自己搭建yum source. 在我这里的环境下可以有镜像更新yum,因此我们只要考虑要安装的Ambari整个库的配置就好。


集群配置

根据上面的问题,我们提出自己搭建yum source源,并利用脚本自动化部署的方法。

一共有3类机器,一台作为yumsource,一台作为master,其余的作为slaves.

配置如下

1
|机器|FQDN(域名)|描述|
|-|-|
|yum源|yumsource.hadoop|部署HDP、HDP-util、Ambari的源|
|master|master.hadoop|作为hadoop的master机器,安装ambari-server|
|N台slave|slaveX.hadoop|作为hadoop的slave机器,会自动安装ambari-agent|

这里每台机器2核CPU,4G内存(这个要大一些,使用过1G结果卡死了,服务多的机器8G最好),50-100GB硬盘,系统采用CentOS7完全版


用到的技术

  • bash script
  • expect
  • httpd

Goal

  1. 按照官方文档的说明,每台机器的需要配置的项如下:
  • 设置ip等网络配置,并且设置开机自动启动网络
  • 生成ssh-key,并且将public key传送给其他机器
  • 关闭SELinux(需要重启)
  • 关闭iptables(CentOS7中是firewalld),并设置开机启动
  • 安装ntp,启动ntpd,并设置开机启动
  • 更新openssl
  • 设置hosts
    注:其中有一些可以统一用脚本处理,有一些(例如ip的设置)就需要每台手动做了
  1. 配置好了基本配置后,我们还需要配置下Ambari、HDP、HDP-UTILS的服务器(yum source),使其成为一个yum-source server.

  2. 接下来就是安装Ambari了

下面会详细叙述整个过程。


Steps

安装Amabri之前我们需要做一些准备工作,主要分为:

  • 每台机器的预备工作,以使各机器连接到网络中,可以自动化部署
  • Server端执行自动化脚本,执行一些Server端的处理
  • Server端调用各个Client远程执行脚本,对于每个Client进行配置

Pre-work of each client

每台机器做简单的ip配置即可,只要实现其在集群的网络中并且可以连通,以及yum install xxx好使就可以了。

在我这里环境下,我是需要手动配置静态ip的,并且设置了DNS就可以使用yum install(如果不可以的话,那么就要自己配置centosssyum source了),另外我希望在不同网段的机器远程访问该服务器,因此我设置了两方面内容:

/etc/sysconfig/network-script/ifcfg-eth0中设置ip(eth0为对应的网卡,CentOS7中一般为enoXXXXXX)及DNS,并设置自动启动该网卡(ONBOOT=yes):

1
2
3
4
5
6
BOOTPROTO=static

ONBOOT=yes
IPADDR=xx.xx.xxx.xxx
NETMASK=255.255.255.0
DNS1=xx.xx.x.xx

/etc/sysconfig/network中设置gateway(用于其他网段的机器访问该机器,可选):

1
GATEWAY=xx.xx.xxx.x

Server端自动化脚本

这里的server是指master、slave之外的机器,我这里采用yumsource那台机器作为Server。

在Server端,主要做以下几件事情:

  1. 生成server的ssh-key, 并且分发给各个client(使用scp命令,并且用expect处理交互),为后面的无密码访问client做准备
  2. 给各个client传送hosts文件
  3. 给各个client传送selinux的配置文件(通过这种方式设置关闭)
  4. 调用client该执行的脚本,并用ssh远程执行: ssh root@$hostip 'bash -s' < client.sh
  5. 将client生成的公钥(public key)收集回server:同样使用scp,如下
    scp -r root@$hostip:~/.ssh/id_rsa.pub ~/.ssh/pub/$hostname.pub
  6. 当所有client都处理完毕后,收集、整合所有的公钥再分发给各个client(下文的deploypubkeys.sh)
  7. 最后再依次远程重启每个机器(ssh root@$hostip 'reboot' < /dev/null),以应用配置

建立一个hostlist文件(其实就是我们要传送的hosts)

1
2
3
10.xx.xxx.xxx master.hadoop
10.xx.xxx.xxx slave1.hadoop
10.xx.xxx.xxx slave2.hadoop

在这里我们用脚本读取hostlist文件的每个机器(包括master、slave)的ip与域名(hostname),然后依次执行上述的操作:

1
2
3
4
5
cat hostlist | while read hostinfo
do
hostip=`echo $hostinfo|cut -d " " -f1`
hostname=`echo $hostinfo|cut -d " " -f2`
...

具体实现主要采用bash脚本以及expect程序,expect程序用于需要输入密码等交互时使用,
这里将传送文件的那几个任务(1-3)都用expect程序实现(即下文的deployclient.sh),其余的用bash脚本实现。

关闭SELinux的配置文件需要提前存好,名字为disSELinuxCfg,内容如下:

1
2
SELINUX=disabled
SELINUXTYPE=targeted

下面就是脚本们,把所有的代码、配置放在一个文件夹下,运行initserver.sh即可。

initserver.sh

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
#!/usr/bin/bash

filepath=~/.ssh/id_rsa
# read -p "Plase specify the ip of this server:" serverip
serverip=xx.xx.xxx.xxx
read -p "Enter the client password(all should be same):" -s pwd

if [ -f $filepath ]; then
echo
echo "ssh-key already exists. it won't be generated again."
echo "if you want to generate new key, please remove the key file first."
else
echo
echo "===ssh key generating..."
ssh-keygen -f ~/.ssh/id_rsa -P ""
fi

rm -rf ~/.ssh/pub/
mkdir ~/.ssh/pub/
cp ~/.ssh/id_rsa.pub ~/.ssh/pub/id_rsa.pub
cat hosts_template hostlist > hosts

echo
echo "===Deploying Client..."
cat hostlist | while read hostinfo
do
hostip=`echo $hostinfo|cut -d " " -f1`
hostname=`echo $hostinfo|cut -d " " -f2`
echo "===Deploy Client $hostip..."

chmod +x deployclient.sh
./deployclient.sh $hostip $pwd

head1="clientip=$hostip\n"
head2="serverip=$serverip\n"
head3="password=$pwd\n"
head=$head1$head2$head3
echo -e $head > head.tmp
cat head.tmp client_template.sh > client.sh
ssh root@$hostip 'bash -s' < client.sh

echo
echo "===Transfer pub key to server..."
scp -r root@$hostip:~/.ssh/id_rsa.pub ~/.ssh/pub/$hostname.pub
done

echo
echo "===gathering pub keys..."
cat ~/.ssh/pub/*.pub > authorized_keys
echo "===deploy pub keys..."
cat hostlist | while read hostip
do
./deploypubkeys.sh $hostip $pwd
done

echo
echo "===Cleaning..."
rm -f head.tmp
rm -f client.sh
rm -f hosts
rm -f authorized_keys
echo "===Clean finished."

echo
echo "===reboot all the machine..."
cat hostlist | while read hostinfo
do
hostip=`echo $hostinfo|cut -d " " -f1`
hostname=`echo $hostinfo|cut -d " " -f2`
ssh root@$hostip 'reboot' < /dev/null
done
echo "===reboot finished."

expect脚本deployclient.sh(用于给各个client传送各种文件)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#!/usr/bin/expect

set clientip [lindex $argv 0]
set pwd [lindex $argv 1]

# deploy current pub key
spawn ssh root@$clientip "mkdir ~/.ssh"
expect {
"*continue connecting*" { send "yes\r"; exp_continue }
"*password*" { send "$pwd\r"; exp_continue }
"#" { send "\r" }
}

# deploy current pub key
spawn scp /root/.ssh/id_rsa.pub root@$clientip:~/.ssh/authorized_keys
expect {
"*continue connecting*" { send "yes\r"; exp_continue }
"*password*" { send "$pwd\r"; exp_continue }
"#" { send "\r" }
}

# deploy selinux config
spawn scp disSELinuxCfg root@$clientip:/etc/selinux/config
expect {
"*continue connecting*" { send "yes\r"; exp_continue }
"*password*" { send "$pwd\r"; exp_continue }
"#" { send "\r" }
}

# deploy hosts
spawn scp hosts root@$clientip:/etc/hosts
expect {
"*continue connecting*" { send "yes\r"; exp_continue }
"*password*" { send "$pwd\r"; exp_continue }
"#" { send "\r" }
}

expect脚本deploypubkeys.sh(用于server给各个client分发汇总的公钥)

1
2
3
4
5
6
7
8
9
10
11
!/usr/bin/expect

set serverip [lindex $argv 0]
set pwd [lindex $argv 1]

spawn scp authorized_keys root@$serverip:~/.ssh/authorized_keys
expect {
"*continue connecting*" { send "yes\r"; exp_continue }
"*password*" { send "$pwd\r"; exp_continue }
"#" { send "\r" }
}

Client端脚本(远程调用)

给每个client执行的脚本client_template.sh,在Server端通过ssh远程调用。

这里之所以是个template,这是因为我们在server端会根据不同的client生成前面的一些信息(包括clientip,serverip等),将信息放在这个template最前面,然后供client执行。(这里其实就是为了显示那一句echo,表示当前处理到哪个机器了……因此client_template.sh是可以直接被client执行的,不会有任何实质上的影响)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
hostname=`hostname -f`
firewall="firewalld" #centos7中是firewalld,之前是iptables

echo
echo "client $clientip hostname: $hostname, server: $serverip"

echo
echo "===disable $firewall & it won't start after boot..."
service $firewall stop
chkconfig $firewall off

echo
echo "===install, start, config ntpd..."
yum -y install ntp
systemctl disable chronyd #centos7中要关闭这个否则冲突
service ntpd restart
chkconfig ntpd on

echo
echo "===deal with ssh key..."
rm -f ~/.ssh/id_rsa*
ssh-keygen -f ~/.ssh/id_rsa -P ""

echo
echo "===update openssl..."
yum -y update openssl

echo
echo "===deal with sshd..."
service sshd restart
chkconfig sshd on

echo
echo "===set network start automatically..."
chkconfig network on

echo
echo "===Finished!!!"

Yum Source的配置

由于教育网可以直接更新CentOS的软件,因此我这里没有配置CentOS的yum-source。这里我们仅仅配置Ambari和HDP、HDP-UTIL包的source。

首先下载各个安装包,地址可以在文档中找到,如2.2.0.0的网址是:
http://docs.hortonworks.com/HDPDocuments/Ambari-2.2.0.0/bk_Installing_HDP_AMB/content/_obtaining_the_repositories.html

然后将各个安装包解压放在/var/www/html下的hdp文件夹(自己建一个hdp文件夹),然后利用httpd(没有的话自己安装一下)把html整个目录对外开放。如果在另一台机器访问这台机器的域名,能看到整个目录以及文件信息,那么就说明ok了。

Ambari安装与配置

在安装之前,我们还需要告诉yum去哪里下载我们的ambari,建立一个ambari.repo并放在/etc/yum.repos.d/下面,内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
[Ambari-2.2.0.0]
name=Ambari-2.2.0.0
baseurl=http://yumsource.hadoop/hdp/ambari-2.2.0.0/centos7/2.2.0.0-1310/
gpgcheck=0
enabled=1

[HDP-2.3.4.0]
name=HDP-2.3.4.0
baseurl=http://yumsource.hadoop/hdp/HDP/centos7/2.x/updates/2.3.4.0/
gpgcheck=0
enabled=1

[HDP-UTILS-1.1.0.20]
name=HDP-UTILS-1.1.0.20
baseurl=http://yumsource.hadoop/hdp/HDP-UTILS-1.1.0.20/repos/centos7/
gpgcheck=0
enabled=1

配置好后, 调用yum install -y ambari-server即可开始安装ambari及其附属组件。
安装好后,调用ambari-server setup即可开始设置ambari,在这个过程中需要下载JDK,
我们可以提前下好JDK,然后放在对应的目录下:/var/lib/ambari-server/resources/,这样可以节约很多时间.

安装成功后,执行ambari-server start即可启动,接着就在浏览器中查看master这台机器的8080端口即可访问配置页面,按照提示一步步做就好。

节点重启怎么办

主节点调用ambari-server restart
子节点调用ambari-agent restart
剩下的具体Hadoop服务,直接在网页端就可以配置了


背景知识

expect

expect是一个解释器,可以处理交互式输入,例如:

1
spawn scp authorized_keys root@$serverip:~/.ssh/authorized_keys
expect {
"*continue connecting*" { send "yes\r"; exp_continue }
"*password*" { send "$pwd\r"; exp_continue }
"#" { send "\r" }
}

在调用scp命令时,会问你输入密码等;我们可以用spawn加个壳来调用scp,用expect来匹配可能的输出(例如\*password\*,这里*是通配符),从而做出动作;send "command"用于发送指令,exp_continue表示继续匹配,否则就直接进行下一条语句了。

另外,spawn套spawn貌似不是很好使。

无密钥SSH登录

ssh原理就是,自己生成一对公钥、私钥. 将公钥给要登录的服务器,自己是私钥. 登录时,client发送公钥给server,服务器看到自己这有匹配的公钥,加密一段信息返回给client. client用私钥解密,再给服务器,从而建立一个连接.

因此client要把公钥复制到服务器的~/.ssh/目录下,文件名为authorized_keys,如果有多个(多个client都想这么配置),直接cat起来就好。

配置好后,ssh 对方域名/ip,即可测试是否成功。

FQDN

Fully Qualified Domain Name, 是对应hosts文件中的名字
hostname -f查看

bash中指令结果存到变量

variable=`hostname -f`
echo $variable

用``把命令包起来即可。