20.27 分发系统介绍

由于业务迭代更新,需要更改代码,如果机器很多,那么久需要一个分发系统,可以把每段时间更新的代码分别发布到机器上去

分发系统就是上线的shell脚本,核心为expect

expect是一种脚本语言,和shell很像,可以用它去实现传输文件和远程执行命令,不需要去输入密码


20.28 expect脚本远程登录

安装:

[root@arslinux-01 ~]# yum install -y expect

实例1:

自动远程登录

[root@arslinux-01 expect]# vim 1.expect
#! /usr/bin/expect
set host "192.168.194.132"
set passwd "12345678"
spawn ssh root@$host
expect {
"yes/no" { send "yes\r"; exp_continue}        //交互内容里有 yes/no 需要怎么办
"assword:" { send "$passwd\r" }                //交互内容里有 assword 怎么办
}
interact

expect 定义变量的方法:set 变量名

/root/.ssh/known_hosts 记录历史登录服务器的文件,这样再登录不提示

interact 表示结束,停留在远程的机器上(如果不加这一行,那么登录后马上回退出)

(如果不用interact,而是expect eof ,那么会停留在机器上几秒,然后退出)

测试:

[root@arslinux-01 expect]# chmod a+x 1.expect
[root@arslinux-01 expect]# ll 1.expect
-rwxr-xr-x 1 root root 179 6月  20 06:44 1.expect
[root@arslinux-01 expect]# ./1.expect
spawn ssh [email protected]
[email protected]'s password:
Last login: Sun Jun 16 20:50:10 2019 from 192.168.194.1
[root@arslinux-02 ~]#

成功登录2号机器


20.29 expect脚本远程执行命令

实例2:

自动远程登录后,执行命令并退出

[root@arslinux-01 expect]# vim 2.expect
#!/usr/bin/expect
set user "root"
set passwd "123456"
spawn ssh [email protected]
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"

测试:

[root@arslinux-01 expect]# chmod a+x 2.expect
[root@arslinux-01 expect]# ./2.expect
spawn ssh [email protected]
[email protected]'s password:
Last failed login: Thu Jun 20 07:15:12 CST 2019 from 192.168.194.130 on ssh:notty
There were 4 failed login attempts since the last successful login.
Last login: Thu Jun 20 07:13:41 2019 from 192.168.194.130
[root@arslinux-02 ~]# touch /tmp/12.txt
[root@arslinux-02 ~]# echo 1212 > /tmp/12.txt
[root@arslinux-02 ~]# [root@arslinux-01 expect]#

到2号机上查看

[root@arslinux-02 ~]# ll /tmp/12.txt
-rw-r--r-- 1 root root 5 6月  20 07:15 /tmp/12.txt
[root@arslinux-02 ~]# cat /tmp/12.txt
1212

成功


20.30 expect脚本传递参数

实例3:

传递参数

[root@arslinux-01 expect]# vim 3.expect
#!/usr/bin/expect
set user [lindex $argv 0]
set host [lindex $argv 1]
set passwd "123456"
set cm [lindex $argv 2]
spawn ssh $user@$host
expect {
"yes/no" { send "yes\r"}
"password:" { send "$passwd\r" }
}
expect "]*"
send "$cm\r"
expect "]*"
send "exit\r"
[root@arslinux-01 expect]# chmod a+x 3.expect

set user [lindex $argv 0],set host [lindex $argv 1],set cm [lindex $argv 2]分别表示第1,2,3个参数

设置用户名,主机,命令(cm)

执行过程和之前脚本一致,只不过在执行命令时,需要向在命令行写出3个参数传递到脚本中

如果想要传递多个命令,需要用双引号括起来,并且命令之间用分号隔开

测试:

