對於大規模的集羣,相信都有一整套比較完善的自動化部署方案。自動化部署有很多問題值得思考,比如如何均衡的利用每個節點的資源,保證整個集羣的負載打散;如果方便的加入新機器,如何在機器物理故障時下線它,然後將部署的任務遷移到其他的備機,有點資源管理的意味了。
本文不會討論這些問題。只涉及一個很簡單的場景:如何將應用部署到一定數量的機器,然後啓動它。比如你在上線前,需要壓力測試,需要評測性能,都可能需要人工的部署幾十臺機器。
如果純人工,那麼可能需要scp,或者wget,或者hadoop client,將應用下載到目標機器,然後解壓,然後啓動它。本文的目的就是腳本化上述操作。
1. 最簡單
我們知道,ssh可以遠程執行一些命令
ssh hostname "command lines"
可能唯一的障礙就是需要輸入密碼。當然了你可能說可以設置ssh免密碼登陸,那麼你至少要每臺機器操作一下吧,還是沒有繞過輸入密碼。
使用sshpass 可以解決輸入密碼的問題。
$ sshpass
Usage: sshpass [-f|-d|-p|-e] [-hV] command parameters
-f filename Take password to use from file
-d number Use number as file descriptor for getting password
-p password Provide password as argument (security unwise)
-e Password is passed as env-var "SSHPASS"
With no parameters - password will be taken from stdin
-h Show help (this screen)
-V Print version information
sshpass不是默認安裝的。
接下來的工作就很簡單了,
sshpass -p your_password ssh "command1; command2;..."
那設置ssh 密碼登陸來說,實際上就是先wget 中控機的id_rsa.pub, 然後加到目標機的authorized_keys即可。幾條命令的羅列。
如果你可以通過上述命令解決你的問題,那麼恭喜你,否則,接着向下看吧。
2. 人工交互不可避免怎麼辦
有時候邏輯的確是複雜,有的應用還是需要人工交互才能搞定。。。我們需要完全人工化,那麼使用expect可以滿足你的要求。
相信大家都熟悉awk,sed等一衆非常有用的linux 命令,那麼expect也是。下面以設置ssh密碼登陸爲例,講解expect的用法。
uploadRsaKey()
{
expect <<EOF
set timeout 20
spawn scp /home/work/.ssh/id_rsa.pub $1:~
expect {
"password:" {
send "your_password\r"
expect eof
}
"*continue connecting*" {
exec sleep 1
send "yes\r"
expect "password:" {
exec sleep 1
send "your_password\r"
expect eof
}
}
}
EOF
}
第7行實際上是一個模糊匹配的過程,如果當前的交互中出現password,那麼send 你的密碼過去,注意一定要以\r結尾。當然瞭如果是continue connecting,那麼首先發送yes,然後再發送密碼過去。使用exec sleep 1,可以sleep 1 秒。
現在只是將key上傳到額目標機器上了,那麼如何install rsa key呢?
installRsaKey()
{
expect <<EOF
set timeout 100
spawn ssh $1
expect {
"password:"
{
send "your_password\r"
expect "*"
send "cat id_rsa.pub >> .ssh/authorized_keys\r"
expect "*"
send "exit\r"
expect eof
}
"Last login" {
send "exit\r"
expect eof
}
}
EOF
}
當然了,要注意.ssh 的權限要設置爲700, .ssh/authorized_keys的權限是600;如果權限不對,系統是不會讓你免密碼登陸的。
最後給出一個通用的執行一個命令的函數吧:
exec_shell()
{
expect <<EOF
set timeout 100
spawn ssh $1
expect {
"Last login" {
send "$2\r"
expect "*"
send "exit\r"
expect eof
}
}
EOF
}