一、基础概念
ansible是什么?
ansible是通过调用ssh协议进行批量配置和管理的软件。
为什么用ansible?
如果我们只有两台主机,根本没必要用ansible,但是假如我们有50多台主机,要统一进行修改配置,一台台的改工作量太大了,我们这时就可以用ansible工具,统一对50台主机同时进行连接并修改配置,仅需要一次的操作,减少重复性的操作,大大提高了运维人员的效率。
ansible可以做些什么?
- 批量命令执行
- 批量同步配置文件
- 批量代码部署
ansible的特点和优势
-
只需要在控制端安装ansible软件,受控端保证ssh正常运行即可,并不用启动服务。
-
修改配置之后不用重读,立马生效。
-
模块相当于ansible的命令,而playbook相当于脚本。
ansible的架构组成
-
host inventory:主机清单
-
playbook:任务剧本
-
core modules:核心模块
-
commection plugin:连接插件
ansible的执行流程
- ansible读取playbook中的剧本,剧本中会记录将要对哪些主机执行哪些任务。
- ansible通过主机清单找到要执行的主机,然后调用具体的模块(相当于不同功能的命令)
- 然后,通过连接插件连接对应的主机下发任务列表。
- 最后受控端主机将下发来的任务解析成本地shell命令执行。
怎么用ansible?
至于怎么用ansible,那正是这一节的主要内容所在。
与ansible同类型的工具,比较出名的就属salstack
二、基本操作
安装
安装之前准备epel源:
yum -y install ansible
ansible --version
ansible 2.9.1
推送公钥
ansible默认是使用公钥进行连接受控端的,在使用ansible之前要先将ansible的公钥推送到三台受控端。
如果受控端数量较少,可以手动推送公钥,如果受控端数量较多,就使用脚本推送公钥。当前受控端有三台主机
- 192.168.80.62
- 192.168.80.63
- 192.168.80.64
手动推送公钥的步骤:
-
主控端ansible通过
ssh-keygen
生成一对密钥,会自动存放在家目录的.ssh/authorized_keys文件下 -
然后通过ssh-copy-id把公钥上传到被控端,会自动保存在目的用户家目录下的.ssh/
//生成公钥,一路回车
[root@ansible ~]# ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa):
Created directory '/root/.ssh'.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /root/.ssh/id_rsa.
Your public key has been saved in /root/.ssh/id_rsa.pub.
The key fingerprint is:
SHA256:GS0Cof8VpoMGy9QfS9ICN1ZFrpwWHo5ED9zrPYBSZlo root@ansible
The key's randomart image is:
+---[RSA 2048]----+
| ..O+.oo |
| BE*.. . |
| +*=.O.* . |
| oo=.@o@ = |
| o.=.%oS |
| . o.oo |
| . . |
| |
| |
+----[SHA256]-----+
//发现有两个密钥
[root@ansible .ssh]# ls
id_rsa id_rsa.pub
//这样就可以推送了,交互式输入yes和被控端的密码
[root@ansible ~]# ssh-copy-id 192.168.80.62
脚本推送公钥的步骤:
//找个文件把受控端IP和密码写好,中间用空格隔开
[root@ansible ~]# cat host
192.168.80.62 cba-123
192.168.80.63 cba-123
192.168.80.64 cba-123
[root@ansible ~]# vim push_pub_key.sh
#!/bin/bash
#先定义一个函数expect
expect () {
/usr/bin/expect <<-EOF
spawn ssh-copy-id root@$ADDR
expect {
"yes/no" { send "yes\r"; exp_continue }
"password:" { send $PASSWD\r }
}
expect eof
EOF
} #函数在此结束
SERVERHOST=./host
for ADDR in `cut -d" " -f1 $SERVERHOST`;do #这一cut把所有的ip全都列出来了
PASSWD=$(grep $ADDR $SERVERHOST | cut -d" " -f2)
test -f ~/.ssh/id_rsa
if [ $? -ne 0 ];then
ssh-keygen -P "" -f ~/.ssh/id_rsa &>/dev/null
expect
echo "key already send!"
else
expect
echo "key already send!!"
fi
done
由于此章节是讲
ansible
,所以对shell
脚本不做过多的解释,如果想看具体的解释,请点击我的博客链接,传送门
定义主机清单
所谓的定义主机清单就是告诉ansible程序,要连接哪些主机的IP,也可以使用主机名,支持组;
[root@ansible ~]# vim /etc/ansible/hosts
[test]
192.168.80.62
192.168.80.63
192.168.80.64
//列出test组的主机
[root@ansible ~]# ansible test --list-host
hosts (3):
192.168.80.62
192.168.80.63
192.168.80.64
//列出所有主机
[root@ansible ~]# ansible all --list-host
hosts (3):
192.168.80.62
192.168.80.63
192.168.80.64
推送完公钥、定义完主机清单,测试一下是否可以使用了,用ping模块,这个模块不是网络当中的ping,而仅是测试ansible与受控端的连通性而已。
//ansible后面直接跟组名,-m是指定模块,这里我们使用ping模块,测试成功,全是绿色的。
[root@ansible ~]# ansible test -m ping
192.168.80.62 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
192.168.80.63 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
192.168.80.64 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
- 绿色代表被管理主机没有被修改
- 黄色代表被管理主机发现变更
- 红色代表出现故障,注意查看提示原因
ad-hoc(远程执行命令)
什么是ad-hoc?
其实就是远程对主机清单里面的主机执行命令,这些命令是临时执行,执行完就结束了,并不会保存。
ad-hoc的使用场景
比如在多台机器上查看某个进程是否启动
ad-hoc的格式
ansible <组名> -m <模块名称> -a <具体命令>
模块可以不写,默认是command,如ansible test -m command -a 'hostname'
可以简写成如下格式:
//ansible后面直接写组名,-a 后面加上单引号,把命令引起来就可以了
[root@ansible ~]# ansible test -a 'hostname'
192.168.80.64 | CHANGED | rc=0 >>
backup
192.168.80.63 | CHANGED | rc=0 >>
nfs
192.168.80.62 | CHANGED | rc=0 >>
nginx
ad-hoc缺点就是不太支持管道和&符号,一用就报错,如果想让其支持管道的话,就用shell模块,如下
//在command模块中使用管道会报错,红色
[root@ansible ~]# ansible test -a 'df -h | head -2'
192.168.80.64 | FAILED | rc=1 >>
df: invalid option -- '2'
Try 'df --help' for more information.non-zero return code
192.168.80.62 | FAILED | rc=1 >>
df: invalid option -- '2'
Try 'df --help' for more information.non-zero return code
192.168.80.63 | FAILED | rc=1 >>
df: invalid option -- '2'
Try 'df --help' for more information.non-zero return code
//使用shell模块就好了
[root@ansible ~]# ansible test -m shell -a 'df -h | head -2'
192.168.80.62 | CHANGED | rc=0 >>
Filesystem Size Used Avail Use% Mounted on
/dev/mapper/centos-root 45G 1.7G 44G 4% /
192.168.80.63 | CHANGED | rc=0 >>
Filesystem Size Used Avail Use% Mounted on
/dev/mapper/centos-root 45G 1.7G 44G 4% /
192.168.80.64 | CHANGED | rc=0 >>
Filesystem Size Used Avail Use% Mounted on
/dev/mapper/centos-root 45G 1.7G 44G 4% /
shell模块是万能的,啥都能执行,那我们干脆只学shell模块不就行了,干吗还要学习其他的模块呢?是因为shell模块不管对方是什么状态,都要将命令在对方执行一次,而其他模块会判断,判断对方当前的状态是什么,如果的对方的状态就是我们希望的,那就不执行,如果不是,就执行,这样多好,我们下面来举一个例子:
[root@ansible ~]# ansible test -m shell -a 'yum -y install vim'
上述命令,无论你执行多少次都会显示黄色,而黄色代表对方被更改,其实只有第一次被更改,后面都是重复的,按理说除了第一次都应该显示绿色,但是通过shell模块不会判断对方的状态,我们如果使用专门的安装模块结果就变成我们想要的,如果受控端已经安装了vim,就不会再执行安装了,不被更改就显示绿色,如下所示:
[root@web1 ~]# ansible-doc yum #找到帮助示例学习一下yum模块的使用
EXAMPLES:
- name: install the latest version of Apache #将这个安装apache的写法转换成临时命令的写法
yum:
name: httpd #模块是httpd
state: latest #方法是latest(更新),absent(移除),present(安装)
[root@ansible ~]# ansible test -m yum -a 'name=vim state=present'