ansible之playbooks用法

1、Playbooks基础:

Playbooks是一种完全不同的运用 ansible 的方式,是非常之强大的

简单来说,playbooks 是一种简单的配置管理系统与多机器部署系统的基础.与现有的其他系统有不同之处,且非常适合于复杂应用的部署

Playbooks 可用于声明配置,更强大的地方在于,在 playbooks 中可以编排有序的执行过程,甚至于做到在多组机器间,来回有序的执行特别指定的步骤.并且可以同步或异步的发起任务

YAML语法与其他高级语言类似,其结构通过缩进来展示,通过“-”来代表项;“:”用来分隔键和值;整个文件以”—“开头并以”…”结尾,其实三个点可以省略

下面是一个简单的例子,ping组webservers中的机器,如图:

上图中以”—开头”,hosts指定了要操作的主机组名称,可以有多个,中间用逗号分割,gather_facts表示获取被控主机的facts数据,设置为false表示关闭,关闭后可以提高playbooks的执行效率,否则会卡一会才会执行下一步,remote_user表示远程执行命令的用户,也可以在tasks任务中单独定义此任务执行所用的远程用户,最后通过三个点”…”结束,”…”可以省略,注意, 所有的“-”和“:”后面均有空格,而且注意缩进和对齐

执行playbooks,通过-i 指定执行主机清单(没用默认的/etc/ansible/hosts),如图:

2、Tasks 列表:

每一个 play 包含了一个 task 列表(任务列表).一个 task 在其所对应的所有主机上(通过 host pattern 匹配的所有主机)执行完毕之后,下一个 task 才会执行.有一点需要明白的是(很重要),在一个 play 之中,所有 hosts 会获取相同的任务指令,这是 play 的一个目的所在,也就是将一组选出的 hosts 映射到 task.

在运行 playbook 时(从上到下执行),如果一个 host 执行 task 失败,这个 host 将会从整个 playbook 的 rotation 中移除,然后继续向下执行其他host, 如果发生执行失败的情况,请修正playbook 中的错误,然后重新执行即可, 每个 task 的目标在于执行一个 moudle, 通常是带有特定的参数来执行.在参数中可以使用变量(variables)

modules 具有”幂等”性,意思是如果你再一次地执行 moudle(译者注:比如遇到远端系统被意外改动,需要恢复原状),moudle 只会执行必要的改动,只会改变需要改变的地方.所以重复多次执行 playbook 也很安全

每一个 task 必须有一个名称 name,这样在运行 playbook 时,从其输出的任务执行信息中可以很好的辨别出是属于哪一个 task 的. 如果没有定义 name,‘action’ 的值将会用作输出信息中标记特定的 task.

下面例子中,表示通过playbooks来启动webservers组中机器上的tomcat程序,webservers组中原来的登录用户变量为test,现在需要提权到root用户下执行命令,如图:

3、ansible-playbooks常用参数如下

--syntax-check:检测yaml文件的语法  例:ansible-playbook --syntax-check file.yml
-C(—check):预测试,不会改变目标主机设置 例:ansible-playbook --C file.yml
--list-hosts:列出yaml文件影响的主机列表 例:ansible-playbook --list-hosts file.yml
--list-tasks:列出yaml文件的任务列表
--list-tags:列出yaml文件中的标签
-t TAGS(--tags=TAGS):表示只执行指定标签的任务
--skip-tags=SKIP_TAGS:表示除了指定标签的任务,执行其他任务
--start-at-task=START_AT:从指定的任务开始往下运行

4、下面是一个通过playbooks来部署nginx的脚本,在playbooks目录下新建nginx.yml文件,内容如下:

---
- hosts: webservers      #要操作的主机地址
  gather_facts: false    #关闭获取被控机器的fact数据,可以加快速度
  remote_user: root      #远程执行用户为root
  tasks:
   - name: install nginx             #安装nginx
     yum: name=nginx state=present
   - name: copy nginx.conf           #复制本地配置文件到远程机器的nginx配置文件位置(如有需要)
     template: src=template/nginx.conf dest=/etc/nginx/conf.d/
   - name: copy index.html           #复制首页面(如有需要)
     template: src=template/index.html dest=/var/www/html/
     notify:
     - restart nginx     #notify相当于一个触发器,此名字和handlers名字一定要一致,通过notify去调用handlers执行handler中的任务
   - name: check nginx.conf
     shell: /usr/sbin/nginx -t   #检查nginx配置是否正常
   - name: start nginx
     service: name=nginx state=started   #启动nginx
  handlers:               #与前面的notify相呼应
     - name: restart nginx
       service: name=nginx state=restarted

