最近要在10幾臺機器上安裝hadoop。對于這種繁復而重復的工作,一步步的打命令行,對于程序員來說是一件不能忍的事情。所以我就琢磨著怎么寫一個腳本來自動安裝hadoop。
任務: 在10幾臺機器上中的任意一臺執行腳本,即可安裝好hadoop。
條件: 每臺機器的用戶名和密碼都是一樣的。每臺機器都配置好了ssh,能夠遠程登錄。
解決思路:
1. 首先讀取配置文件,讀取到節點的ip和想要的機器名字,然后修改好本地hadoop的配置文件。
2. 然后讀取配置文件,復制所有文件到每個節點的安裝的路徑。(利用scp命令可以遠程復制)
3. 然后讀取配置文件,自動ssh到每個節點做一些配置工作,包括配置hadoop和JDK 環境變量、生成ssh-key。
4. ssh到主節點,將每個節點(包括主節點自己)生成的public key 都復制并追加到自己的authorized_keys. 然后把這個authorized_keys分發到每個節點。
這樣就配置好了hadoop。
題外話,介紹一下 ssh-keygen。ssh-keygen是一個ssh用于生成密鑰的命令。用途是用于免密碼登錄。它會生成兩個密鑰,一個是公鑰,一個是私鑰。比如A 機器生成了pubKeyA,PRiKeyB。然后A 把pubKeyA給了機器B ,然后機器B 就可以無密碼登錄機器A 了。
在上面的步驟中,主要的難題是。
1. 對于步驟一,主要難題在于怎么用shell讀取配置文件。由于我也之前沒寫過shell,所以Shell的循環和if 語句和字符串處理也卡了不少時間。
# 這段代碼是怎么從hosts的節點配置文件中讀取節點的信息# hosts的格式如下# 192.168.1.100 master# 192.168.1.101 slave1# 192.168.1.102 slave2# ...while read linedo echo $line ip=`echo $line | cut -d" " -f1` name=`echo $line | cut -d" " -f2` if [ ! -z $ip ]; then echo $name if [[ $name == maste* ]]; then echo "$name" >> ../hadoop-1.2.1/conf/masters elif [[ $name == slave* ]]; then echo "$name" >> ../hadoop-1.2.1/conf/slaves fi fidone < hosts
2. 對于步驟2,由于剛開始節點直接沒有實現無密碼ssh,所以scp命令需要輸入密碼,所以怎么實現自動輸入密碼實在是一個棘手的問題。我搜索之后,發現一個工具叫expect。
expect工具就像bash一樣有自己的語法,然后有自己的命令。它的語法是基于TCL這種腳本語言(我也沒聽過),看幫助可以直接man expect。我覺得主要需要知道的expect命令是spawn,expect,exp_continue這三個。
#!/usr/bin/expect# expect 定義函數的方式如下proc usage {} { puts stderr "usage: $::argv0 ip usrname passWord" exit 1}if {$argc != 3} { usage }#利用腳本傳參數set hostip [lindex $argv 0]set username [lindex $argv 1]set password [lindex $argv 2]set timeout 100000# 利用expect的spawn命令來代理執行命令spawn scp -r ../../hadoop ${username}@${hostip}:~#獲取期望的輸出expect {#如果輸出是 要輸入密碼#注意下面的大括號 不能換行寫,必須用java風格,而且與前面的“之間要有一個空格,我當時犯了這錯誤,程序執行的結果很奇怪卻不報錯。 "*assword:" { send "$password/n"#輸入密碼后期待spawn代理的命令結束 expect eof }#如果不需要輸入密碼,那也是一樣期待命令結束 expect eof}
對于步驟3、4已經沒什么挑戰性了,很快就完成了。
下面我把所有代碼貼上來
1. setHadoopOnce.sh 這個文件是腳本執行的起點
1 #!/bin/bash 2 #修改密碼 3 pw=123456 4 loginName=hadoop 5 master=master 6 slave=slave 7 slaveNum=1 8 set timeout 100000 9 > ../hadoop-1.2.1/conf/masters10 > ../hadoop-1.2.1/conf/slaves11 #update local file12 while read line13 do14 echo $line15 ip=`echo $line | cut -d" " -f1`16 name=`echo $line | cut -d" " -f2`17 if [ ! -z $ip ]; then18 echo $name19 if [[ $name == maste* ]]; then20 echo "$name" >> ../hadoop-1.2.1/conf/masters21 elif [[ $name == slave* ]]; then22 echo "$name" >> ../hadoop-1.2.1/conf/slaves23 fi24 fi25 done < hosts26 #upload file to all nodes27 while read line28 do29 ip=`echo $line | cut -d" " -f1`30 name=`echo $line | cut -d" " -f2`31 if [ ! -z $ip ]; then32 expect copyDataToAll.exp $ip $loginName $pw33 expect setForAll.exp $ip $loginName $pw34 fi35 done < hosts36 37 while read line38 do39 ip=`echo $line | cut -d" " -f1`40 name=`echo $line | cut -d" " -f2`41 if [ ! -z $ip ]; then42 if [[ $name == maste* ]]; then43 expect setForMaster.exp $ip $loginName $pw44 fi45 fi46 done < hosts
2. copyDataToAll.exp 這個在setHadoopOnce.sh中的32行被調用,以復制文件到所有節點。
1 #!/usr/bin/expect 2 proc usage {} { 3 puts stderr "usage: $::argv0 ip usrname password" 4 exit 1 5 } 6 if {$argc != 3} { usage } 7 set hostip [lindex $argv 0] 8 set username [lindex $argv 1] 9 set password [lindex $argv 2]10 set timeout 10000011 spawn scp -r ../../hadoop ${username}@${hostip}:~12 expect {13 "*assword:" {14 send "$password/n"15 expect eof16 }17 expect eof18 }
3. setForAll.exp 為所有節點進行一些配置工作,在setHadoopOnce.sh中的33行被調用.
#!/usr/bin/expectproc usage {} { puts stderr "usage: $::argv0 ip usrname password" exit 1}proc connect {pwd} { expect { "*(yes/no)?" { send "yes/n" expect "*assword:" { send "$pwd/n" expect { "*Last login:*" { return 0 } } } } "*assword:" { send "$pwd/n" expect { "*Last login:*" { return 0 } } } "*Last login:*" { return 0 } } return 1}if {$argc != 3} { usage }set hostip [lindex $argv 0]set username [lindex $argv 1]set password [lindex $argv 2]set timeout 100000spawn ssh ${username}@${hostip}if {[connect $password]} { exit 1}#set hostsend "sudo bash ~/hadoop/setup/addHosts.sh/r"expect "*assword*"send "$password/r"expect "*ddhostsucces*"sleep 1send "ssh-agent bash ~/hadoop/setup/sshGen.sh/n"expect { "*(yes/no)?" { send "yes/n" exp_continue } "*verwrite (y/n)?" { send "n/n" exp_continue } "*nter file in which to save the key*" { send "/n" exp_continue } "*nter passphrase*" { send "/n" exp_continue } "*nter same passphrase again*" { send "/n" exp_continue } "*our public key has been saved*" { exp_continue } "*etsshGenSucces*" { sleep 1 }}send "bash ~/hadoop/setup/setEnvironment.sh/n"expect "*etEnvironmentSucces*"sleep 1send "exit/n"expect eof
3.1 addHosts.sh 在setForAll.exp中被調用,用于設置節點的hosts文件
#!/bin/bashhadoopRoot=~/hadoophadoopPath=$hadoopRoot/hadoop-1.2.1setupPath=$hadoopRoot/setuplocalip="`ifconfig |head -n 2|tail -n1 |cut -f2 -d: |cut -f1 -d" " `"hostline="`grep "$localip$" $hadoopRoot/setup/hosts`"sed -i /$hostline//d $hadoopRoot/setup/hosts#cp /etc/hosts /etc/hosts.hadoop.bakfor delip in `cat $hadoopRoot/setup/hosts`do delipline="`grep -n "$delip[[:space:]]" /etc/hosts |cut -f1 -d:`" #echo $delipline if [ -n "$delipline" ]; then sed -i $delipline/d /etc/hosts sleep 1s #else #echo "Your List have no the ip $delip" fidonecat $hadoopRoot/setup/hosts >> /etc/hostsrm -f "$setupPath"/sed*echo "addhostsuccess"
3.2 sshGen.sh 在setForAll.sh中被調用,用于生成sshkey。
#!/bin/bashsshPath=~/.sshsetupPath=~/hadoop/setuprm "$sshPath"/authorized_keyssleep 1ssh-keygen -t rsacat "$sshPath"/id_rsa.pub >> "$sshPath"/authorized_keysssh-addecho "setsshGenSuccess"
3.3 setEnvironment.sh 在setForAll.sh中被調用,用于設置環境變量
#!/bin/bashhadoopRoot=~/hadoophadoopPath=$hadoopRoot/hadoop-1.2.1setupPath=$hadoopRoot/setupJAVA_VERSION=`java -version 2>&1 | awk '/java version/ {print $3}'|sed 's/"http://g'|awk '{if ($1>=1.6) print "ok"}'`if [ "$JAVA_VERSION"x != "okx" ]; then cat "$setupPath"/jdkenv >> ~/.bashrc sleep 1 source ~/.bashrc sleep 1fiHadoop_Version=`hadoop version|awk '/Hadoop/ {print $2}'|awk '{if ($1>=1.0) print "ok"}'`if [ "$Hadoop_Version"x != "okx" ]; then cat "$setupPath"/hadoopenv >> ~/.bashrc sleep 1 source ~/.bashrc sleep 1fiecho "setEnvironmentSuccess"
4. setForMaster.exp 遠程ssh調用setForMaster.sh,以配置無密碼登錄的功能。
#!/usr/bin/expectproc usage {} { puts stderr "usage: $::argv0 ip usrname password" exit 1}proc connect {pwd} { expect { "*(yes/no)?" { send "yes/n" expect "*assword:" { send "$pwd/n" expect { "*Last login:*" { return 0 } } } } "*assword:" { send "$pwd/n" expect { "*Last login:*" { return 0 } } } "*Last login:*" { return 0 } } return 1}if {$argc != 3} { usage }set hostip [lindex $argv 0]set username [lindex $argv 1]set password [lindex $argv 2]set timeout 100000spawn ssh ${username}@${hostip}if {[connect $password]} { exit 1}send "ssh-agent bash ~/hadoop/setup/setForMaster.sh/n"expect { "*etForMasterSucces*" { sleep 1 send "exit/n" } "*assword*" { send "$password/n" exp_continue } "*(yes/no)?" { send "yes/n" exp_continue }}
4.1 setForMaster.sh
#!/bin/bashwhile read linedo ip=`echo $line | cut -d" " -f1` name=`echo $line | cut -d" " -f2` if [ ! -z $ip ]; then if [[ $name == slave* ]]; then scp $ip:~/.ssh/authorized_keys ~/tmpkey cat ~/tmpkey >> ~/.ssh/authorized_keys fi fidone < ~/hadoop/setup/hostssleep 1rm -f ~/tmpkeywhile read linedo ip=`echo $line | cut -d" " -f1` name=`echo $line | cut -d" " -f2` if [ ! -z $ip ]; then if [[ $name == slave* ]]; then scp ~/.ssh/authorized_keys $ip:~/.ssh/authorized_keys fi fidone < ~/hadoop/setup/hostsecho "setForMasterSuccess"
安裝包打包下載地址: http://pan.baidu.com/s/1dDj6LHJ
新聞熱點
疑難解答