概览
什么是 ad-hoc commands 呢 ? 下面这样就是
ansible all -a "free -h"
也就是在命令行直接执行Ansible命令,不是我装逼,这个没找到很好的翻译,官方文档和一些国外的书籍都这么称呼
在命令行直接运行Ansible命令,基本上只存在于测试环节,甚至有时候测试都不用,毕竟生产环境都是写playbook管理,否则有点什么操作大家都冲到机器上执行个Ansible远程命令,也没啥记录,时间久了其不乱成一坨,而写成playbook尤其是在配合git进行管理,则可以清楚的看到服务修改的来龙去脉
我们在查看官方文档,某个模块如何用的时候,官方文档给的示例基本也是playbook形式
为什么需要 ad-hoc commands 呢 ?
不过在一些特殊情况下,直接在命令行执行Ansible命令有一个优点,那就是快,比如新上线某个服务严重拖垮机器资源,此时根本来不及再去写什么完整的playbook,直接一行命令批量把这个服务先停掉再说
Ansible ad-hoc command适合新手学习、简单测试,能够帮助我们快速了解Ansible强大的功能,所有能够使用Ansible命令行直接实现的操作,都可以通过书写playbook实现
环境准备
和之前的环境一致
[root@192-168-31-106 ~]# cat /etc/ansible/hosts
[allservers]
192.168.31.106
192.168.31.100
192.168.31.101
192.168.31.102
[webservers]
192.168.31.100
192.168.31.101
192.168.31.102
基础
ansible group-or-host [-m MODULE_NAME] [-a MODULE_ARGS]
查看帮助 ansible -h OR man ansible
上面我们查看内存的命令,如果写完整是这样
ansible all -m shell -a "free -h"
即默认的执行模块是shell命令
参数的顺序无关紧要,上面的命令写成这样也正确
ansible -m shell -a "free -h" all
输出详细信息
-v 输出详细信息
-vvv 输出更详细信息
-vvvv 调试(debug)模式
并发执行
Ansible默认是采用并发执行的方式,管理多台机器,反复执行下面的命令观察结果的顺序
ansible all -a "hostname"
可以看到每次的输出顺序是不通的,可以通过参数控制并发的个数
ansible all -a "hostname" -f 1
ansible all -a "hostname" --forks 10 #参数的长写法,同-f功能一致
Ansible默认是5个并发执行
拿到目标机器的全部环境信息
ansible 192.168.31.100 -m setup
这个命令会输出大量目标机器的详细信息,如操作系统、IP地址、内存、磁盘等,返回的是一个JSON格式数据,输出之详细我们甚至可以用这种方法在生产环境上收集机器的信息,当然过滤这些信息最好拿python之类的程序进行JSON格式化解析
注意我们这里的IP 192.168.31.100 ,是已经写在主机清单里的,如果填写一个主机清单里没有的IP地址,则会报错:
[root@192-168-31-106 ~]# ansible 192.168.31.120 -m setup
[WARNING]: Could not match supplied host pattern, ignoring: 192.168.31.120
[WARNING]: No hosts matched, nothing to do
后面我们学习变量的时候,会讲到利用这些信息做些特定操作,如判断目标机器是CentOS6安装一个包,如果是CentOS7则安装另外一个包之类
command 与 shell
前面我们已经使用过这种方法,如查看远程机器的内存:
ansible all -m command -a "free -h" OR ansible all -a "free -h"
ansible all -m shell -a "free -h"
使用-m shell
功能更为强大,如普通执行远程命令的方式不支持管道,但普通的命令执行方式因为其功能少,相对来说安全性好
https://docs.ansible.com/ansible/2.9/modules/shell_module.html
https://docs.ansible.com/ansible/2.9/modules/command_module.html
幂等性
幂等性是指如果系统已经处于期望的状态,则对系统什么也不操作。
下面我们看下,使用Ansible的YUM模块给机器安装上Nginx,借这个例子再重点看下Ansible的幂等性
ansible webservers -m ping
ansible webservers -m yum -a "name=Nginx state=present"
命令执行第2次,就可以看到全是绿色的,说明机器状态无变化
可不可以不实用YUM模块,就使用Shell命令呢,可以,如下
ansible webservers -m shell -a "yum install Nginx -y"
我们可以看到,输出内容有蓝色警告内容,提醒我们建议使用YUM模块而不是Shell YUM命令,并且更关键的是后面3台机器的输出内容都是黄色的,表示机器状态已被修改,即便我们多次执行ansible webservers -m shell -a "yum install Nginx -y"
,输出内容依旧是黄色CHANGED的状态
可以看到要想让Ansible完美支持幂等性,需要尽可能不使用直接的Shell命令,而是多使用Ansible自带的模块,后面我们还会学习到Ansible其它模块
使用Ansible自带的模块而不是原生shell命令有2个好处:
- 方便维护,Ansible模块的语法统一,而shell脚本如果写的复杂,难以维护
- 支持幂等性(idempotency)
为什么非要强调幂等性的重要呢,比如说一个常见的场景,老板说让初始化一台新机器,安装Nginx提供七层的负载均衡服务,团队之前已经写好了对应的playbook,理想情况下是直接一条Ansible命令完成初始化,但是谁也不能保证永远不报错,一旦有什么错误,或者新增什么新的需求,就需要这套Ansible服务支持反复执行,状态始终是预期的状态,换句话说我们希望写的playbook文件是一种对状态的描述,类似于"保持Nginx出于安装并且启动的状态"而不是"安装Nginx"
理想虽好,但是实际工作中想要保证Ansible剧本里完全没有直接运行shell命令的方式,全部使用的是Ansible自带的模块,难,非常难,但是我么至少要保证别挖大坑,避免第一次执行脚本正常,而多次执行某个脚本系统处于什么状态,已经完全不可预期的情况
ansible all -m copy -a "src=/root/node_exporter-1.0.0.linux-amd64.tar.gz dest=/tmp"
ansible all -m copy -a "src=/root/node_exporter-1.0.0.linux-amd64.tar.gz dest=/tmp"
上面的命令连续执行两次,可以发现第1次输出为黄色,表明系统已经做了修改,第2次输出为绿色表明无任何修改,具有一定的幂等性
限制针对某台机器执行
假设我们之前的主机清单是这样的
[root@192-168-31-106 ~]# cat /etc/ansible/hosts
[webservers]
192.168.31.100
192.168.31.101
即已经有了2台webserver服务器,但现在的场景是,量太大,机器抗不住,需要初始化一台新的webserver机器加入集群,因此我们修改主机清单,增加一行IP,如下
[root@192-168-31-106 ~]# cat /etc/ansible/hosts
[webservers]
192.168.31.100
192.168.31.101
192.168.31.102
此时我们进行相关部署操作的时候,希望限定在对102机器执行操作,其它不动,我们可以使用--limit ${ip}
参数
ansible webservers -m yum -a "name=Nginx state=present" --limit "192.168.31.102"
管理系统users和groups
在shell命令中,我们使用useradd、usermod、userdel
来管理用户,使用groupadd、groupdel、groupmod
来管理组
在Ansible中分别使用user
和group
进行管理
管理组 group
ansible 192.168.31.100 -m group -a "name=test1 state=present" #增加test1组
ansible 192.168.31.100 -m group -a "name=test1 state=absent" #删除test1组
ansible 192.168.31.100 -m group -a "name=test1 state=present gid=2000" #指定组的gid
管理用户 user
ansible 192.168.31.100 -m user -a "name=test2 state=present" #增加用户
ansible 192.168.31.100 -m user -a "name=test2 state=absent" #删除用户
ansible 192.168.31.100 -m user -a "name=test3 password={{ '123456' | password_hash('sha512', 'mysecretsalt') }} state=present" #创建用户并指定密码
更多参数,参考官方文档
https://docs.ansible.com/ansible/2.9/modules/user_module.html
https://docs.ansible.com/ansible/2.9/modules/group_module.html
管理包
上面我们已经看到,Ansible的yum模块来管理包,Ansible还有一个通用的包管理模块,可跨平台支持不同的操作系统
ansible 192.168.31.100 -m package -a "name=git state=present"
管理文件和目录
1 查看文件的状态信息
#该功能类似 stat
ansible all -m stat -a "path=/etc/profile"
2 把本地文件或目录(在管理机器上)拷贝到远程机器上
#该功能类似 scp 、 rsync
ansible 192.168.31.100 -m copy -a "src=/etc/hosts dest=/tmp/hosts"
其中src
可以是文件,可以是目录,如果是目录的话注意末尾是否有斜线,行为不同
ansible 192.168.31.100 -m copy -a "src=/etc/sysconfig/network-scripts dest=/tmp"
ansible 192.168.31.100 -m copy -a "src=/etc/sysconfig/network-scripts/ dest=/tmp"
rsync也有类似的逻辑,在实际使用的时候多加测试即可
与cp命令不同,类似 cp /etc/* 这种带星号的逻辑,不支持
3 把远程机器的文件拉到本地
#这种场景应用的比较少,我们演示一种情况,备份所有机器的/etc/hosts到管理机器上
ansible all -m fetch -a "src=/etc/hosts dest=/tmp/xtmp"
#可以看到,还贴心的自动生成了IP文件夹以区分
4 创建目录和文件
#类似 touch mkdir
ansible 192.168.31.100 -m file -a "path=/tmp/test10 mode=644 state=directory" #创建目录
ansible 192.168.31.100 -m file -a "path=/tmp/test6.txt mode=0644 state=touch" #创建文件
ansible 192.168.31.100 -m file -a "path=/tmp/test10 state=absent"
https://docs.ansible.com/ansible/2.9/modules/file_module.html
https://docs.ansible.com/ansible/2.9/modules/copy_module.html
管理定时任务
话不多说,我们直接看个简单的效果
ansible 192.168.31.100 -m cron -a "name='cron_test' minute='*/2' job='date >> /tmp/tmp.txt' state='present'"
ansible 192.168.31.100 -m cron -a "name='cron_test' minute='*/2' job='date >> /tmp/tmp.txt' state='absent'"
参考链接
https://docs.ansible.com/ansible/2.9/modules/cron_module.html
提升权限
执行Ansible的用户默认就是当前使用的用户,如果管理机器上用root执行,到目标机器上也是root用户,可以通过参数更改使用的用户
ansible all -a "whoami" -u Nginx
如果这个普通用户,配置了sudo免密切到root,则可以加上参数-b OR --become
,这样需要提权才能执行的操作才能正常执行
ansible all -a "whoami" -u Nginx -b
可能遇到的报错
1 No hosts matched
遇到此类报错,一般都是主机清单没有配置正确,如果确认已经配置正确,还可以通过设定环境变量的方式指定主机清单文件,如
ANSIBLE_INVENTORY=/etc/ansible/hosts ansible all -a "hostname"
上面的命令直接执行,明确告诉Ansible的路径,也可以把相关环境变量写到脚本里,或者/etc/profile
2 The authenticity of host '192.168.31.100' can't be established
类似这种报错是因为,默认SSH远程有一个输入yes确认的过程,我们可以随便用一个远程命令测试下,把yes输入上,或者使用如下的环境变量
ANSIBLE_HOST_KEY_CHECKING=False ansible all -a "hostname"
总结
本篇文章,我们主要是围绕着Ansible Ad-Hoc命令,以一些重点模块为例,展开讲一些Ansible的主要功能,主要的目的是让大家对Ansible能够干啥有个直观的认识,另外还简要探讨了幂等性这个重要的概念,有了这些基本的认识,为我们紧接着学习playbook打下良好的基础