zoukankan      html  css  js  c++  java
  • 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分组语法

    ansible testB -m blockinfile -a 'path=/testdir/rc.local block="systemctl start mariadb
    systemctl start httpd" '

    使用path参数指定要操作的文件,使用block参数指定文本块内容,由于我们使用了ad-hoc命令,所以我们使用 表示换行,在写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
    systemctl 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模块

    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/$releaseverServer/$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/$releaseverServer/$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模块的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/aF-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
  • 相关阅读:
    [leetcode-693-Binary Number with Alternating Bits]
    [leetcode-695-Max Area of Island]
    [leetcode-690-Employee Importance]
    Windows Phone开发(17):URI映射
    Windows Phone开发(18):变形金刚第九季
    Windows Phone开发(19):三维透视效果
    Windows Phone开发(20):当MediaElement和VideoBrush合作的时候
    Windows Phone开发(21):做一个简单的绘图板
    Windows Phone开发(22):启动器与选择器之BingMapsDirectionsTask
    Windows Phone开发(1):概论
  • 原文地址:https://www.cnblogs.com/qingbaizhinian/p/14041251.html
Copyright © 2011-2022 走看看