2.0 Ad-Hoc命令

概览

什么是 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则安装另外一个包之类

使用原生命令

前面我们已经使用过这种方法,如查看远程机器的内存:

ansible all -a "free -h"  OR 
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

YUM模块

下面我们看下,使用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个好处:

  1. 方便维护,Ansible模块的语法统一,而shell脚本如果写的复杂,难以维护
  2. 支持幂等性

为什么非要强调幂等性的重要呢,比如说一个常见的场景,老板说让初始化一台新机器,安装nginx提供七层的负载均衡服务,团队之前已经写好了对应的playbook,理想情况下是直接一条Ansible命令完成初始化,但是谁也不能保证永远不报错,一旦有什么错误,或者新增什么新的需求,就需要这套Ansible服务支持反复执行,状态始终是预期的状态,换句话说我们希望写的playbook文件是一种对状态的描述,类似于”保持nginx出于安装并且启动的状态”而不是”安装nginx”

理想虽好,但是实际工作中想要保证Ansible剧本里完全没有直接运行shell命令的方式,全部使用的是Ansible自带的模块,难,非常难,但是我么至少要保证别挖大坑,避免第一次执行脚本正常,而多次执行某个脚本系统处于什么状态,已经完全不可预期的情况

限制针对某台机器执行

假设我们之前的主机清单是这样的

[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中分别使用usergroup进行管理

管理组 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"   #创建文件

5 删除目录和文件

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

SSH免密码配置是针对用户的,如果我们用其它的用户去执行Ansible命令,那么这个用户也需要配置免密

如果这个普通用户,配置了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打下良好的基础