[root@arslinux-02 expect]# ./1.expect root 192.168.194.130 "ls;w;vmstat 1"
spawn ssh [email protected]
Last login: Thu Jun 20 22:18:29 2019 from 192.168.194.132
[root@arslinux-01 ~]# ls;w;vmstat 1
111         2222.txt.bak     bb.txt  f.txt          shell
11111.txt   222.txt          b.txt   F.txt          temp
123         234              B.txt   gakki.jpg.bz2  test
123.txt     234.tar          c.txt   grep           :WQ
1_hard.txt  2.txt            C.txt   log            zabbix.sql
1.sh        anaconda-ks.cfg  d.txt   logs           zrlog-1.7.1-baaecb9-release.war
1_soft.txt  arslinux         D.txt   newfile
1.txt       A.txt            e.txt   oot
1.txz~      awk              E.txt   sed
22:19:15 up  1:37,  3 users,  load average: 0.05, 0.06, 0.05
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
root     tty1                      22:09    8:35   0.13s  0.13s -bash
root     pts/0    192.168.194.1    21:00    3:39   0.12s  0.12s -bash
root     pts/1    192.168.194.132  22:19    3.00s  0.03s  0.01s w
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  60876   2200 279364    0    0    42    60  110  244  0  1 98  0  0
0  0      0  60892   2200 279396    0    0     0     0  118  216  0  0 100  0  0
0  0      0  60892   2200 279400    0    0     4    15  128  237  0  0 100  0  0
0  0      0  60892   2200 279400    0    0     0    10  128  240  0  1 99  0  0

因为expect有默认超时时间,所有都会在10秒后会退出

如果想脚本执行不超时,可以设置 set timeout,指定一个数值,set timeout -1 永远不超时,想要执行 5 秒就写 5、执行某个命令就在命令 send "$cm\r" 下面 set time 指定秒数

出现问题:

[root@arslinux-01 expect]# ./3.expect root 192.168.194.132 "ls;w;vmstat 1"
spawn ssh [email protected]
[email protected]'s password: yum
Permission denied, please try again.

解决方法:

在 arslinux-01 上,编辑 /etc/ssh/sshd_config

找到 PermitRootLogin 取消#注释,并改为 yes

重启 sshd ,再次尝试 expect 应该没有问题了


20.31 expect脚本同步文件

实例4:

自动同步文件

[root@arslinux-01 expect]# vim 4.expect
#!/usr/bin/expect
set passwd "123456"
spawn rsync -av [email protected]:/tmp/12121212.txt /tmp/
expect {
"yes/no" { send "yes\r"}
"password:" { send "$passwd\r" }
}
expect eof
[root@arslinux-01 expect]# chmod a+x 4.expect

测试:

[root@arslinux-02 expect]# ./4.expect
spawn rsync -av [email protected]:/tmp/12121212.txt /tmp/
receiving incremental file list
12121212.txt
sent 43 bytes  received 93 bytes  12.95 bytes/sec
total size is 0  speedup is 0.00

expect eof  如果不加这条语句,那么还没有开始执行数据传输,就马上结束了,甚至有可能还没有远程登录成功,就已经退出来了,所以脚本里面必须要加这条语句。

不加 expect eof

[root@arslinux-01 expect]# ./4.expect
spawn rsync -av [email protected]:/tmp/1922168194132.txt /tmp/


20.32 expect脚本指定host和要同步的文件

实例5:

指定host和要同步的文件

[root@arslinux-01 expect]# vim 5.expect
#!/usr/bin/expect
set passwd "123456"
set host [lindex $argv 0]
set file [lindex $argv 1]
spawn rsync -av $file root@$host:$file
expect {
"yes/no" {send "yes\r"}
"password:" {send "$passwd\r"}
}
expect eof
[root@arslinux-01 expect]# chmod a+x 5.expect

测试:

[root@arslinux-01 expect]# ./5.expect 192.168.194.132 "/tmp/1234567.txt"
spawn rsync -av /tmp/7654321.txt [email protected]:/tmp/1234567.txt
sending incremental file list
1234567.txt
sent 93 bytes  received 35 bytes  12.19 bytes/sec
total size is 0  speedup is 0.00


20.33 构建文件分发系统

需求背景:

对于大公司而言,肯定时不时会有网站或者配置文件更新,而且使用的机器肯定也是好多台,少则几台,多则几十甚至上百台。所以,自动同步文件是至关重要的。

实现思路:

首先要有一台模板机器,把要分发的文件准备好,然后只要使用expect脚本批量把需要同步的文件分发到目标机器即可。

核心命令:

rsync -av --files-from=list.txt  /  root@host:/

实例6:

[root@arslinux-02 expect]# vim rsync.expect
#!/usr/bin/expect
set passwd "123456"
set host [lindex $argv 0]
set file [lindex $argv 1]
spawn rsync -avR --files-from=$file / root@$host:/
expect {
"yes/no" { send "yes\r"}
"password:" { send "$passwd\r" }
}
expect eof
[root@arslinux-02 expect]# chmod a+x rsync.expect

