一、分發系統介紹:expect,也就是一個分發腳本:php
場景:業務會愈來愈大,網站app,後端,服務端所使用的編程語言爲php,要想運行這個環境,就須要配置LAMP或者LNMP,最後還須要把代碼上傳到服務器上去,業務不斷的增長,一兩臺機器還好好說,要是幾十臺,上百臺設備,這時候就須要用到了分發系統了,把天天更新的代碼發佈到每一臺機器上去:shell
expect是一種腳本語言,經過它能夠實現傳輸,上線代碼,能夠實現遠程執行命令,不須要輸入密碼:編程
首先準備一臺模板機器(最新的代碼待上線),而後給下面分發代碼的多臺臺機器上線,機器的IP,對應用戶的密碼,然經過expect,藉助rsync來上傳代碼,能夠用expect去登陸執行某些命令:vim
1:expect腳本安裝:後端
yum install -y expect (安裝包和mkpasswd是一塊兒的)安全
示例1:自動遠程登陸,並執行一些命令:bash
[root@localhost_01 sbin]# vim 1.expect #! /usr/bin/expect set host "192.168.149.129" set passwd "nihao123!" set port "-p 56888" spawn ssh $port root@$host expect { "yes/no" { send "yes\r"; exp_continue} "password:" { send "$passwd\r" } } ##expect eof 表示登陸遠程機器後,暫停一兩秒鐘後退出: interact #腳本結束
註釋:在expect中定義變量須要set host才能夠:服務器
註釋:在文件裏 expect { }這裏是保證登陸信息,第一次登陸時候,則須要yes記錄登陸信息,下一次則不須要了,須要清空 >/root/.ssh/known_hosts才能夠:app
exp_continue表示繼續/r換行, interact表示繼續停留在這臺機器不退出:若是不加的話則登陸後立刻退出:ssh
[root@localhost_01 sbin]# ssh -p 56888 192.168.149.129 root@192.168.149.129's password: #由於咱們之前登陸過,全部不詢問爲了安全性,是否須要還繼續連接: [root@localhost_01 sbin]# > /root/.ssh/ authorized_keys authorized_keys_xshell id_rsa.pub authorized_keys.bakup id_rsa known_hosts [root@localhost_01 sbin]# > /root/.ssh/known_hosts #清空這個文件裏面的信息: [root@localhost_01 sbin]# ssh -p 56888 192.168.149.129 #再次登陸時則會詢問: The authenticity of host '[192.168.149.129]:56888 ([192.168.149.129]:56888)' can't be established. ECDSA key fingerprint is SHA256:mtOEV1y+2ErXFWqQRL0rYCQGGuVE7z4n1is+2dPQc7E. ECDSA key fingerprint is MD5:d9:f7:03:de:c4:f5:40:89:be:3c:25:6d:70:6a:49:a5. Are you sure you want to continue connecting (yes/no)? yes
加入執行權限後成功登陸: chmod a+x 1.expect
[root@localhost_01 sbin]# ./1.expect -bash: ./1.expect: 權限不夠 [root@localhost_01 sbin]# chmod a+x 1.expect [root@localhost_01 sbin]# ./1.expect spawn ssh -p 56888 root@192.168.149.129 The authenticity of host '[192.168.149.129]:56888 ([192.168.149.129]:56888)' can't be established. ECDSA key fingerprint is SHA256:mtOEV1y+2ErXFWqQRL0rYCQGGuVE7z4n1is+2dPQc7E. ECDSA key fingerprint is MD5:d9:f7:03:de:c4:f5:40:89:be:3c:25:6d:70:6a:49:a5. Are you sure you want to continue connecting (yes/no)? yes Warning: Permanently added '[192.168.149.129]:56888' (ECDSA) to the list of known hosts. root@192.168.149.129's password: Last login: Thu Oct 4 00:33:35 2018 from 192.168.149.135 [root@localhost_02 ~]#
2:expect遠程執行命令:
遠程執行完命令,並退出:
[root@localhost_01 sbin]# vim 2.expect #!/usr/bin/expect set user "root" set passwd "nihao123!" set port "-p 56888" spawn ssh $port $user@192.168.180.135 expect { "yes/no" { send "yes\r"; exp_continue} "password:" { send "$passwd\r" } } expect "]*" send "touch /tmp/12.txt\r" expect "]*" send "echo 1212 > /tmp/12.txt\r" expect "]*" send "exit\r"
註釋:expect "]*" 星號表示通配,匹配右邊的全部字符(不論是root用戶普通用戶):
註釋:send 表示執行這個命令:
3:須要加執行權限並執行這個命令:
[root@localhost_01 sbin]# chmod a+x 2.expect [root@localhost_01 sbin]# ll 2.expect -rwxr-xr-x 1 root root 307 10月 4 16:09 2.expect [root@localhost_01 sbin]# ./2.expect spawn ssh -p 56888 root@192.168.149.129 root@192.168.149.129's password: Last login: Thu Oct 4 06:00:22 2018 from 192.168.149.130 [root@localhost_02 ~]# touch /tmp/12.txt [root@localhost_02 ~]# echo 1212 > /tmp/12.txt
而後在129這臺機器上查看是否建立成功:
[root@localhost_02 ~]# ls /tmp/12.txt /tmp/12.txt [root@localhost_02 ~]# cat /tmp/12.txt 1212
四、expect腳本傳遞參數:
[root@localhost_01 sbin]# vim 3.expect [root@localhost_01 sbin]# cat 3.expect #!/usr/bin/expect set port [lindex $argv 0] #第一個參數,若是端口仍是默認的22,則不須要定義次參數,依次往下定義便可: set user [lindex $argv 1] #第二個參數 set host [lindex $argv 2] #第三個參數 set passwd "nihao123!" set cm [lindex $argv 3] #第四參數 spawn ssh -p $port $user@$host expect { "yes/no" { send "yes\r"} "password:" { send "$passwd\r" } } expect "]*" send "$cm\r" expect "]*" send "exit\r"
1:增長執行權限: chmod +x 3.expect
[root@localhost_01 sbin]# chmod a+x 3.expect [root@localhost_01 sbin]# ll 3.expect -rwxr-xr-x 1 root root 369 10月 4 16:37 3.expect
2:執行此腳本:
./3.expect 第一個參數(port) 第二個參數(user) 第三個參數(host) 第四個參數(command)
[root@localhost_01 sbin]# ./3.expect 56888 root 192.168.149.129 ls spawn ssh -p 56888 root@192.168.149.129 root@192.168.149.129's password: Last login: Thu Oct 4 06:24:37 2018 from 192.168.149.130 [root@localhost_02 ~]# ls 1 anaconda-ks.cfg bash CentOS7-Base-163.repo link shell test test.txt
一樣,也支持多條參數: 多條命令最後用雙引號括住,而後用分號分割則能夠:
[root@localhost_01 sbin]# ./3.expect 56888 root 192.168.149.129 "ls;w" spawn ssh -p 56888 root@192.168.149.129 root@192.168.149.129's password: Last login: Thu Oct 4 06:32:46 2018 from 192.168.149.130 [root@localhost_02 ~]# ls;w 1 anaconda-ks.cfg bash CentOS7-Base-163.repo link shell test test.txt 06:32:57 up 19:42, 2 users, load average: 0.42, 0.23, 0.16 USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT root pts/0 192.168.149.130 06:32 1.00s 0.02s 0.01s w root pts/1 192.168.149.135 00:33 26:57 0.03s 0.03s -bash
註釋:若是是執行多條命令的話,也能夠傳遞多個參數,若是要是把多個命令當成一個參數來傳遞的話,則須要用雙引號引發來,而且用分號分割才能夠:
一樣:當咱們傳遞第四個參數時: vmstat模式超時時間是10秒:
[root@localhost_01 sbin]# ./3.expect 56888 root 192.168.149.129 "w;vmstat 1" spawn ssh -p 56888 root@192.168.149.129 root@192.168.149.129's password: Last failed login: Thu Oct 4 06:56:10 CST 2018 from 192.168.149.130 on ssh:notty There were 2 failed login attempts since the last successful login. Last login: Thu Oct 4 06:37:26 2018 from 192.168.149.130 [root@localhost_02 ~]# w;vmstat 1 07:07:33 up 20:17, 2 users, load average: 0.01, 0.19, 0.20 USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT root pts/0 192.168.149.130 07:07 0.00s 0.03s 0.03s w root pts/1 192.168.149.135 00:33 1:01m 0.03s 0.03s -bash procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu----- r b swpd free buff cache si so bi bo in cs us sy id wa st 3 0 0 1026092 2076 240768 0 0 3 42 61 101 0 0 99 1 0 0 0 0 1026108 2076 240820 0 0 0 0 37 78 0 1 99 0 0 0 0 0 1026108 2076 240820 0 0 0 0 42 84 0 0 100 0 0 0 0 0 1026108 2076 240820 0 0 0 0 42 82 0 0 100 0 0 0 0 0 1026108 2076 240820 0 0 0 10 54 90 0 0 100 0 0 0 0 0 1026108 2076 240820 0 0 0 0 37 78 0 0 100 0 0 0 0 0 1026108 2076 240820 0 0 0 103 43 104 0 1 99 0 0 0 0 0 1026108 2076 240820 0 0 0 0 45 86 0 0 100 0 0 0 0 0 1026108 2076 240820 0 0 0 0 37 74 0 0 100 0 0 0 0 0 1026108 2076 240820 0 0 0 0 34 72 0 0 100 0 0 0 0 0 1026108 2076 240820 0 0 0 0 33 70 0 0 100 0 0 0 0 0 1026108 2076 240820 0 0 0 0 35 80 0 0 100 0 0 十秒後自動超時:
註釋:也能夠設置永不超時: 須要在執行命令(也就是第四個參數)後面添加 set timeout -1
expect "]*" send "$cm\r" #set timeout -1 #表示永不超時: #set timeout 5 #也能夠手動指定具體的秒數: 本次5ms: expect "]*" send "exit\r"
一、expect同步文件: 自動同步文件; 一臺機器向一臺機器同步文件:
1:在一臺機器上,把文件同步到其餘機器上;並添加執行權限:
[root@localhost_01 sbin]# vim 4.expect [root@localhost_01 sbin]# cat 4.expect #!/usr/bin/expect set passwd "nihao123!" spawn rsync -av -e "ssh -p 56888" root@192.168.149.129:/tmp/12.txt /tmp/ expect { "yes/no" { send "yes\r"} "password:" { send $passwd\r} } expect eof [root@localhost_01 sbin]# chmod a+x 4.expect
2:執行這個腳本: ./4.expect 並查看同步後的文件內容:
[root@localhost_01 sbin]# ./4.expect spawn rsync -av -e ssh -p 56888 root@192.168.149.129:/tmp/12.txt /tmp/ root@192.168.149.129's password: receiving incremental file list 12.txt sent 43 bytes received 96 bytes 278.00 bytes/sec total size is 5 speedup is 0.04 [root@localhost_01 sbin]# ls /tmp/12.txt /tmp/12.txt [root@localhost_01 sbin]# ll /tmp/12.txt -rw-r--r-- 1 root root 5 Oct 4 06:04 /tmp/12.txt
註釋:expect eof表示只有spawn執行命令的結果纔會被expect捕捉到,由於spawn會啓動一個進程,只有這個進程相關信息纔會被捕捉到,注意包括標準輸入的提示信息,eof 和timeout:
以下測試,註釋掉expect eof,則還沒來得及傳輸了,就退出來了(僅僅到輸入密碼的那裏)
[root@localhost_01 sbin]# vim 4.expect #!/usr/bin/expect set passwd "nihao123!" spawn rsync -av -e "ssh -p 56888" root@192.168.149.129:/tmp/12.txt /tmp/ expect { "yes/no" { send "yes\r"} "password:" { send $passwd\r} } #expect eof #註釋掉: [root@localhost_01 sbin]# rm -fr /tmp/12.txt [root@localhost_01 sbin]# ./4.expect spawn rsync -av -e ssh -p 56888 root@192.168.149.129:/tmp/12.txt /tmp/ root@192.168.149.129's password: [root@localhost_01 sbin]#
二、expect指定host和要同步的文件:
[root@localhost_01 sbin]# vim 5.expect [root@localhost_01 sbin]# cat 5.expect #!/usr/bin/expect set passwd "nihao123!" set host [lindex $argv 0] set file [lindex $argv 1] spawn rsync -av -e "ssh -p 56888" $file root@$host:$file expect { "yes/no" { send "yes\r"} "password:" { send "$passwd\r"} } expect eof [root@localhost_01 sbin]# chmod a+x 5.expect
註釋:用變量定義的文件所在目錄要寫絕對路徑纔可:
如:同步本機目錄/tmp/12.txt到遠端主機192.168.149.129的/tmp/目錄下:
[root@localhost_01 sbin]# ./5.expect 192.168.149.129 "/tmp/12.txt" spawn rsync -av -e ssh -p 56888 /tmp/12.txt root@192.168.149.129:/tmp/12.txt root@192.168.149.129's password: sending incremental file list 12.txt sent 100 bytes received 35 bytes 90.00 bytes/sec total size is 9 speedup is 0.07
註釋:由於同步rsync須要藉助ssh的端口,若是是默認的22端口或者自定義的,那若是有多臺機器的ssh的端口各不相同,那是否能夠把port當成一個參數來傳遞:以下:
[root@localhost_01 sbin]# vim 5.expect #!/usr/bin/expect set passwd "nihao123!" set port [lindex $argv 0] set host [lindex $argv 1] set file [lindex $argv 2] spawn rsync -av -e "ssh -p $port" $file root@$host:$file expect { "yes/no" { send "yes\r"} "password:" { send "$passwd\r"} } expect eof [root@localhost_01 sbin]# ./5.expect 56888 192.168.149.129 "/tmp/12.txt" spawn rsync -av -e ssh -p 56888 /tmp/12.txt root@192.168.149.129:/tmp/12.txt root@192.168.149.129's password: sending incremental file list sent 44 bytes received 12 bytes 37.33 bytes/sec total size is 9 speedup is 0.16
二、構建文件分發系統;
一臺機器向多臺機器同步文件:
需求背景:對於大公司而言,確定會時不時有網站或者配置文件更新,並且使用的機器也是好多臺,少則幾臺,多則上百臺,因此自動同步文件是很重要的:
實現思路:首先須要有一臺模板機器,提早把要分發的文件準備好,而後只要使用expect腳本批量把須要同步的文件分發到目標機器便可:
核心命令:rsync -av --filep-from=list.txt / root@host:/
註釋:使用rsync 的 --files參數,能夠實現調用文件裏面的列表(列表裏的路徑須要絕對路徑),進行多個文件遠程傳輸,進而實現文件分發:
1:建立rsync.expect的腳本內容:
[root@localhost_01 sbin]# vim rsync.expect [root@localhost_01 sbin]# cat rsync.expect #!/usr/bin/expect set passwd "nihao123!" set host [lindex $argv 0] set file [lindex $argv 1] spawn rsync -avR -e "ssh -p 56888" --files-from=$file / root@$host:/ #這個地方定義了原目錄和目標目錄以跟目錄開始 expect { "yes/no" { send "yes\r"} "password:" { send "$passwd\r" } } expect eof [root@localhost_01 sbin]# chmod a+x rsync.expect
註釋:文件路徑放在/tmp/flie.list:同步的路徑,咱們要把要同步的文件路徑放在/tmp/list.txt裏面,這個時候須要保證對方機器上也要有個這個路徑(文件有沒有無所謂),若是沒有路徑,則須要使用rsync -avR建立路徑:
註釋:IP列表 /tmp/ip.list:實現分發系統,遠程同步的機器數量大,還須要定義一個IP列表 /tmp/ip.txt;
建立同步文件的列表和建立分發系統的IP地址列表:
註釋:同步前提是分發系統的密碼須要都同樣才能夠,可是這也容易形成系統不安全(expect腳本泄露),不過能夠也使用祕鑰驗證(rsync驗證),省略掉密碼的哪一步;
2:建立同步文件列表(寫絕對路徑):/tmp/file.list
[root@localhost_01 sbin]# vim /tmp/flie.list /tmp/12.txt /root/shell/test.sh /root/111/222/111.txt
3:建立IP地址列表: /tmp/ip.list
[root@localhost_01 sbin]# vim /tmp/ip.list 192.168.149.129 192.168.149.131
4:建立rsync.sh腳本: 並給予執行權限:
[root@localhost_01 sbin]# vim rsync.sh #!/bin/bash for ip in `cat /tmp/ip.list` do echo $ip ./rsync.expect $ip /tmp/file.list done [root@localhost_01 sbin]# chmod a+x rsync.sh
5:執行rsync.sh腳本: ./rsync.sh
[root@localhost_01 sbin]# sh rsync.sh 192.168.149.129 spawn rsync -avR -e ssh -p 56888 --files-from=/tmp/file.list / root@192.168.149.129:/ root@192.168.149.129's password: building file list ... done root/ root/111/ root/111/222/ root/111/222/111.txt root/shell/ root/shell/test.sh tmp/ sent 415 bytes received 69 bytes 322.67 bytes/sec total size is 118 speedup is 0.24 192.168.149.131 spawn rsync -avR -e ssh -p 56888 --files-from=/tmp/file.list / root@192.168.149.131:/ root@192.168.149.131's password: building file list ... done root/ root/111/ root/111/222/ root/111/222/111.txt root/shell/ root/shell/test.sh tmp/ tmp/12.txt sent 467 bytes received 88 bytes 1,110.00 bytes/sec total size is 118 speedup is 0.21
註釋:這個shell腳本的目的,就是遍歷一下IP列表中的IP地址;
註釋:重要的是expect腳本要加上執行權限,而且兩端都要安裝rsync服務:
註釋:分發系統還有一個重要的關鍵是,確保同步的機器的密碼以及端口號(由於rsync要以來sshd的端口)一致,不然將不能實現同步;因此這就存在一個弊端,一旦腳本暴露,將會讓別人知道如何登錄你機器;固然也有對應的解決辦法,那就是使用密鑰認證,這樣的話,天然在命令行業省去「輸入密碼< password:" { send "$passwd\r" } >''」和「定義密碼< set passwd "123123a" >」的命令了;
二、批量遠程執行命令; 有時候遠端機器操做完後,須要遠程重啓,或者重啓服務等,則使用這個方法;
1: 建立exe.expcet腳本: 並給執行權限;
[root@localhost_01 sbin]# vim exe.expect #!/usr/bin/expect set port [lindex $argv 0] set host [lindex $argv 1] set cm [lindex $argv 2] set passwd "nihao123!" spawn ssh $port root@$host expect { "yes/no" { send "yes\r"} "password:" { send "$passwd\r" } } expect "]*" send "$cm\r" expect "]*" send "exit\r" [root@localhost_01 sbin]# chmod a+x exe.expect
2:建立exe.sh執行腳本:
#!/bin/bash for ip in `cat ip.list` do echo $ip ./exe.expect $port -p56888 $ip "hostname" done
3:執行腳本: sh exe.sh
[root@localhost_01 sbin]# sh exe.sh 192.168.149.129 spawn ssh -p56888 root@192.168.149.129 root@192.168.149.129's password: Last login: Thu Oct 4 07:12:29 2018 from 192.168.149.130 [root@localhost_02 ~]# hostname localhost_02 [root@localhost_02 ~]# 192.168.149.131 spawn ssh -p56888 root@192.168.149.131 root@192.168.149.131's password: Last login: Thu Oct 4 20:19:06 2018 from 192.168.149.135 [root@localhost_03 ~]# hostname localhost_03