注意:template目录也是在nginx.yml同级目录新建的,里面放上nginx.conf和index.html文件即可

handlers知识点:
    当之前定义在tasks中的任务执行成功后,若希望在此基础上触发其他任务,这时就需要定义handlers。例如,当通过ansible的模块对目标主机的配置文件进行修改之后,如果任务执行成功,可以触发一个触发器,在触发器中定义目标主机的服务重启操作,以使配置文件生效。handlers触发器具有以下特点:
1、handlers是Ansible提供的条件机制之一。
2、handlers和task很类似,但是它只在被task通知的时候才会触发执行。
3、handlers只会在所有任务执行完成后执行。
4、而且即使被通知了很多次,它也只会执行一次。
5、handlers按照定义的顺序依次执行。

在playbooks中定义变量

用户可以在playbook中通过vars关键字自定义变量,使用时候用{{}} 引用即可

例如:在下面的例子中,编写nginx_port.yml文件,自定义nginx的端口变量nginx_port,其值为80,然后通过{{}} 引用,如图:

上述脚本执行完成后将会在webservers组中的主机防火墙放开80端口

将变量放在单独的文件中

当变量比较多的时候,或者变量需要在多个playbook中重用的时候,可以把变量放到一个单独的文件中。通过关键字var_files把文件中定义的变量引入playbook中,使用变量的方法和在本文件中定义的变量相同

例如:在playbooks目录下创建文件夹vars,在vars中定义变量文件webservers.yml,然后在nginx_port.yml中通过关键字var_files来引用,如图:

变量文件webservers.yml的内容如下:

最后通过ansible-playbook nginx_port.yml -i ../inventory/hosts执行即可

定义和使用复杂变量:

有时候我们需要使用的变量的值不是简单的字符串或者数字,而是一个对象。这时候定义的语法如下,格式为YAML的字典格式,变量文件内容如下:

编写playbooks文件foo.yml,内容如下:

从上图中可以看出,访问复杂变量的子属性,可以通过中括号或者点号的形式,两种方法都可以

最后执行命令ansible-playbook foo.yml -i ../inventory/hosts即可

YAML的陷阱

