ansible的介绍和使用1(基本概念,主机清单和常用模块的介绍使用)
此系列文章借鉴于技术大拿博客,博客地址:http://www.zsythink.net/archives/category/%e8%bf%90%e7%bb%b4%e7%9b%b8%e5%85%b3/ansible/page/5/
1.ansible的基本概念
1.ansible是什么?
它是一个"配置管理工具",它是一个"自动化运维工具",如果你没有使用过任何配置管理工具,不要害怕,看完这篇文章,你自然会对ansible有所了解。
2.ansible能做什么?
正如其他配置管理工具一样,ansible可以帮助我们完成一些批量任务,或者完成一些需要经常重复的工作。
比如:同时在100台服务器上安装nginx服务,并在安装后启动它们。
比如:将某个文件一次性拷贝到100台服务器上。
比如:每当有新服务器加入工作环境时,你都要为新服务器部署redis服务,也就是说你需要经常重复的完成相同的工作。
这些场景中我们都可以使用到ansible。
3.ansible的相关特性介绍
看到这里,你可能会说,我编写一些脚本,也能够满足上面的工作场景,为什么还要使用ansible呢?没错,使用脚本也可以完成这些工作,不过我还是推荐你使用ansible,因为ansible支持一些优秀的特性,比如"幂等性","幂等性"是什么意思呢?举个例子,你想把一个文件拷贝到目标主机的某个目录上,但是你不确定此目录中是否已经存在此文件,当你使用ansible完成这项任务时,就非常简单了,因为如果目标主机的对应目录中已经存在此文件,那么ansible则不会进行任何操作,如果目标主机的对应目录中并不存在此文件,ansible就会将文件拷贝到对应目录中,说白了,ansible是"以结果为导向的",我们指定了一个"目标状态",ansible会自动判断,"当前状态"是否与"目标状态"一致,如果一致,则不进行任何操作,如果不一致,那么就将"当前状态"变成"目标状态",这就是"幂等性","幂等性"可以保证我们重复的执行同一项操作时,得到的结果是一样的,这种特性在很多场景中相对于脚本来说都有一定优势,单单这样说,可能并不容易理解,当你在后面真正使用到时,自然会有自己的体会,所以此处不用纠结,继续向下看。
如果你了解过其他的配置管理工具,比如puppet或者saltstack,那么你一定知道,如果我们想要使用puppet管理100台主机,就要在这100台主机上安装puppet对应的agent(客户端代理程序),而ansible则不同,ansible只需要依赖ssh即可正常工作,不用在受管主机上安装agent,也就是说,只要你能通过ssh连接到对应主机,你就可以通过ansible管理对应的主机。
ansible是一个配置管理工具,可以帮助我们完成一些批量工作或者重复性工作,ansible通过ssh管理其他受管主机,并且具有一些特性,比如幂等性、剧本、模板,角色等,我们会慢慢的介绍这些特性以及怎样使用ansible。
2.ansible的安装和清单配置详解
1.ansible的安装和实验环境介绍
介绍ansible的使用之前,我们首先要做的就是安装ansible.
但是安装之前,我们先介绍一下我的演示环境。
172.31.46.38
172.31.46.78
172.31.46.22
172.31.46.115
我将主机172.31.46.38(后文简称38)作为配置管理主机,所以我们需要在38上安装ansible,剩下的主机作为受管主机。
我使用yum源的方式安装ansible,因为安装ansible需要epel源,所以我配置了阿里的epel源和centos7系统镜像源,配置和安装过程如下
[root@linux-test-no ~]# wget -O /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-7.repo [root@linux-test-no ~]# wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo [root@linux-test-no ~]# yum install ansible -y
2.ansible清单的简单介绍
安装完毕,不过别急,我们还需要做一些其他的基本配置,如果想要通过ansible管理某主机,还需要将对应主机的信息添加到ansible的"配置清单"中,清单中没有的主机无法通过ansible进行配置管理,现在,我们就来介绍一下ansible的"清单",当安装完ansible以后,ansible会提供一个默认的"清单",这个清单就是/etc/ansible/hosts,打开此文件,你会看到一些配置示例,没错,还是熟悉的配方,还是熟悉的味道,此文件使用的就是INI的配置风格,那么,我们一起来看看怎样进行配置吧。
以我们的演示环境为例,我们想要通过ansible主机管理22主机,所以,最直接的方式就是将它的IP地址和ssh信息写入到/etc/ansible/hosts文件中,配置如下,在/etc/ansible/hosts文件底部写入如下信息
172.31.46.22 ansible_port=22 ansible_user=root ansible_ssh_pass=test@123
修改清单文件,在之前的主机IP后加入ssh的相关配置信息,如上图所示
ansible_port 用于配置对应主机上的sshd服务端口号,在实际的生产环境中,各个主机的端口号通常不会使用默认的22号端口,所以用此参数指定对应端口。
ansible_user 用于配置连接到对应主机时所使用的用户名称。
ansible_ssh_pass 用于配置对应用户的连接密码。
所以,上图中的配置表示,172.31.46.22这台主机的sshd服务监听在22号端口,当ansible通过ssh连接到主机22时,会使用主机60的root用户进行连接,主机60的root用户的密码为test@123
好了,主机22的ssh信息已经配置完毕,我们来尝试一下执行如下命令
[root@linux-test-no ~]# ansible 172.31.46.22 -m ping
上述命令表示,使用ansible去ping 172.31.46.22这台主机,很容易理解吧。
"ping"是ansible中的一个模块,这个模块的作用就是ping对应的主机,ansible调用ping模块,就相当于我们手动执行ping命令一样,上述命令中的"-m ping"表示调用ping模块,当然,ansible肯定不止这一个模块,它有很多模块,不同的模块可以帮助我们完成不同的工作,你应该已经猜到了,我们在实际使用时,会使用到各种模块,ansible是基于这些模块完成实际任务的。
上述命令返回如下结果
从上图我们看到通过ansible控制端去ping控制端失败了,产生上述结果的原因是因为控制端和被控制端第一次通讯,需要先添加指纹信息。解决方法如下
然后我们在执行一下上面的命令
可以看到,上述命令已经正常执行了,ansible主机成功的ping通了172.31.46.22,从此以后,我们就可以通过ansible主机,管理172.31.46.22这台主机了。
其实,为了更加方便的使用,ansible还支持对主机添加别名,当主机存在别名时,我们可以通过主机的"别名"管理对应主机。
比如,我们想要将172.31.46.22这台主机的别名命名为test3,那么,我们在配置清单时,可以进行如下配置
test3 ansible_host=172.31.46.22 ansible_port=22 ansible_user=root ansible_ssh_pass=test@123
如上图所示,当为主机配置别名时,主机的IP地址必须使用anible_host关键字进行指明,否则ansible将无法正确的识别对应的主机。
主机的别名配置完成后,则可以使用主机的别名管理对应主机,示例如下。
注意:上述配置参数都是ansible2.0版本以后的写法,2.0版本之前,应遵从如下写法
ansible_port应该写成ansible_ssh_port
ansible_user应该写成ansible_ssh_user
ansible_host应该写成ansible_ssh_host
上述参数,其实都是为了创建ssh连接所使用的,而说到ssh,我们都知道,创建ssh连接时,可以基于密码进行认证,也可以基于密钥进行认证,而在生产环境中,为了提高安全性,我们通常会基于密钥进行ssh认证,甚至会禁用密码认证,那么,当ansible主机需要与受管主机建立ssh连接时,能够基于密钥进行认证码?必须能的。
其实,在实际的使用环境中,我们通常会在"配置管理机(ansible主机)"中生成密钥,然后通过公钥认证的方式连接到对应的受管主机中,
那么,我们就在ansible主机中生成密钥,并进行相应的配置吧。
首先,生成默认格式的密钥对,私钥与公钥。
[root@linux-test-no ~]# ssh-keygen
然后将生成的公钥加入到172.31.46.22的认证列表
[root@linux-test-no ~]# ssh-copy-id -i /root/.ssh/id_rsa.pub root@172.31.46.22
好了,公钥认证的相关操作配置完成,此刻,我们已经可以通过ansible主机免密码连接到主机22中了。
因为配置了密钥认证,所以可以实现免密码创建ssh连接,既然已经能够免密码创建ssh连接,那么在配置"主机清单"时,就没有必要再提供对应主机的用户名与密码了,所以,在完成了密钥认证的相关配置后,我们可以将清单中的配置精简为如下格式。
test3 ansible_host=172.31.46.22 ansible_port=22
当然,如果你的受管服务器中的sshd服务使用了默认的22号端口,上述配置中的ansible_port也是可以省略的,为了方便演示,演示环境中的所有受管主机均使用默认的sshd端口号。
在今后的演示中,默认使用密钥认证的方式连接到对应主机,我会提前配置好各个受管主机的密钥认证,后文中将不再对密钥认证的配置过程进行描述。
3.清单配置详解
在前文中,我们已经介绍了怎样简单的配置清单,比如通过IP地址的方式配置受管主机,或者通过别名的方式配置受管主机,此处不再赘述,假设,我想要通过ansible管理主机115与主机78,那么我可以在/etc/ansible/hosts中写入如下内容
test2 ansible_host=172.31.46.78 test4 ansible_host=172.31.46.115
配置完成后,即可通过命令管理这两台主机,仍然使用之前的示例命令作为演示。
如上图所示,我们使用了两条命令,分别去ping主机78和主机115,是没有问题的,其实,我们也可以使用"all"关键字,在一条命令中,一次性的去操作"清单"中的所有主机,示例如下
是不是很简单,有没有很方便?那么,聪明如你一定会想,我们能不能自定义一些类似"all"这样的关键字呢?
答案是肯定的,
清单支持"分组"功能,我们可以将某些主机分为一组,然后通过组名去管理组内的所有主机。
比如,主机78和主机22都属于A模块的服务器,主机115属于B模块的服务器,那么,我们则可以在清单中进行如下配置
[A] 172.31.46.22 172.31.46.78 [B] 172.31.46.115
上述配置表示我们定义了两个组,A组和B组,A组中包含主机22与78,B组中包含主机115,经过上述配置后,我们可以通过组名去管理组内的所有主机,示例如下
当然,在实际的应用中,我们并不会使用"A"或者"B"这样的名字作为组名,此处是为了演示方便,在实际使用时,组名应该尽量的见名知义
在实际应用中,如果你需要配置10台IP地址连续的主机时,只需要一条配置就可以搞定了,配置如下
[A] 172.31.46.[22:32]
上面配置代表A组包含从172.31.46.22到172.31.46.32之间所有ip
除了使用IP地址,我们也可以使用主机名配置受管主机,当然,使用主机名配置受管主机的前提是ansible主机可以正确解析对应的主机名,比如,我们想要通过主机名配置两台主机,示例如下。
眼尖的你一定又从上述配置中发现了某种规律,没错,上述主机名中,"dbSrv-"之后的字母是按照字母顺序排列的,所以,上述配置也可以简写为如下模样,它们的效果是相同的。
嵌套组的应用
通常情况下,我们为了更加的灵活的管理受管主机,可能需要在组内嵌套组。
比如,服务器环境从大类上可以分为"生产环境"和"测试环境",所以,我们很自然的把主机分成了两组,生产组和测试组,但是,仔细想想,生产环境又包含很多业务模块,比如,A模块生产组、B模块生产组,同理,测试环境中也会有同样的问题,比如A模块测试环境组,B模块测试组,这时,我们就需要更加细化的进行分组,示例如下
[proA] 172.31.46.22 [proB] 172.31.46.115 [pro:children] proA proB
上述示例表示我们配置了3个组,proA组、proB组、pro组,而pro组中包含"子组",没错,"children"关键字表示当前组中存在子组,pro组的子组就是proA组和proB组,也就是说,当我们操作pro组时,就相当于操作proA组和ProB组中的所有主机,这样分组就能为我们带来一些好处,比如,当我们需要针对生产环境中的所有主机进行操作时,调用pro组即可,当我们需要对生产环境中的某一个模块进行操作时,比如生产环境中的A模块,那么我们只调用proA组即可。
4.清单配置中语法详解(YAML语法的介绍)
到目前为止,我们一直都在使用INI的配置风格去配置"清单",其实,/etc/ansible/hosts不仅能够识别INI的配置语法,还能够识别"YAML"的配置语法。
YAML是一种语言,YAML是"YAML Ain't a Markup Language"的缩写,从YAML的全称可以看出来,YAML并不是一种标记语言,但是,如果你使用过类似XML这种标记语言,那么你可能会很快的学会YAML,与XML相同的是,我们可以使用YAML编写配置文件,而ansible的清单也支持YAML的语法,所以我们可以使用YAML语法编写清单,从而管理受管主机,这样说可能不是特别容易理解,不如先来看一个小例子(没有接触过YAML语法没有关系,先向下看)
如下示例仍然是在/etc/ansible/hosts文件中编写
all: hosts: 172.31.46.22: 172.31.46.115:
上述配置就是使用YAML语法配置的主机清单,非常简单
最上方使用all关键字,all后面有":",你一定联想到了,我们之前可以使用all关键字,管理清单中的所有主机,这里的"all:"就是这个含义。
第二行开头使用一个空格作为缩进,使用hosts关键字,表示hosts属于all的下一级,我们可以这样理解,all是默认的一个组,这个组是最大的一个组,当我们需要在组中定义受管主机时,就需要使用到hosts关键字,当我们进行自定义分组时,也需要使用hosts关键字,每个分组指明自己组内的受管主机时,都要使用到hosts关键字,注意,在YAML的语法中,只能使用空格作为缩进,不能使用tab,否则语法上会报错,
第三行开头使用两个空格作为缩进,然后指明了主机22的IP地址,没错,主机22的IP地址就是hosts元素下一级的元素
第四行开头使用两个空格作为缩进,然后指明了主机115的IP地址,你一定想明白了,主机22和主机115的层级是相同的,它们是平级的,因为它们的左侧缩进是对齐的。
为了让从来没有接触过YAML的朋友能够更好的理解,在下面的示例中,我们会先给出INI风格的配置,然后使用YAML语法写出同样效果的配置,并进行对比,以方便理解。
此处先列出上述YAML配置以及对应的INI配置
#YAML示例 all: hosts: 172.31.46.22: 172.31.46.115: #上例相当于如下INI配置 172.31.46.22 172.31.46.115
那么,我们来扩展一下,YAML分组语法
#先看一个INI风格的配置,示例如下 172.31.46.22 [test4] 172.31.46.115 [test2] 172.31.46.78 #上述配置表示当前清单中有3台受管主机,主机22不属于任何组,主机115属于test4组,主机78属于test2组
#使用YAML语法进行同等效果的配置如下
all:
hosts:
172.31.46.22
children:
test4:
hosts:
172.31.46.115:
test2:
hosts:
172.31.46.78:
#从上例可以看出,当直接在清单中创建组时,需要在all关键字内使用children关键字,而定义每个组时,有必须使用hosts关键字,指明组内的主机
有了上面的基础,我们来看一下当组中嵌套组时,使用YAML语法应该怎样描写
#仍然先写出INI风格的示例以作对比,如下 [proA] 172.31.46.78 [proB] 172.31.46.22 [pro:children] proA proB #对应YAML格式的配置如下 all: children: pro: children: proA: hosts: 172.31.46.78: proB: hosts: 172.31.46.22: #上述配置表示,pro组有两个子组,分别为proA组和proB组,而这两个组分别有自己组内的主机。
细心如你,一定已经发现,当我们使用YAML语法配置清单时,无非是使用hosts、children等关键字与我们的自定义名称进行排列组合罢了。
#前文中,我们还介绍了使用别名的方式配置受管主机,这里我们演示一下别名情况下YAML和INI格式的对比:
#INI格式的示例如下 172.31.46.78 test3 ansible_host=172.31.46.22 172.31.46.115 #同等效果的YAML语法配置如下 all: hosts: 172.31.46.78: test3: ansible_host: 172.31.46.22 172.31.46.115: #上面YMAL的ansible_host: 后面注意有一个空格,这是YAML的语法,省略空格后会报错
其实,我们还可以在清单中配置变量,但是,目前我们并没有实际的演示场景,所以此处先行略过。
更多内容可以参考官网手册,直达链接如下
http://docs.ansible.com/ansible/2.4/intro_inventory.html
3.ansible模块的介绍
1.ansible模块的基本使用
在前文的基础上,我们已经知道,当我们使用ansible完成实际任务时,需要依靠ansible的各个模块,比如,我们想要去ping某主机,则需要使用ping模块,命令如下
ansible all -m ping
前文说过,除了ping模块,ansible还有很多模块可供我们使用,那么ansible都有哪些模块呢?我们可以使用如下命令,查看ansible都有哪些模块。
ansible-doc -l
执行上述命令后,可以看到ansible中各个模块的名称,以及模块的大概功能,当然,通过"ansible-doc -l"命令获取到的模块信息比较概括,并不是特别详细,如果想要获取到各个模块更加详细的用法,可以使用“ansible-doc -s”命令,比如,我们想要获取ping模块的详细使用方法,则可以使用如下命令查看
ansible-doc -s ping
即使使用“ansible-doc -s ping”命令查看ping模块的信息,得到的信息也是比较少的,这是因为ping模块本来就比较简单,而且ping模块并没有太多参数可用,但是并非所有模块都像ping模块一样简单,有的模块在使用时必须使用参数,比如 fetch 模块,见名知义,fetch为"拿来"之意,当我们需要将受管主机中的文件拉取到ansible主机时,则可以使用此模块,首先,我们可以使用“ansible-doc -s fetch”命令,查看一下fetch模块的用法,如下图所示
从受管主机中拉取文件模块fetch的介绍使用
从帮助信息中可以看出,fetch模块的作用就是"Fetches a file from remote nodes",即"从受管主机中拉取文件"之意,而且fetch模块提供了一些参数供我们使用,我们可用的参数有 dest、fail_on_missing、flat、src、validate_checksum ,如上图所示,返回信息中注释了每个参数的作用。
比如src参数,src参数的作用就是指定从受管主机中拉取哪个文件。
比如dest参数,dest参数的作用就是指定拉取文件到本地以后文件存放的位置。
细心如你一定发现了,在上图中,dest参数和src参数的注释中都包含"(required)"字样,这表示,在使用fetch模块时,dest参数与src参数是必须提供的,如果在使用fetch模块时,没有提供这两个参数,将会报错,想想也对,如果我们想要从远程主机中拉取文件,那么我们必须告诉ansible,从哪里拉取文件,拉取后将文件存放到哪里吧,所以,在学习怎样使用一个模块时,要注意这些必选参数,那么,我们就从fetch模块入手,看看怎样使用带有参数的模块吧~
在开始之前,先来看一下我们的主机清单配置,配置如下
[testA] 172.31.46.78 172.31.46.22 [testB] 172.31.46.115 [test:children] testA testB
假如我们想要将testA组中所有主机的/etc/fstab文件拉取到本地,则可以使用如下命令
ansible testA -m fetch -a "src=/etc/fstab dest=/testdir/ansible/"
如上述命令所示,-m选项用于调用指定的模块,"-m fetch"表示调用fetch模块,
-a选项用于传递模块所需要使用的参数, -a "src=/etc/fstab dest=/testdir/ansible/"表示我们在使用fetch模块时,为fetch模块传入了两个参数,src与dest,这里dest后面的目录不存在也没关系,ansible会默认为我们创建,这就是ansible以结果为导向的特性。
那么,我们一起来看一下上述命令的执行效果吧,如下
你可能会有疑问,为什么命令执行成功了,返回的信息却是"黄色"的,在我们的印象中,执行成功,返回的信息不应该是"绿色"的吗?这是为什么呢?
这个时候我们只要再次执行一下上面的命令,然后把testA组主机中/etc/fstab文件做一些修改后,再次执行一下上面的命令。对比两次执行命令之后的结果,我们就能发现ansible的一些特性。
没错,这就是幂等性的体现,当第一次执行上述命令时,ansible发现当前主机中并没有我们需要的fstab文件,ansible就会按照我们指定的操作,拉取fstab文件,也就是说,ansible"改变"了"当前状态",将当前"没有fstab文件的状态"变为了"有fstab文件的状态",当我们再次执行同样的命令时,ansible发现对应文件已经存在与对应目录中,于是ansible并没有做出任何操作,也没有进行任何改变,因为"当前状态"与我们预期的"目标状态"一致,没有必要再做出重复的无用功。
看到这里,你应该已经明白,为什么执行ansible命令时,会返回黄色的成功信息或者绿色的成功信息了吧?我们可以通过返回信息的颜色,更加精准的判断执行命令之前的状态是否与我们预期的一致。
基本使用小结:
列出ansible所支持的模块
ansible-doc -l
查看模块的详细帮助信息,比如查看fetch模块的帮助
ansible-doc -s fetch
调用模块,比如调用ping模块
ansible all -m ping
调用模块的同时传入模块所需要的参数,以fetch模块为例
ansible 172.31.46.78 -m fetch -a "src=/etc/fstab dest=/testdir/ansible/"
2.常用模块之文件操作(copy模块,file模块,blockinfile模块,lineinfile模块,find模块,replace模块)
前文中,我们已经介绍了怎样使用模块,而且我们知道,ansible有很多模块,每个模块都有自己的功能,"模块"涉及到的方向比较多,所以对于个人来说,并没有必要了解所有的模块,我们只需要根据实际的业务场景了解相应的模块即可,而且ansible比较贴心,ansible根据模块的功能对这些模块进行了大致的分类,比如,如果某些模块都是操作文件的,就把它们分类到文件类模块中,如果某些模块都是操作数据库的,就把他们分类到数据库类模块中,那么,ansible把模块分为了哪些类呢?你可以参考官方手册,找到答案,模块的分类目录如下
https://docs.ansible.com/ansible/2.9/modules/modules_by_category.html#modules-by-category
上述链接不仅对模块进行了分类,还给出了每个模块的使用示例,不过这些示例都是编写"剧本(playbook)"的示例,我们还没有介绍过怎样编写剧本,所以暂时不会参考这些示例,前文的示例中,我们一直以命令的方式运行ansible,通过命令的方式调用模块,这种直接在命令行中运行的ansible命令被称作为"ad-hoc命令",我们可以通过"ad-hoc命令"的方式,快速的了解一个模块。
在前文的示例中,我们已经了解了ping模块与fetch模块,那么这篇文章中,我们来了解一些新的模块,这些模块都是常用的操作文件的模块
copy模块
见名知义,copy模块的作用就是拷贝文件,它与之前介绍的fetch模块类似,不过,fetch模块是从远程主机中拉取文件到ansible主机,而copy模块是将ansible主机上的文件拷贝到远程主机中。
此处我们介绍一些copy模块的常用参数,然后再给出对应示例。
src参数 :用于指定需要copy的文件或目录
dest参数 :用于指定文件将被拷贝到远程主机的哪个目录中,dest为必须参数
content参数 :当不使用src指定拷贝的文件时,可以使用content直接指定文件内容,src与content两个参数必有其一,否则会报错。
force参数 : 当远程主机的目标路径中已经存在同名文件,并且与ansible主机中的文件内容不同时,是否强制覆盖,可选值有yes和no,默认值为yes,表示覆盖,如果设置为no,则不会执行覆盖拷贝操作,远程主机中的文件保持不变。
backup参数 : 当远程主机的目标路径中已经存在同名文件,并且与ansible主机中的文件内容不同时,是否对远程主机的文件进行备份,可选值有yes和no,当设置为yes时,会先备份远程主机中的文件,然后再将ansible主机中的文件拷贝到远程主机。
owner参数 : 指定文件拷贝到远程主机后的属主,但是远程主机上必须有对应的用户,否则会报错。
group参数 : 指定文件拷贝到远程主机后的属组,但是远程主机上必须有对应的组,否则会报错。
mode参数 : 指定文件拷贝到远程主机后的权限,如果你想将权限设置为"rw-r--r--",则可以使用mode=0644表示,如果你想要在user对应的权限位上添加执行权限,则可以使用mode=u+x表示。
对应上述参数的ad-hoc示例命令如下:
将ansible主机中/testdir/copytest文件复制到远程主机的/opt目录下,注意,如果copytest文件已经存在于远程主机的/opt目录中,并且远程主机中的copytest与ansible主机中copytest文件内容不同,那么使用如下命令时,远程主机中的copytest文件将被覆盖。
ansible testB -m copy -a "src=/testdir/copytest dest=/opt/"
在远程主机的/opt目录下生成文件test,test文件中有两行文本,第一行文本为aaa,第二行为bbb,当使用content指定文件内容时,dest参数对应的值必须是一个文件,而不能是一个路径。(content参数用法实例)
ansible testB -m copy -a 'content="aaa\nbbb\n" dest=/opt/test'
将ansible主机中/testdir/copytest文件复制到远程主机的/opt目录中时,如果远程主机中已经存在/opt/copytest文件,并且文件内容与ansible主机中的copytest文件的内容不一致,则不执行拷贝操作,远程主机中的/opt/copytest文件内容不会被改变。(force参数用法实例)
ansible testB -m copy -a "src=/testdir/copytest dest=/opt/ force=no"
将ansible主机中/testdir/copytest文件复制到远程主机的/opt目录中时,如果远程主机中已经存在/opt/copytest文件,并且文件内容与ansible主机中的copytest文件的内容不一致,会执行拷贝操作,但是在执行拷贝操作之前,会将远程主机中的原文件重命名,以作备份,然后再进行拷贝操作。(backup参数用法实例)
ansible testB -m copy -a "src=/testdir/copytest dest=/opt/ backup=yes"
拷贝文件时,指定文件的属主,需要注意,远程主机上必须存在对应的用户。(owner参数用法实例)
ansible testB -m copy -a "src=/testdir/copytest dest=/opt/ owner=zsy"
拷贝文件时,指定文件的属组,需要注意,远程主机上必须存在对应的组。(group参数用法实例)
ansible testB -m copy -a "src=/testdir/copytest dest=/opt/ group=zsy"
拷贝文件时,指定文件的权限(mode参数用法实例)
ansible testB -m copy -a "src=/testdir/copytest dest=/opt/ mode=0640"
file模块
file模块可以帮助我们完成一些对文件的基本操作,比如,创建文件或目录、删除文件或目录、修改文件权限等
此处我们介绍一些file模块的常用参数,然后再给出对应示例。
path参数 :必须参数,用于指定要操作的文件或目录,在之前版本的ansible中,使用dest参数或者name参数指定要操作的文件或目录,为了兼容之前的版本,使用dest或name也可以。
state参数 :此参数非常灵活,此参数对应的值需要根据情况设定,比如,当我们需要在远程主机中创建一个目录的时候,我们需要使用path参数指定对应的目录路径,假设,我想要在远程主机上创建/testdir/a/b目录,那么我则需要设置path=/testdir/a/b,但是,我们无法从"/testdir/a/b"这个路径看出b是一个文件还是一个目录,ansible也同样无法单单从一个字符串就知道你要创建文件还是目录,所以,我们需要通过state参数进行说明,当我们想要创建的/testdir/a/b是一个目录时,需要将state的值设置为directory,"directory"为目录之意,当它与path结合,ansible就能知道我们要操作的目标是一个目录,同理,当我们想要操作的/testdir/a/b是一个文件时,则需要将state的值设置为touch,当我们想要创建软链接文件时,需将state设置为link,想要创建硬链接文件时,需要将state设置为hard,当我们想要删除一个文件时(删除时不用区分目标是文件、目录、还是链接),则需要将state的值设置为absent,"absent"为缺席之意,当我们想让操作的目标"缺席"时,就表示我们想要删除目标。
src参数 :当state设置为link或者hard时,表示我们想要创建一个软链或者硬链,所以,我们必须指明软链或硬链链接的哪个文件,通过src参数即可指定链接源。
force参数 : 当state=link的时候,可配合此参数强制创建链接文件,当force=yes时,表示强制创建链接文件,不过强制创建链接文件分为两种情况,情况一:当你要创建的链接文件指向的源文件并不存在时,使用此参数,可以先强制创建出链接文件。情况二:当你要创建链接文件的目录中已经存在与链接文件同名的文件时,将force设置为yes,回将同名文件覆盖为链接文件,相当于删除同名文件,创建链接文件。情况三:当你要创建链接文件的目录中已经存在与链接文件同名的文件,并且链接文件指向的源文件也不存在,这时会强制替换同名文件为链接文件。
owner参数 :用于指定被操作文件的属主,属主对应的用户必须在远程主机中存在,否则会报错。
group参数 :用于指定被操作文件的属组,属组对应的组必须在远程主机中存在,否则会报错。
mode参数:用于指定被操作文件的权限,比如,如果想要将文件权限设置为"rw-r-x---",则可以使用mode=650进行设置,或者使用mode=0650,效果也是相同的,如果你想要设置特殊权限,比如为二进制文件设置suid,则可以使用mode=4700,很方便吧。
recurse参数:当要操作的文件为目录,将recurse设置为yes,可以递归的修改目录中文件的属性。
对应上述参数的ad-hoc示例命令如下:
在testB主机上创建一个名为testfile的文件,如果testfile文件已经存在,则会更新文件的时间戳,与touch命令的作用相同。(创建文件,state=touch)
ansible testB -m file -a "path=/testdir/testfile state=touch"
在testB主机上创建一个名为testdir的目录,如果testdir目录已经存在,则不进行任何操作。(创建目录,state=directory)
ansible testB -m file -a "path=/testdir/testdir state=directory"
在testB上为testfile文件创建软链接文件,软链接名为linkfile,执行下面命令的时候,testfile已经存在。(创建软链接,state=link)
ansible testB -m file -a "path=/testdir/linkfile state=link src=/testdir/testfile"
在testB上为testfile文件创建硬链接文件,硬链接名为hardfile,执行下面命令的时候,testfile已经存在。(创建硬链接,state=hard)
ansible testB -m file -a "path=/testdir/hardfile state=hard src=/testdir/testfile"
在创建链接文件时,如果源文件不存在,或者链接文件与其他文件同名时,强制覆盖同名文件或者创建链接文件,参考上述force参数的解释。(force=yes)
ansible testB -m file -a "path=/testdir/linkfile state=link src=sourcefile force=yes"
删除远程机器上的指定文件或目录(删除文件或目录,state=absent)
ansible testB -m file -a "path=/testdir/testdir state=absent"
在创建文件或目录的时候指定属主,或者修改远程主机上的文件或目录的属主。
ansible testB -m file -a "path=/testdir/abc state=touch owner=zsy" ansible testB -m file -a "path=/testdir/abc owner=zsy" ansible testB -m file -a "path=/testdir/abc state=directory owner=zsy"
在创建文件或目录的时候指定属组,或者修改远程主机上的文件或目录的属组。
ansible testB -m file -a "path=/testdir/abb state=touch group=zsy" ansible testB -m file -a "path=/testdir/abb group=zsy" ansible testB -m file -a "path=/testdir/abb state=directory group=zsy"
在创建文件或目录的时候指定权限,或者修改远程主机上的文件或目录的权限。
ansible testB -m file -a "path=/testdir/abb state=touch mode=0644" ansible testB -m file -a "path=/testdir/abb mode=0644" ansible testB -m file -a "path=/testdir/binfile mode=4700" ansible testB -m file -a "path=/testdir/abb state=directory mode=0644"
当操作远程主机中的目录时,同时递归的将目录中的文件的属主属组都设置为zsy。
ansible testB -m file -a "path=/testdir/abd state=directory owner=zsy group=zsy recurse=yes"
blockinfile模块
blockinfile模块可以帮助我们在指定的文件中插入"一段文本",这段文本是被标记过的,换句话说就是,我们在这段文本上做了记号,以便在以后的操作中可以通过"标记"找到这段文本,然后修改或者删除它,单单这样描述不是特别容易理解,结合下面的小例子动手做做立马就能够明白了。
此处我们介绍一些blockinfile模块的常用参数,你可以先对这些参数有一个大概了解,然后再看小示例。
path参数 :必须参数,指定要操作的文件。
block参数 :此参数用于指定我们想要操作的那"一段文本",此参数有一个别名叫"content",使用content或block的作用是相同的。
marker参数 :假如我们想要在指定文件中插入一段文本,ansible会自动为这段文本添加两个标记,一个开始标记,一个结束标记,默认情况下,开始标记为# BEGIN ANSIBLE MANAGED BLOCK,结束标记为# END ANSIBLE MANAGED BLOCK,我们可以使用marker参数自定义"标记",比如,marker=#{mark}test ,这样设置以后,开始标记变成了# BEGIN test,结束标记变成了# END test,没错,{mark}会自动被替换成开始标记和结束标记中的BEGIN和END,我们也可以插入很多段文本,为不同的段落添加不同的标记,下次通过对应的标记即可找到对应的段落。
state参数 : state参数有两个可选值,present与absent,默认情况下,我们会将指定的一段文本"插入"到文件中,如果对应的文件中已经存在对应标记的文本,默认会更新对应段落,在执行插入操作或更新操作时,state的值为present,默认值就是present,如果对应的文件中已经存在对应标记的文本并且将state的值设置为absent,则表示从文件中删除对应标记的段落。
insertafter参数 :在插入一段文本时,默认会在文件的末尾插入文本,如果你想要将文本插入在某一行的后面,可以使用此参数指定对应的行,也可以使用正则表达式(python正则),表示将文本插入在符合正则表达式的行的后面,如果有多行文本都能够匹配对应的正则表达式,则以最后一个满足正则的行为准,此参数的值还可以设置为EOF,表示将文本插入到文档末尾。
insertbefore参数 :在插入一段文本时,默认会在文件的末尾插入文本,如果你想要将文本插入在某一行的前面,可以使用此参数指定对应的行,也可以使用正则表达式(python正则),表示将文本插入在符合正则表达式的行的前面,如果有多行文本都能够匹配对应的正则表达式,则以最后一个满足正则的行为准,此参数的值还可以设置为BOF,表示将文本插入到文档开头。
backup参数 :是否在修改文件之前对文件进行备份。
create参数 :当要操作的文件并不存在时,是否创建对应的文件。
对应上述参数的ad-hoc示例命令如下:
为了方便举例,我们将/etc/rc.d/rc.local文件复制到/testdir目录中,以做测试
假如,我们想要在testB主机中的/testdir/rc.local文件尾部插入如下两行
systemctl start mariadb
systemctl start httpd
可以使用如下命令,(文件尾部插入指定文本,并加上默认标记)
ansible testB -m blockinfile -a 'path=/testdir/rc.local block="systemctl start mariadb\nsystemctl start httpd" '
使用path参数指定要操作的文件,使用block参数指定文本块内容,由于我们使用了ad-hoc命令,所以我们使用\n表示换行,在写ansible剧本时则可以直接将文本块写在多行中,但是我们还没有介绍剧本的编写,所以此处不用在意,当执行上述命令后,/testdir/rc.local的文件尾部会多出如下文本块
正如之前所说,blockinfile模块的作用就是在文件中添加、更新、或者删除"被标记的文本块",而上述被标记的文本块就是我们添加进文件的,# BEGIN ANSIBLE MANAGED BLOCK 和 # END ANSIBLE MANAGED BLOCK 就是blockinfile模块自动为我们添加的文本块标记,一个是开始标记,一个是结束标记。
我们也可以自定义标记,但是自定义的标记仍然要"成对出现",需要有开始标记和结束标记,示例如下(修改默认标记)
ansible testB -m blockinfile -a 'path=/testdir/rc.local block="systemctl start mariadb\nsystemctl start httpd" marker="#{mark} serivce to start" '
使用marker可以自定义文本块的标记, 上例中的"{mark}" 会自动被替换成开始标记中的"BEGIN" 和结束标记中的 "END",如果文件中不存在同名标记的文本块,那么文件的末尾将会出现如下文本块。
在执行完上述命令的基础上,执行如下命令。(修改指定标记下的文本)
ansible testB -m blockinfile -a 'path=/testdir/rc.local block="systemctl start mariadb" marker="#{mark} serivce to start" '
因为在执行此命令时,"#{mark} serivce to start"标记对应的文本块已经存在于文件中,而同时,block参数对应的内容又与之前文本块的内容不同,所以,这种情况下,对应文本块中的内容会被更新,而不会再一次插入新的文本块,这种用法相当于更新原来文本块中的内容,执行上述命令后,文本块的内容被更新为如下文本。
在执行完上述命令的基础上,执行如下命令(删除指定标记的文本块和标记)
ansible testB -m blockinfile -a 'path=/testdir/rc.local block="" marker="#{mark} serivce to start" '
因为在执行此命令时,"#{mark} serivce to start"标记对应的文本块已经存在于文件中,而同时,block参数对应的内容为空,这时,blockinfile模块会删除对应标记的文本块,我们还可以使用如下命令删除对应的文本块,它们的效果是相同的。
ansible testB -m blockinfile -a 'path=/testdir/rc.local marker="#{mark} serivce to start" state=absent'
是的,使用将state的值设置为absent,表示删除对应标记的文本块
默认情况下,文本块插入在文件的尾部,我们也可以将文本块插入指定的位置,比如,插入在文件开头,或者根据正则表达式去匹配对应的行,然后将文本块插入到匹配到的行的前头或者后头,示例如下
如果想要将文本块插入到文档的开头,可以使用insertbefore参数,将其值设置为BOF,BOF表示Begin Of File(插入文本块到匹配的行前)
ansible testB -m blockinfile -a 'path=/testdir/rc.local block="####blockinfile test####" marker="#{mark} test" insertbefore=BOF'
如果使用如下命令,表示将文本块插入到文档的结尾,与默认操作相同,将insertafter参数设置为EOF表示End Of File
ansible testB -m blockinfile -a 'path=/testdir/rc.local block="####blockinfile test####" marker="#{mark} test" insertafter=EOF'
使用如下命令表示使用正则表达式匹配行,将文本块插入到 "以#!/bin/bash开头的行" 之后
ansible testB -m blockinfile -a 'path=/testdir/rc.local block="####blockinfile test####" marker="#{mark} test reg" insertafter="^#!/bin/bash" '
使用backup参数,可以在操作修改文件之前,对文件进行备份,备份的文件会在原文件名的基础上添加时间戳
ansible testB -m blockinfile -a 'path=/testdir/rc.local marker="#{mark} test" state=absent backup=yes'
使用create参数,如果指定的文件不存在,则创建它,示例如下
ansible testB -m blockinfile -a 'path=/testdir/test block="test" marker="#{mark} test" create=yes'
lineinfile模块
我们可以借助lineinfile模块,确保"某一行文本"存在于指定的文件中,或者确保从文件中删除指定的"文本"(即确保指定的文本不存在于文件中),还可以根据正则表达式,替换"某一行文本"。
此处我们介绍一些lineinfile模块的常用参数,你可以先对这些参数有一个大概了解,然后再看小示例。
path参数 :必须参数,指定要操作的文件。
line参数 : 使用此参数指定文本内容。
regexp参数 :使用正则表达式匹配对应的行,当替换文本时,如果有多行文本都能被匹配,则只有最后面被匹配到的那行文本才会被替换,当删除文本时,如果有多行文本都能被匹配,这么这些行都会被删除。
state参数:当想要删除对应的文本时,需要将state参数的值设置为absent,absent为缺席之意,表示删除,state的默认值为present
backrefs参数:与一起使用state=present
。如果设置,则line
可以包含反向引用(位置和名称),如果regexp
匹配,则将填充该反向引用。此参数会稍微改变模块的操作;insertbefore
,并且insertafter
将被忽略,如果regexp
文件中的任何位置都不匹配,则文件将保持不变。如果regexp
确实匹配,则最后一个匹配的行将被扩展的line参数替换。
insertafter参数:借助insertafter参数可以将文本插入到“指定的行”之后,insertafter参数的值可以设置为EOF或者正则表达式,EOF为End Of File之意,表示插入到文档的末尾,默认情况下insertafter的值为EOF,如果将insertafter的值设置为正则表达式,表示将文本插入到匹配到正则的行之后,如果正则没有匹配到任何行,则插入到文件末尾,当使用backrefs参数时,此参数会被忽略。
insertbefore参数:借助insertbefore参数可以将文本插入到“指定的行”之前,insertbefore参数的值可以设置为BOF或者正则表达式,BOF为Begin Of File之意,表示插入到文档的开头,如果将insertbefore的值设置为正则表达式,表示将文本插入到匹配到正则的行之前,如果正则没有匹配到任何行,则插入到文件末尾,当使用backrefs参数时,此参数会被忽略。
backup参数:是否在修改文件之前对文件进行备份。
create参数 :当要操作的文件并不存在时,是否创建对应的文件。
对应上述参数的ad-hoc示例命令如下:
为了方便举例,我们使用/testdir/test文件作为被操作的文件,test文件内容如下
[root@centos-test4-no testdir]# cat test Hello ansible,Hiiii lineinfile - Ensure a particular line is in a file, lineinfile - or replace an existing line using a back-referenced regular expression.
确保指定的"一行文本"存在于文件中,如果指定的文本本来就存在于文件中,则不做任何操作,如果不存在,默认在文件的末尾插入这行文本,如下命令表示确保"test lineinfile"这行文本存在于/testdir/test文件中。
ansible testB -m lineinfile -a 'path=/testdir/test line="test lineinfile"'
如下命令表示根据正则表达式替换"某一行",如果不止一行能够匹配正则,那么只有最后一个匹配正则的行才会被替换,被匹配行会被替换成line参数指定的内容
ansible testB -m lineinfile -a 'path=/testdir/test regexp="^line" line="test text" '
根据line参数的内容删除行,如果文件中有多行都与line参数的内容相同,那么这些相同的行都会被删除。
ansible testB -m lineinfile -a 'path=/testdir/test regexp="^lineinfile" state=absent'
默认情况下,lineinfile模块不支持后向引用
如果将backrefs设置为yes,表示开启支持后向引用,使用如下命令,可以将test示例文件中的"Hello ansible,Hiiii"替换成"Hiiii",如果不设置backrefs=yes,则不支持后向引用,那么"Hello ansible,Hiiii"将被替换成"\2"
ansible testB -m lineinfile -a 'path=/testdir/test regexp="(H.{4}).*(H.{4})" line="\2" backrefs=yes'
insertafter、insertbefore、backup、create等参数就不再举例赘述了,可参考blockinfile模块,都是类似的
find模块
find模块可以帮助我们在远程主机中查找符合条件的文件,就像find命令一样。
此处我们介绍一些find模块的常用参数,你可以先对这些参数有一个大概了解,然后再看小示例。
paths参数 :必须参数,指定在哪个目录中查找文件,可以指定多个路径,路径间用逗号隔开,此参数有别名,使用别名path或者别名name可以代替paths。
recurse参数 : 默认情况下,只会在指定的目录中查找文件,也就是说,如果目录中还包含目录,ansible并不会递归的进入子目录查找对应文件,如果想要递归的查找文件,需要使用recurse参数,当recurse参数设置为yes时,表示在指定目录中递归的查找文件。
hidden参数 :默认情况下,隐藏文件会被忽略,当hidden参数的值设置为yes时,才会查找隐藏文件。
file_type参数 : 默认情况下,ansible只会根据条件查找"文件",并不会查找"目录"或"软链接"等文件类型,如果想要指定查找的文件类型,可以通过file_type指定文件类型,可指定的文件类型有any、directory、file、link 四种。
patterns参数 : 使用此参数指定需要查找的文件名称,支持使用shell(比如通配符)或者正则表达式去匹配文件名称,默认情况下,使用shell匹配对应的文件名,如果想要使用python的正则去匹配文件名,需要将use_regex参数的值设置为yes。
use_regex参数:默认情况下,find模块不会使用正则表达式去解析patterns参数中对应的内容,当use_regex设置为yes时,表示使用python正则解析patterns参数中的表达式,否则,使用glob通配符解析patterns参数中的表达式。
contains参数:使用此参数可以根据文章内容查找文件,此参数的值为一个正则表达式,find模块会根据对应的正则表达式匹配文件内容。
age参数 :使用此参数可以根据时间范围查找文件,默认以文件的mtime为准与指定的时间进行对比,比如,如果想要查找mtime在3天之前的文件,那么可以设置age=3d,如果想要查找mtime在3天以内的文件,可以设置age=-3d,这里所说的3天是按照当前时间往前推3天,可以使用的单位有秒(s)、分(m)、时(h)、天(d)、星期(w)。
age_stamp参数 :文件的时间属性中有三个时间种类,atime、ctime、mtime,当我们根据时间范围查找文件时,可以指定以哪个时间种类为准,当根据时间查找文件时,默认以mtime为准。
size参数 :使用此参数可以根据文件大小查找文件,比如,如果想要查找大于3M的文件,那么可以设置size=3m,如果想要查找小于50k的文件,可以设置size=-50k,可以使用的单位有t、g、m、k、b。
get_checksum参数 :当有符合查找条件的文件被找到时,会同时返回对应文件的sha1校验码,如果要查找的文件比较大,那么生成校验码的时间会比较长。
对应上述参数的ad-hoc示例命令如下:
在testB主机的/testdir目录中查找文件内容中包含abc字符串的文件,隐藏文件会被忽略,不会进行递归查找。
ansible testB -m find -a 'paths=/testdir contains=".*abc.*" '
在testB主机的/testdir目录以及其子目录中查找文件内容中包含abc字符串的文件,隐藏文件会被忽略。
ansible testB -m find -a 'paths=/testdir contains=".*abc.*" recurse=yes '
在testB主机的/testdir目录中查找以.sh结尾的文件,包括隐藏文件,但是不包括目录或其他文件类型,不会进行递归查找。
ansible testB -m find -a 'paths=/testdir patterns="*.sh" hidden=yes'
在testB主机的/testdir目录中查找以.sh结尾的文件,包括隐藏文件,包括所有文件类型,比如文件、目录、或者软链接,但是不会进行递归查找。
ansible testB -m find -a 'paths=/testdir patterns="*.sh" file_type=any hidden=yes'
在testB主机的/testdir目录中查找以.sh结尾的文件,只不过patterns对应的表达式为正则表达式,查找范围包括隐藏文件,包括所有文件类型,但是不会进行递归查找,不会对/testdir目录的子目录进行查找。
ansible testB -m find -a 'paths=/testdir patterns=".*\.sh" use_regex=yes file_type=any hidden=yes'
在testB主机的/testdir目录中以及其子目录中查找mtime在4天以内的文件,不包含隐藏文件,不包含目录或软链接文件等文件类型。
ansible testB -m find -a "path=/testdir age=-4d recurse=yes"
在testB主机的/testdir目录中以及其子目录中查找atime在2星期以内的文件,不包含隐藏文件,不包含目录或软链接文件等文件类型。
ansible testB -m find -a "path=/testdir age=-2w age_stamp=atime recurse=yes"
在testB主机的/testdir目录中以及其子目录中查找大于2G的文件,不包含隐藏文件,不包含目录或软链接文件等文件类型。
ansible testB -m find -a "paths=/testdir size=2g recurse=yes"
在testB主机的/testdir目录中以及其子目录中查找以.sh结尾的文件,并且返回符合条件文件的sha1校验码,包括隐藏文件
ansible testB -m find -a "paths=/testdir patterns=*.sh get_checksum=yes hidden=yes recurse=yes"
replace模块
replace模块可以根据我们指定的正则表达式替换文件中的字符串,文件中所有被正则匹配到的字符串都会被替换。
此处我们介绍一些replace模块的常用参数,你可以先对这些参数有一个大概了解,然后再看小示例。
path参数 :必须参数,指定要操作的文件,2.3版本之前,只能使用dest, destfile, name指定要操作的文件,2.4版本中,仍然可以使用这些参数名,这些参数名作为path参数的别名使用。
regexp参数 : 必须参数,指定一个python正则表达式,文件中与正则匹配的字符串将会被替换。
replace参数 : 指定最终要替换成的字符串。
backup参数 :是否在修改文件之前对文件进行备份,最好设置为yes。
对应上述参数的ad-hoc示例命令如下:
把testB主机中的/testdir/test文件中的所有ASM替换成asm
ansible testB -m replace -a 'path=/testdir/test regexp="ASM" replace=asm'
把testB主机中的/testdir/test文件中的所有ASM替换成asm,但是在操作文件之前进行备份。
ansible testB -m replace -a 'path=/testdir/test regexp="ASM" replace=asm backup=yes'
3.常用模块之命令类模块(command模块,shell模块,script模块)
command模块
command模块可以帮助我们在远程主机上执行命令
注意:使用command模块在远程主机中执行命令时,不会经过远程主机的shell处理,在使用command模块时,如果需要执行的命令中含有重定向、管道符等操作时,这些符号也会失效,比如"<", ">", "|", ";" 和 "&" 这些符号,如果你需要这些功能,可以参考后面介绍的shell模块,还有一点需要注意,如果远程节点是windows操作系统,则需要使用win_command模块。
此处我们介绍一些command模块的常用参数,你可以先对这些参数有一个大概了解,然后再看小示例。
free_form参数 :必须参数,指定需要远程执行的命令,需要说明一点,free_form参数与其他参数并不相同,在之前的模块示例中,如果想要使用一个参数,那么则需要为这个参数赋值,举个例子,之前的示例模块中,大多都有path参数,当我们需要指定要操作的文件时,通常需要对path参数赋值,比如,path=/testdir/test,表示我们想要操作/testdir/test文件,但是free_form参数则不同,"free_form"并不是一个"实际存在"的参数名,比如,当我们想要在远程主机上执行ls命令时,我们并不需要写成"free_form=ls" ,这样写反而是错误的,因为并没有任何参数的名字是free_form,当我们想要在远程主机中执行ls命令时,直接写成ls即可,这就是free_form参数的含义,因为command模块的作用是执行命令,所以,任何一个可以在远程主机上执行的命令都可以被称为free_form,如果你还是不明白,看下面的小示例就行了。
chdir参数 : 此参数的作用就是指定一个目录,在执行对应的命令之前,会先进入到chdir参数指定的目录中。
creates参数 :看到creates,你可能会从字面上理解这个参数,但是使用这个参数并不会帮助我们创建文件,它的作用是当指定的文件存在时,就不执行对应命令,比如,如果/testdir/test文件存在,就不执行我们指定的命令。
removes参数 :与creates参数的作用正好相反,它的作用是当指定的文件不存在时,就不执行对应命令,比如,如果/testdir/tests文件不存在,就不执行我们指定的命令,此参数并不会帮助我们删除文件
对应上述参数的ad-hoc示例命令如下:
使用如下命令,表示在testB主机上执行ls命令,因为我使用的是root用户,所以默认情况下,ls出的结果是testB主机中root用户家目录中的文件列表。
ansible testB -m command -a "ls"
chdir参数表示执行命令之前,会先进入到指定的目录中,所以如下命令表示查看testB主机上/testdir目录中的文件列表
ansible testB -m command -a "chdir=/testdir ls"
如下命令表示/testdir/test文件如果存在于远程主机中,则不执行对应命令,如果不存在,才执行"echo test"命令
ansible testB -m command -a "creates=/testdir/test echo test"
如下命令表示/testdir/test文件如果不存在于远程主机中,则不执行对应命令,如果存在,才执行"echo test"命令
ansible testB -m command -a "removes=/testdir/test echo test"
shell模块
shell模块可以帮助我们在远程主机上执行命令,与command模块不同的是,shell模块在远程主机中执行命令时,会经过远程主机上的/bin/sh程序处理。
学习此模块之前,请先参考本文中的command模块。
此处我们介绍一些shell模块的常用参数。
free_form参数 :必须参数,指定需要远程执行的命令,但是并没有具体的一个参数名叫free_form,具体解释参考command模块。
chdir参数 : 此参数的作用就是指定一个目录,在执行对应的命令之前,会先进入到chdir参数指定的目录中。
creates参数 :使用此参数指定一个文件,当指定的文件存在时,就不执行对应命令,可参考command模块中的解释。
removes参数 :使用此参数指定一个文件,当指定的文件不存在时,就不执行对应命令,可参考command模块中的解释。
executable参数:默认情况下,shell模块会调用远程主机中的/bin/sh去执行对应的命令,通常情况下,远程主机中的默认shell都是bash,如果你想要使用其他类型的shell执行命令,则可以使用此参数指定某种类型的shell去执行对应的命令,指定shell文件时,需要使用绝对路径。
shell模块中chdir、creates、removes参数的作用与command模块中的作用都是相同的,此处不再举例。
使用shell模块可以在远程服务器上执行命令,它支持管道与重定向等符号。
ansible testB -m shell -a "chdir=/testdir echo test > test1"
如果你想要执行的命令需要csh解析,那么可以指定使用csh在远程主机上执行对应的命令,比如在如下示例中,我们使用csh的语法定义了一个数字类型的变量TestNum,然后将TestNum变量的值重定向到了/testdir/TestNumFile,在bash中,@符号不能用于定义变量,所以,可以使用executable指定需要的shell类型。
ansible testB -m shell -a 'executable=/bin/csh @ TestNum=666 ; echo $TestNum > /testdir/TestNumFile'
script模块
学习此模块之前,请先参考本文中的command模块。
此处我们介绍一些script模块的常用参数,你可以先对这些参数有一个大概了解,然后再看小示例。
free_form参数 :必须参数,指定需要执行的脚本,脚本位于ansible主机本地,并没有具体的一个参数名叫free_form,具体解释参考command模块。
chdir参数 : 此参数的作用就是指定一个远程主机中的目录,在执行对应的脚本之前,会先进入到chdir参数指定的目录中。
creates参数 :使用此参数指定一个远程主机中的文件,当指定的文件存在时,就不执行对应脚本,可参考command模块中的解释。
removes参数 :使用此参数指定一个远程主机中的文件,当指定的文件不存在时,就不执行对应脚本,可参考command模块中的解释。
上述参数对应的ad-hoc示例命令如下:
如下命令表示ansible主机中的/testdir/atest.sh脚本将在testB主机中执行,执行此脚本之前,会先进入到testB主机中的/opt目录
ansible testB -m script -a "chdir=/opt /testdir/atest.sh"
如下命令表示,如果testB主机中的/opt/testfile文件已经存在,ansible主机中的/testdir/atest.sh脚本将不会在testB主机中执行,反之则执行。
ansible testB -m script -a "creates=/opt/testfile /testdir/atest.sh"
如下命令表示,如果testB主机中的/opt/testfile文件不存在,ansible主机中的/testdir/atest.sh脚本将不会在testB主机中执行,反之则执行。
ansible testB -m script -a "removes=/opt/testfile /testdir/atest.sh"
4.常用模块之系统类模块(cron模块,service模块,user模块,group模块)
cron模块
cron模块可以帮助我们管理远程主机中的计划任务,功能相当于crontab命令。
在了解cron模块的参数之前,先写出一些计划任务的示例,示例如下
#示例1
5 1 * * * echo test
#示例2
1 1 */3 * * echo test
#示例3
@reboot echo test
#示例4
@hourly echo test
上述示例1表示每天的1点5分输出test字符
上述示例2表示每3天执行一次计划任务,于当天的1点1分执行,具体任务为输出test字符
上述示例3表示每次系统启动后需要执行一次计划任务,具体任务为输出test字符
上述示例4表示每小时执行一次计划任务,具体任务 为输出test字符
根据上述示例,可以更好的了解cron模块的参数
cron模块通常使用的参数如下,你可以先大概的了解一下这些参数,然后再结合后面的示例去理解:
minute参数:此参数用于设置计划任务中分钟设定位的值,比如,上述示例1中分钟设定位的值为5,即minute=5,当不使用此参数时,分钟设定位的值默认为"*"
hour参数:此参数用于设置计划任务中小时设定位的值,比如,上述示例1中小时设定位的值为1,即hour=1,当不使用此参数时,小时设定位的值默认为"*"
day参数:此参数用于设置计划任务中日设定位的值,当不使用此参数时,日设定位的值默认为"*"
month参数:此参数用于设置计划任务中月设定位的值,当不使用此参数时,月设定位的值默认为"*"
weekday参数:此参数用于设置计划任务中周几设定位的值,当不使用此参数时,周几设定位的值默认为"*"
special_time参数:在上述示例3与示例4中,计划任务的时间设定格式为@reboot或者@hourly,@reboot表示重启时执行,@hourly表示每小时执行一次,相当于设置成"0 * * * *" ,这种@开头的时间设定格式则需要使用special_time参数进行设置,special_time参数的可用值有reboot(重启后)、yearly(每年)、annually(每年,与yearly相同)、monthly(每月)、weekly(每周)、daily(每天)、hourly(每时)。
注意:当上述时间单位设定参数都未指定时,计划任务的时间设定默认会被设定为"* * * * *",这样表示每分钟都会执行一次计划任务,所以,在使用cron模块时,我们应该确定对应的时间参数设置正确。
user参数:此参数用于设置当前计划任务属于哪个用户,当不使用此参数时,默认为管理员用户
job参数:此参数用于指定计划的任务中需要实际执行的命令或者脚本,比如上例中的"echo test"命令。
name参数:此参数用于设置计划任务的名称,计划任务的名称会在注释中显示,当不指定计划任务的名称时,ansible会默认为计划任务加入注释,注释的内容为#Ansible: None,假设指定计划任务的名称为test,那么注释的内容为#Ansible: test,在一台机器中,计划任务的名称应该具有唯一性,方便我们以后根据名称修改或删除计划任务。
state参数:当计划任务有名称时,我们可以根据名称修改或删除对应的任务,当删除计划任务时,需要将state的值设置为absent
disabled参数:当计划任务有名称时,我们可以根据名称使对应的任务"失效"(注释掉对应的任务),注意,使用此参数时,除了需要指定任务的名称,还需要同时指定任务的job以及任务的时间设定,而且任务的时间设定必须和对应任务完全相同,否则在注释任务的同时,任务的时间设定会被修改,除非你确定这样做,如果你不明白这段话的意思,可以参考下文中的示例。
backup参数:如果此参数的值设置为yes,那么当修改或者删除对应的计划任务时,会先对计划任务进行备份,然后再对计划任务进行修改或者删除,cron模块会在远程主机的/tmp目录下创建备份文件,以crontab开头并且随机加入一些字符,具体的备份文件名称会在返回信息的backup_file字段中看到,推荐将此此参数设置为yes。
cron模块的ad-hoc示例命令如下:
在testB主机上创建计划任务,任务名称为"test crontab",任务于每天1点5分执行,任务内容为输出test字符
ansible testB -m cron -a " name='test crontab' minute=5 hour=1 job='echo test' "
执行上述命令后,在testB主机中root用户下会有如下计划任务被创建
#Ansible: test crontab
5 1 * * * echo test
在testB主机上创建计划任务,任务名称为"crontab day test",任务每3天执行一次,于执行当天的1点1分开始执行,任务内容为输出test字符
ansible testB -m cron -a " name='crontab day test' minute=1 hour=1 day=*/3 job='echo test' "
在testB主机上创建计划任务,任务名称为"test special time",任务将在重启时执行,任务内容为输出test字符
ansible testB -m cron -a " name='test special time' special_time=reboot job='echo test' "
执行上述命令后,在testB主机中root用户下会有如下计划任务被创建
#Ansible: test special time
@reboot echo test
在"test special time"已经存在的情况下,当我们再次操作同名的任务时,ansible将会认为是修改原来的任务。所以当我们执行如下命令,原计划任务会被修改,因为启用了backup,所以任务在修改前会被备份。
ansible testB -m cron -a " name='test special time' special_time=hourly job='echo test' backup=yes "
命令执行后,从返回信息的backup_file字段中可以看到备份文件的远程主机中的位置
默认操作root用户的计划任务,如果想要操作远程主机中其他用户的计划任务,可以指定要操作的用户(注意这个用户远程主机一定要存在)
ansible testB -m cron -a "user=zsy name='test special time' special_time=hourly job='echo test'"
上述命令执行后,可以在远程主机中使用crontab -lu zsy查看对应的计划任务。
之前已经创建了名称为crontab day test的计划任务,如果我们想要暂时注释这个计划任务,可以使用如下命令,但是需要注意,在注释任务时,所有设定需要 跟原设定保持一致,否则计划任务的设置将会发生改变,示例如下
比如,我们想要将crontab day test这个任务注释掉,则需要使用如下命令,注意,最好与backup参数同时使用
ansible testB -m cron -a " name='crontab day test' minute=1 hour=1 day=*/3 job='echo test' disabled=yes backup=yes"
如果你在使用disabled参数时,设置了错误的时间,那么对应任务被注释的同时,时间设定也会发生改变,比如,如果你执行了如下命令
ansible testB -m cron -a " name='crontab day test' minute=55 job='echo test' disabled=yes backup=yes"
那么对应任务被注释的同时,同时还会进行如下设置
#Ansible: crontab day test
#55 * * * * echo test
如果你忘记了任何时间设定,那么在任务被注释时,还会被设置为默认的时间设定,也就是 "* * * * *"
所以,在使用disabled参数时,最好结合backup参数一起使用,万一一时大意,还有回旋的余地。
service模块
service模块可以帮助我们管理远程主机上的服务,比如,启动或停止远程主机中的nginx服务。
注意:假如你想要管理远程主机中的某个服务,那么这个服务必须能被 BSD init, OpenRC, SysV, Solaris SMF, systemd, upstart 中的任意一种所管理,否则service模块也无法管理远程主机的对应服务,这样说可能不容易理解,那么我们换个方式来解释,假设你在使用centos6,那么你的centos6中的nginx则必须能够通过"service nginx start"启动,如果你的nginx无法通过"service nginx start"进行启动,那么它将同样无法通过ansible的service模块启动,假设你在使用centos7,那么你的centos7中的nginx则必须能够通过"systemctl start nginx"启动,如果它无法通过"systemctl start nginx"进行启动,那么它将同样无法通过ansible的service模块进行启动,centos6中默认通过sysv管理服务,centos7中默认通过systemd管理服务,如果你的服务无法通过 BSD init, OpenRC, SysV, Solaris SMF, systemd, upstart 中的任意一种所管理,那么它也无法被ansible的service模块管理。
service模块通常使用的参数如下,你可以先大概的了解一下这些参数,然后再结合后面的示例去理解:
name参数:此参数用于指定需要操作的服务名称,比如nginx
state参数:此参数用于指定服务的状态,比如,我们想要启动远程主机中的nginx,则可以将state的值设置为started,如果想要停止远程主机中的服务,则可以将state的值设置为stopped,此参数的可用值有started、stopped、restarted、reloaded。
enabled参数:此参数用于指定是否将服务设置为开机 启动项,设置为yes表示将对应服务设置为开机启动,设置为no表示不会开机启动。
service模块的ad-hoc示例命令如下:
将testB中的nginx服务处于启动状态
ansible testB -m service -a "name=nginx state=started"
将testB中的nginx服务处于停止状态
ansible testB -m service -a "name=nginx state=stopped"
将testB中的nginx服务被设置为开机自动启动项
ansible testB -m service -a " name='nginx' enabled=yes"
user模块
user模块可以帮助我们管理远程主机上的用户,比如创建用户、修改用户、删除用户、为用户创建密钥对等操作。
此处我们介绍一些user模块的常用参数,你可以先对这些参数有一个大概了解,然后再看小示例。
name参数:必须参数,用于指定要操作的用户名称,可以使用别名user。
group参数:此参数用于指定用户所在的基本组
gourps参数:此参数用于指定用户所在的附加组,注意,如果说用户已经存在并且已经拥有多个附加组,那么如果想要继续添加新的附加组,需要结合append参数使用,否则在默认情况下,当再次使用groups参数设置附加组时,用户原来的附加组会被覆盖。
append参数:如果用户原本就存在多个附加组,那么当使用groups参数设置附加组时,当前设置会覆盖原来的附加组设置,如果不想覆盖原来的附加组设置,需要结合append参数,将append设置为yes,表示追加附加组到现有的附加组设置,append默认值为no。
shell参数:此参数用于指定用户的默认shell
uid参数:此参数用于指定用户的uid号
expires参数:此参数用于指定用户的过期时间,相当于设置/etc/shadow文件中的的第8列,比如,你想要设置用户的过期日期为2018年12月31日,那么你首先要获取到2018年12月31日的unix时间戳,使用命令"date -d 2018-12-31 +%s"获取到的时间戳为1546185600,所以,当设置expires=1546185600时,表示用户的过期时间为2018年12月31日0点0分,设置成功后,查看远程主机的/etc/shadow文件,对应用户的第八列的值将变成17895(表示1970年1月1日到2018年12月31日的天数,unix时间戳的值会自动转换为天数,我们不用手动的进行换算),目前此参数只支持在Linux和FreeBSD系统中使用。
comment参数:此参数用于指定用户的注释信息
state参数:此参数用于指定用户是否存在于远程主机中,可选值有present、absent,默认值为present,表示用户需要存在,当设置为absent时表示删除用户。
remove参数:当state的值设置为absent时,表示要删除远程主机中的用户,但是在删除用户时,不会删除用户的家目录等信息,这是因为remoove参数的默认值为no,如果设置为yes,在删除用户的同时,会删除用户的家目录,当state=absent并且remove=yes时,相当于执行"userdel --remove"命令
password参数:此参数用于指定用户的密码,但是这个密码不能是明文的密码,而是一个对明文密码"加密后"的字符串,相当于/etc/shadow文件中的密码字段,是一个对明文密码进行哈希后的字符串,你可以在python的命令提示符下输入如下命令,生成明文密码对应的加密字符串。
import crypt; crypt.crypt('666666')
输入上述命令后,即可得到明文密码666666对应的加密字符串。
update_password参数:此参数有两个值可选,always和on_create,当此参数的值设置为always时表示,如果password参数设置的值与用户当前的加密过的密码字符串不一致,则直接更新用户的密码,默认值即为always,但是当此参数设置为on_create时,如果password参数设置的值与用户当前的加密过的密码字符串不一致,则不会更新用户的密码字符串,保持之前的密码设定,如果是新创建的用户,即使此参数设置为on_create,也会将用户的密码设置为password参数对应的值。
generate_ssh_key参数:此参数默认值为no,如果设置为yes,表示为对应的用户生成ssh密钥对,默认在用户家目录的./ssh目录中生成名为id_rsa的私钥和名为id_rsa.pub的公钥,如果同名的密钥已经存在与对应的目录中,原同名密钥并不会被覆盖(不做任何操作)
ssh_key_file参数:当generate_ssh_key参数的值为yes时,使用此参数自定义生成ssh私钥的路径和名称,对应公钥会在同路径下生成,公钥名以私钥名开头,以".pub"结尾。
ssh_key_comment参数:当generate_ssh_key参数的值为yes时,在创建证书时,使用此参数设置公钥中的注释信息,但是如果同名的密钥对已经存在,则并不会修改原来的注释信息,即不做任何操作,当不指定此参数时,默认的注释信息为"ansible-generated on 远程主机的主机名"
ssh_key_passphrase参数:当generate_ssh_key参数的值为yes时,在创建证书时,使用此参数设置私钥的密码,但是如果同名的密钥对已经存在,则并不会修改原来的密码,即不做任何操作
ssh_key_type参数:当generate_ssh_key参数的值为yes时,在创建证书时,使用此参数设置密钥对的类型,默认密钥类型为rsa,但是如果同名的密钥对已经存在,并不会对同名密钥做任何操作
user模块的ad-hoc示例命令如下:
在testB主机上创建名为zsy的用户,如果用户已经存在,则不进行任何操作。
ansible testB -m user -a 'name=zsy'
在testB主机上删除名为zsy的用户,但是不会删除zsy用户的家目录
ansible testB -m user -a 'name=zsy state=absent'
在testB主机上删除名为zsy的用户,同时会删除zsy用户的家目录等信息
ansible testB -m user -a 'name=zsy state=absent remove=yes'
指定testB主机上的zsy用户的主组为ZF-USER,ZF-USER组需要提前存在,当不使用group设置主组时,默认主组与用户名相同。(创建用户时,指定用户组)
ansible testB -m user -a "name=zsy group=ZF-USER"
指定testB主机上的zsy用户的附加组为zsythink,zsythink组需要提前存在,当不使用groups设置附属组时,默认附加组与用户名相同,注意,为了保险起见,在不知道用户原来的附加组设定的情况下,最好将append参数设置为yes,我们也可以一次性设置多个附加组,附加组之间用逗号隔开,比如groups=zsy,zsythink,root 示例命令如下
ansible testB -m user -a "name=zsy groups=jenkins append=yes"
指定testB主机上的zsy用户使用/bin/csh作为默认shell
ansible testB -m user -a "name=zsy shell=/bin/csh"
指定testB主机上的zsy用户的uid为2002
ansible testB -m user -a "name=zsy uid=2002"
指定testB主机上的zsy用户的过期时间为2020年12月31日,使用"date -d 2020-12-31 +%s"命令可以获取到对应日期的unix时间戳。下面expires参数后面跟的就是unix的时间戳
ansible testB -m user -a 'name=zsy expires=1609344000'
指定testB主机上的zsy用户的注释信息
ansible testB -m user -a 'name=zsy comment="www.zsythink.net"'
将testB主机上的zsy用户的密码设置为666666
首先生成666666的加密字符串
[root@test1 ~]# python; Python 2.7.5 (default, Aug 4 2017, 00:39:18) [GCC 4.8.5 20150623 (Red Hat 4.8.5-16)] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> import crypt; crypt.crypt('666666') '$6$ygRbo7Fj.mMU2KY0$OEqihCCn5UfOsvMyzPNPBgx3bzAtwrOFyFvacgUmA374XOAEtUCrdjbW5Ip.Zqo491o3kD5I.HaC9nLhh6x741'
使用生成的密码字符串设置用户密码
ansible testB -m user -a ' name=zsy password="$6$ygRbo7Fj.mMU2KY0$OEqihCCn5UfOsvMyzPNPBgx3bzAtwrOFyFvacgUmA374XOAEtUCrdjbW5Ip.Zqo491o3kD5I.HaC9nLhh6x741" '
如下命令表示设置testB主机上的zsy用户的密码,但是如果用户当前的加密字符串与命令中设置的加密字符串不一致,则不进行密码更新的操作。
ansible testB -m user -a 'name=zsy password="$6$a.ofrhIWn4gJGbi0$i6Xhr.F/YyhMe2UCodydwyF952bP4DOf0qYcGE8aK.EsgOR/GKU0Oy9Ov6oIH3RIJ9BnhvoVR9ozflmUJgxhL0" update_password=on_create'
为testB上的zsy用户生成ssh密钥对,默认在用户家目录的./ssh目录中生成名为id_rsa的私钥和名为id_rsa.pub的公钥,如果已经存在同名密钥,并不会覆盖原来的密钥,即不做任何操作。
ansible testB -m user -a 'name=zsy generate_ssh_key=yes'
为testB上的zsy用户生成ssh密钥对,密钥对生成在/opt目录下,私钥名为id_rsa_zsy,公钥名为id_rsa_zsy.pub(生成密钥对,并指定私钥名称和路径,公钥名以私钥名开头,以".pub"结尾)
ansible testB -m user -a 'name=zsy generate_ssh_key=yes ssh_key_file=/opt/id_rsa_zsy'
为testB上的zsy用户生成ssh密钥对,同时指定公钥中的注释信息为"www.zsythink.net",此参数只能在创建密钥时使用才会生效,并不能操作同名的老密钥
ansible test70 -m user -a 'name=zsy generate_ssh_key=yes ssh_key_comment="www.zsythink.net"'
为testB上的zsy用户生成ssh密钥对,同时指定私钥的密码为123456,此参数只能在创建密钥时使用才会生效,并不能操作同名的老密钥
ansible testB -m user -a 'name=zsy generate_ssh_key=yes ssh_key_passphrase="123456"'
为testB上的zsy用户生成ssh密钥对,同时指定密钥对的类型为dsa,当不显式指定密钥类型时,默认类型为rsa,此参数只能在创建密钥时使用才会生效,并不能操作同名的老密钥
ansible testB -m user -a 'name=zsy generate_ssh_key=yes ssh_key_type=dsa'
group模块
group模块可以帮助我们管理远程主机上的组。
此处我们介绍一些group模块的常用参数,你可以先对这些参数有一个大概了解,然后再看小示例。
name参数:必须参数,用于指定要操作的组名称。
state参数:用于指定组的状态,两个值可选,present,absent,默认为present,设置为absent表示删除组。
gid参数:用于指定组的gid
group模块的ad-hoc示例命令如下:
确保testB主机中存在名为zsythink的组
ansible testB -m group -a ' name=zsythink'
删除testB主机中存在名为zsythink的组,删除成功的前提是不能有用户把被删除的组当成主组。
ansible testB -m group -a ' name=zsythink state=absent'
确保testB主机中存在名为zsythink的组,并且确定zsythink组的组id为1008
ansible testB -m group -a 'name=zsythink gid=1008'
5.常用模块之包管理模块(yum_repository模块,yum模块)
yum_repository模块
yum_repository模块可以帮助我们管理远程主机上的yum仓库。
此处我们介绍一些yum_repository模块的常用参数,你可以先对这些参数有一个大概了解,然后再看小示例。
name参数:必须参数,用于指定要操作的唯一的仓库ID,也就是".repo"配置文件中每个仓库对应的"中括号"内的仓库ID
baseurl参数:此参数用于设置yum仓库的baseurl
description参数:此参数用于设置仓库的注释信息,也就是".repo"配置文件中每个仓库对应的"name字段"对应的内容。
file参数:此参数用于设置仓库的配置文件名称,即设置".repo"配置文件的文件名前缀,在不使用此参数的情况下,默认以name参数的仓库ID作为".repo"配置文件的文件名前缀,同一个'.repo'配置文件中可以存在多个yum源
enabled参数:此参数用于设置是否激活对应的yum源,此参数默认值为yes,表示启用对应的yum源,设置为no表示不启用对应的yum源。
gpgcheck参数:此参数用于设置是否开启rpm包验证功能,默认值为no,表示不启用包验证,设置为yes表示开启包验证功能。
gpgcakey参数:当gpgcheck参数设置为yes时,需要使用此参数指定验证包所需的公钥
state参数:默认值为present,当值设置为absent时,表示删除对应的yum源
yum_repository模块的ad-hoc示例命令如下:
使用如下命令在testB主机上设置ID为aliEpel 的yum源,仓库配置文件路径为/etc/yum.repos.d/aliEpel.repo
ansible testB -m yum_repository -a 'name=aliEpel description="alibaba EPEL" baseurl=https://mirrors.aliyun.com/epel/$releasever\Server/$basearch/'
使用如下命令在testB主机上设置ID为aliEpel 的yum源,仓库配置文件路径为/etc/yum.repos.d/alibaba.repo
ansible testB -m yum_repository -a 'name=aliEpel description="alibaba EPEL" baseurl=https://mirrors.aliyun.com/epel/$releasever\Server/$basearch/ file=alibaba'
使用如下命令在testB主机上设置ID为local 的yum源,但是不启用它(local源使用系统光盘镜像作为本地yum源,以便测试举例,所以baseurl中的值以file:///开头)
ansible testB -m yum_repository -a 'name=local baseurl=file:///media description="local cd yum" enabled=no'
使用如下命令在testB主机上设置ID为local的yum源,开启包验证功能,并指定验证包所需的公钥位置为/media/RPM-GPG-KEY-CentOS-7
ansible testB -m yum_repository -a 'name=local baseurl=file:///media description="local cd yum" gpgcheck=yes gpgcakey=file:///media/RPM-GPG-KEY-CentOS-7'
删除/etc/yum.repos.d/alibaba.repo配置文件中的aliEpel源(这个意思就是alibaba.repo里面配置了多个源,删除指定的aliEpel源,不删除其他源)
ansible testB -m yum_repository -a 'file=alibaba name=aliEpel state=absent'
yum模块
yum模块可以帮助我们在远程主机上通过yum源管理软件包。
此处我们介绍一些yum模块的常用参数,你可以先对这些参数有一个大概了解,然后再看小示例。
name参数:必须参数,用于指定需要管理的软件包,比如nginx
state参数:用于指定软件包的状态 ,默认值为present,表示确保软件包已经安装,除了present,其他可用值有installed、latest、absent、removed,其中installed与present等效,latest表示安装yum中最新的版本,absent和removed等效,表示删除对应的软件包。
disable_gpg_check参数:用于禁用对rpm包的公钥gpg验证,默认值为no,表示不禁用验证,设置为yes表示禁用验证,即不验证包,直接安装,在对应的yum源没有开启gpg验证的情况下,需要将此参数的值设置为yes,否则会报错而无法进行安装。
enablerepo参数:用于指定安装软件包时临时启用的yum源,假如你想要从A源中安装软件,但是你不确定A源是否启用了,你可以在安装软件包时将此参数的值设置为yes,即使A源的设置是未启用,也可以在安装软件包时临时启用A源。
disablerepo参数:用于指定安装软件包时临时禁用的yum源,某些场景下需要此参数,比如,当多个yum源中同时存在要安装的软件包时,你可以使用此参数临时禁用某个源,这样设置后,在安装软件包时则不会从对应的源中选择安装包。
enablerepo参数和disablerepo参数可以同时使用
yum模块的ad-hoc示例命令如下:
确保testB主机上通过yum源安装了nginx(对应yum源未开启gpg验证,所以需要设置disable_gpg_check=yes),如下三条命令的效果相同
ansible testB -m yum -a 'name=nginx disable_gpg_check=yes' ansible testB -m yum -a 'name=nginx state=present disable_gpg_check=yes' ansible testB -m yum -a 'name=nginx state=installed disable_gpg_check=yes'
确保testB主机上安装了yum源中最新版本的nginx
ansible testB -m yum -a 'name=nginx state=latest disable_gpg_check=yes'
确保testB主机上通过yum源安装的nginx被卸载了
ansible testB -m yum -a 'name=nginx state=absent' ansible testB -m yum -a 'name=nginx state=removed'
在testB主机上安装telnet时不确定local源是否启用,使用enablerepo=local确保临时启用local源
ansible testB -m yum -a 'name=telnet disable_gpg_check=yes enablerepo=local'
在testB主机上安装telnet时,确定多个源中都有telnet,但是不想从local源中安装,所以在安装时临时禁用local源
ansible testB -m yum -a 'name=telnet disable_gpg_check=yes disablerepo=local'
4.实现自动分发公钥,远程管理多台主机
1.自动分发公钥出现背景及对应脚本介绍
上面我们介绍了ansible的一些基本概率和常用模块。我们知道ansible是基于ssh对远程主机进行管理的,上面演示的都是主机数量不多情况下的一些情况,可以通过一个个命令执行的方式把公钥分发到被管控主机上。但是如果机器比较多的话,之前的方法就不适用了,不过我们可以编写分发公钥脚本文件实现批量分发公钥。
脚本如下:
#!/bin/bash . /etc/rc.d/init.d/functions # 创建密钥 \rm ~/.ssh/id_rsa* -f ssh-keygen -t rsa -f ~/.ssh/id_rsa -N "" -q # 分发公钥 for ip in 31 41 8 do sshpass -p123456 ssh-copy-id -i ~/.ssh/id_rsa.pub " root@172.16.1.$ip -o StrictHostKeyChecking=no " &>/dev/null if [ $? -eq 0 ];then action "fenfa 172.16.1.$ip" /bin/true else action "fenfa 172.16.1.$ip" /bin/false fi echo "" done
上述脚本解释
脚本中引用 . /etc/rc.d/init.d/functions 函数,可以显示执行结果的判断。
使用if语句对结果进行判断,action 执行相应的动作。true/false
ssh-keygen -t rsa -f ~/.ssh/id_rsa -N "" -q 这条语句的作用是自动保存路径,并且不指定密码密码
参数说明:
-f filename Specifies the filename of the key
file
.
指定密钥文件保存的路径信息(免交互)
-P passphrase Provides the (old) passphrase.
提供一个密码信息
-N new_passphrase Provides the new passphrase.
-P -N 都是免交互方式指定密码信息
-q 安静的 不输出信息,减少信息输出
sshpass -p123456 ssh-copy-id -i ~/.ssh/id_rsa.pub " root@172.16.1.$ip -o StrictHostKeyChecking=no " &>/dev/null这条语句的作用是对公钥进行免交互分发。
具体参数解释如下
sshpass 该命令就是为ssh提供密码使用的,为了解决分发公钥的时候,需要手动输入密码的问题。
-i 指定要分发的公钥文件以及路径信息
-o StrictHostKeyChecking=no 的作用是对询问的回应(不进行对密钥检查)。这是因为在首次连接服务器时,会弹出公钥确认的提示。这会导致某些自动化任务,
由于初次连接服务器而导致自动化任务中断。
执行过程结果如下,后面OK就表示公钥分发成功。
上述公钥分发完毕之后,后面如果我们想知道哪些被管理机已经分发了公钥。我们可以通过下面的
基于密钥的批量管理脚本进行检查
[root@m01 scripts]# vim piliang_guanli.sh #!/bin/bash CMD=$1 for ip in 8 31 41 do echo ========host 172.16.1.$ip======= ssh root@172.16.1.$ip "$CMD" echo ============END=============== echo "" done
脚本执行效果如下
2.生产环境,批量分发公钥安全建议
上述示例脚本演示的都是通过root用户进行分发公钥,在实际生产环境中,这种方式可能不是那么安全,所以一般我们建议如下安全策略
禁止密码登录:
工作环境中,通常禁止用户使用密码登录,所以在ansible管理机中,需要生成秘钥(ssh-keygen),给所有被管理的服务器分发公钥,使ansible连接被管理服务器时,
采用秘钥登录不留下键盘输入,增强安全性 禁止root用户远程登录: 防止恶意破坏主机,可以指定一个普通用户,通过visudo授权ALL权限,使普通用户通过提权来获得高权限,这样防止root用户远程登录,又保证了对服务器所拥有的高权限
(这里需要注意,如果按上面指定了普通用户,那边管理端这边生成密钥的用户,也需要是这个用户生成的,然后分发给被管理机对应用户。不然进行密钥认证的时候,可能会
出相关问题) 普通用户密钥登录: 在该用户家目录下,放公钥,配置xshell以密钥登录 关闭GSSAPI认证 修改ssh连接端口,通常设定在1w以上,避免nmap命令扫描出来 权限控制:
注意公钥分发到被管理机上后,被管理机上.ssh目录权限是700,属主属组是该家目录用户,公钥文件权限是600。权限不能过大,不然可能会造成免密钥认证失败。
具体配置示例如下:
cat -n /etc/ssh/sshd_config | sed -n '17p;38p;43p;47p;65p;79p;115p' Port 22221 #修改端口,切记配置好密钥后再进行,不然分发公钥的时候比较麻烦 PermitRootLogin yes #yes表示开启root远程登录,非大规模服务器可以图方便开启,关闭改成no PubkeyAuthentication yes #开启公钥连接认证,默认是注释的 AuthorizedKeysFile .ssh/authorized_keys #指定公钥存放位置 PasswordAuthentication no #允许密码认证方式,no代表关闭,默认是yes GSSAPIAuthentication no #关闭GSSAPI认证,提高ssh连接速度 UseDNS no #关闭DNS反向解析,提高ssh连接速度
通过如下脚本可以进行sudo授权,让普通用户ZF_USER可以通过sudo su临时切换到root权限
#/bin/bash chmod u+w /etc/sudoers sed -i '/^root/a\ZF-USER ALL=(ALL) NOPASSWD: ALL' /etc/sudoers chmod u-w /etc/sudoers
为了安全,当我们通过sudo进行提权的时候,我们可以通过下面配置
配置ansible管理服务器sudo审计日志
开启sudo日志,rsyslog服务时所有日志记录的服务进程
echo "local1.debug /var/log/sudo.log" >> /etc/rsyslog.conf echo "Defaults logfile=/var/log/sudo.log" >> /etc/sudoers visudo -c #手动检测visudo语法是否正确 systemctl restart rsyslog #执行一次sudo提权,sudo su -,再查看sudo日志 cat /var/log/sudo.log