file 内容:

[root@arslinux-02 expect]# vim /tmp/list.txt
/tmp/12123.txt
/root/shell/ceshi.sh
/root/linux2019/README.md

列表里面文件的路径,在另一台机器上也要存在才可以,如果没有可以用 rsync -R 创建

iplist 内容:

[root@arslinux-02 expect]# vim /tmp/ip.txt
192.168.194.130
127.0.0.1

做密钥认证可以省略密码,防止密码泄露

rsync.sh 内容:

[root@arslinux-02 expect]# vim rsync.sh
#!/bin/bash
for ip in `cat /tmp/ip.txt`
do
./rsync.expect $ip /tmp/list.txt
done

测试:

[root@arslinux-02 expect]# sh -x rsync.sh
++ cat /tmp/ip.txt
+ for ip in '`cat /tmp/ip.txt`'
+ ./rsync.expect 192.168.194.130 /tmp/list.txt
spawn rsync -avR --files-from=/tmp/list.txt / [email protected]:/
building file list ... done
root/
root/linux2019/
root/linux2019/README.md
root/shell/
root/shell/ceshi.sh
tmp/
tmp/12123.txt
sent 343 bytes  received 85 bytes  37.22 bytes/sec
total size is 12  speedup is 0.03
+ for ip in '`cat /tmp/ip.txt`'
+ ./rsync.expect 127.0.0.1 /tmp/list.txt
spawn rsync -avR --files-from=/tmp/list.txt / [email protected]:/
The authenticity of host '127.0.0.1 (127.0.0.1)' can't be established.
ECDSA key fingerprint is SHA256:56XmV3ETdeyOoI3O4uQmBzBston1io6oJGzG3tzxR3I.
ECDSA key fingerprint is MD5:70:fe:fe:67:05:ab:b9:25:88:67:98:5f:b5:c3:04:36.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '127.0.0.1' (ECDSA) to the list of known hosts.
[email protected]'s password: [root@arslinux-02 expect]#

在127.0.0.1传递时出错,192.168.194.130可以,思路正确

思路:

执行 rsync.expect 脚本并且要传递两个参数

而其中之一是多个ip中的一个,把 ip 写到一个文本中,for 循环依次去读一个ip,并传递到脚本中去

在 shell 脚本中写此 for 循环,可以执行

把需要同步的文件绝对目录写入到 list.txt 中,这样可以将需要同步的目录依次同步到 ip.txt 中的机器


20.34 批量远程执行命令

实例7:

定义 exe.expect

[root@arslinux-02 expect]# vim exe.expect
#!/usr/bin/expect
set host [lindex $argv 0]
set passwd "123456"
set cm [lindex $argv 1]
spawn ssh root@$host
expect {
"yes/no" { send "yes\r"}
"password:" { send "$passwd\r" }
}
expect "]*"
send "$cm\r"
expect "]*"
send "exit\r"
[root@arslinux-02 expect]# chmod a+x exe.expect

定义exe.sh脚本

[root@arslinux-02 expect]# cd ..
[root@arslinux-02 sbin]# vim exe.sh
#!/bin/bash
for ip in `cat /tmp/ip.list`
do
./exe.expect $ip "hostname"
done

测试:

[root@arslinux-02 expect]# sh -x exe.sh
++ cat /tmp/ip.txt
+ for ip in '`cat /tmp/ip.txt`'
+ ./exe.expect 192.168.194.130 hostname
spawn ssh [email protected]
Last login: Fri Jun 21 06:50:46 2019 from 192.168.194.1
[root@arslinux-01 ~]# hostname
arslinux-01
[root@arslinux-01 ~]# + for ip in '`cat /tmp/ip.txt`'
+ ./exe.expect 127.0.0.1 hostname
spawn ssh [email protected]
[email protected]'s password:
Last failed login: Fri Jun 21 07:17:39 CST 2019 from localhost on ssh:notty
There were 2 failed login attempts since the last successful login.
Last login: Fri Jun 21 06:50:53 2019 from 192.168.194.1
[root@arslinux-02 ~]# hostname
arslinux-02

测试成功!

扩展:

shell多线程  http://blog.lishiming.net/?p=448

shell习题做一下  http://www.apelearn.com/study_v2/chapter15.html#shll