YAML的陷阱是某些时候YAML和Ansible Playbook的变量语法不能在一起好好工作了,模块名冒号后面的值不能以{开头的时候,如果有必要以{开头,必须加上引号。总之在YAML值的定义中,如果提示YMAL语法错误,都可以尝试下加入引号来解决

例如:下面的例子表示定义变量one的值是/usr/bin/,然后在下面的shell命令中引用变量,如图:

上图中,模块名后面的变量引用是以”{” 开头,因此需要通过双引号引起来,否则报错,如果不以”{“开头一般不需要用双引号引起来

远程节点的系统变量(facts)

ansible会通过module setup来收集主机的系统信息,这些收集到的系统信息叫做facts,这些facts信息可以直接以变量的形式使用

# ansible webservers -m setup -i ../inventory/hosts,执行后可以看到输出了facts信息,如图表示一部分:

可直接在playbook文件中引用变量即可,如图:

如果要访问多层级的,负责的变量值,可通过下面两种方式,如图:

方法一,通过点号形式访问,如图:

注意:上述shell模块右侧的命令如果一行太长可以分两行写,如果更多层级可通过{{a.b.c.d}}方式访问即可

方法二:通过中括号形式访问 ,如图:

如果更多层级可通过{{a[‘b’][‘c’][‘d’]}}的 方式访问即可

文件模板中使用的变量

template模块在Ansible中很常用, 在playbook中定义的变量,可以直接在template中使用,同时facts变量也可以直接在template中使用, 当然也包含在inventory里面定义的host和group变量。只要是在playbook中可以访问的变量,都可以在template文件中使用

例如:下面playbook文件copy文件到远程机器,并获取远程机器的变量文件,如图:

file文件内容如下:

在远程机192.168.226.130的/tmp/file.html文件内容如下:

注册变量

把task的执行结果也可以作为一个变量值。这个时候就需要用到“注册变量”,将执行结果注册到一个变量中,待后面的action使用

例如:下面的playbooks文件表示将netstat -lntup命令注册到变量中,然后重定向问其他文件中,如图:

命令执行过程如下:

注意: 注册变量经常和debug module一起使用,这样可以得到更多action的输出信息,帮助用户调试

通过命令行传递变量

为了使Playbook更灵活、通用性更强,允许用户在执行的时候传入变量的值,这个时候就需要用到“额外变量”。

例如:在一个playbook文件release.yml中,hosts和remote_user 都定义为变量,然后通过命令行传递变量值,如图:

第一种,通过直接赋值的方式传递变量,如下:

ansible-playbook release.yml -i ../inventory/hosts --extra-vars "host=webservers user=root"
#上述命令通过--extra-vars参数执行额外变量,后面双引号中的内容为变量对应的实际内容
#可以使用--extra-vars参数,也可以使用简写的-e

第二种,除了上面的直接赋值方式,还可以通过json的方式进行传递值,如下:

#下面是通过json文件的形式来传递变量值
ansible-playbook release.yml -i ../inventory/hosts -e "{'host':'webservers','user':'root'}"

第三种,通过json文件的形式传递变量值,首先定义json文件,release.json,内容如下:

#将变量通过Json格式写入文件中,注意逗号
{
 'host': 'webservers',
 'user': 'root'
}

然后通过命令执行,如下:

#注意看在result.json文件前面还有一个@
ansible-playbook release.yml -i ../inventory/hosts -e "@result.json"

注意:上图中hosts和remote_user后面的变量引用要加双引号(冒号后面如果直接跟{}要加双引号)

条件语句when

有时候用户有可能需满足特定条件才执行某一个特定的步骤。例如,在某个特定版本的系统上装包,或者只在磁盘空间满了的文件系统上执行清理操作。这些操作在Playbook中用when语句实现。

例如:下面的例子表示当系统为RedHat的时候,创建文件,如图:

条件表达式

例如:定义变量test,当为true或者false的时候,执行不同的命令,如图:

循环语句

例如:在webservers组中主机循环创建两个用户,如图:

如果在变量区域定义了用户列表,那么也可以这样引用,如图:

角色(role)

Role是比include更强大灵活的代码重用和分享机制。Include类似于编程语言中的include,是重用单个文件的,功能有限。

而Role类似于编程语言中的“Package”,可以重用一组文件形成完整的功能。例如安装和配置apache,需要tasks实现安装包和拷贝模版等, httpd.conf和index.html的模版文件,和handler文件实现重起功能。这些文件都可以放在一个role里面,供不同的playbook文件重用。

1、定义role完整的目录结构:

在ansible中,通过遵循特定的目录结构,就可以实现对role的定义,具体遵循的目录结构是什么呢?看下面的例子:

下面的目录结构定义了一个role:名字为myrole。在site.yml,调用了这个role ,如图:

ansible并不要求role包含上述所有的目录及文件,根据role的功能需要加入对应的目录和文件。下面是每个目录和文件的功能

  • 如果 roles/x/tasks/main.yml 存在, 其中列出的 tasks 将被添加到 play 中,所以这个文件也可以视作role的入口文件,想看role做了什么操作,可以从此文件看起
  • 如果 roles/x/handlers/main.yml 存在, 其中列出的 handlers 将被添加到 play 中
  • 如果 roles/x/vars/main.yml 存在, 其中列出的 variables 将被添加到 play 中
  • 如果 roles/x/meta/main.yml 存在, 其中列出的 “角色依赖” 将被添加到 roles 列表中
  • roles/x/tasks/main.yml中所有tasks,可以引用 roles/x/{files,templates,tasks}中的文件,不需要指明文件的路径
  • 所有 script tasks 可以引用 roles/x/files/ 中的脚本,不需要指明文件的路径
  • 所有 template tasks 可以引用 roles/x/templates/ 中的文件,不需要指明文件的路径
  • 所有 copy tasks 可以引用 roles/x/files/ 中的文件,不需要指明文件的路径
  • 所有 include tasks 可以引用 roles/x/tasks/ 中的文件,不需要指明文件的路径

自己在写role的时候,一般都要包含role入口文件roles/x/tasks/main.yml,其它的文件和目录,可以根据需求选择加入

下面例子表示在webservers组中机器上部署nginx ,通过roles方式,首先在playbook目录下新建roles目录,然后在roles目录下创建web目录,表示角色名,在web目录下创建tasks、templates 目录(根据实际需要可定义其他文件夹),如图:

tasks中的主文件mail.yml内容如下:

templates文件夹中内容为nginx.conf和index.html

在playbook目录下,定义nginx安装文件,install_nginx.yml,内容如下:

最后执行ansible-playbook install_nginx.yml -i ../inventory/hosts即可

注意:上图中的roles参数表示引用web角色,会去调用tasks目录下的主文件mail.yml来执行相关命令,如果有多个项目可以定义多个角色

role也可以与when命令一起使用,如图:

标签