青蛙学Linux—Ansible中playbook的使用

1、什么是playbook

通过前面的几篇文章我们了解到,Ansible可以通过ad-hoc模式输入一条命令来执行任务,这对于一些简单的任务是非常方便的。但当我们执行的一个任务非常复杂需要进行大量的操作时,通过ad-hoc模式来执行就显得过于麻烦。

为此,Ansible为我们提供了playbook模式执行任务的功能。playbook的本意为剧本,我们可以通过编写playbook来将需要执行的任务交由Ansible一次性的执行,而不需要我们一条条命令的输入。

Ansible提供了ansible-playbook命令用于解析playbook文件。ansible-playbook命令将根据自上而下的顺序依次执行playbook文件中的内容。同时playbook允许传输某个命令的状态到后面的命令中,也可以从一台主机的文件中抓取内容并赋值给变量,然后在另一台主机中使用,这使得playbook可以实现一些复杂的部署机制。

playbook文件使用YAML语言书写。

2、YAML语言基础

想要编写playbook,必须先了解下YAML语言。

YAML是一个类似XML、JSON的标记性语言。YAML强调以数据为中心,并不是以标识语言为重点。YAML本身比较简单,是一种直观的能够被电脑识别的数据序列化格式,是一个可读性高并且容易被人类阅读,容易和脚本语言交互,用来表达资料序列的编程语言。它是类似于标准通用标记语言的子集XML的数据描述语言,语法比XML简单很多。

YAML的基本格式:

  • 使用---做为一个YAML的开头,…做为结尾,因为一个YAML文件中可以保存多个YAML内容,必须使用符号区分这些YAML
  • 大小写敏感
  • 使用缩进代表层级,缩进时使用空格,不能使用tab键
  • 缩进时不要求空格数量,只要求相同层级左对齐即可
  • 注释使用#开头 
  • 使用key: value的格式表示一个对象,注意,:后要加一个空格。如
    name: test
    
    name: 
      name1: test1
      name2: test2
  • 使用-后加一个空格表示一个数组项,如
    name:
      - test1
      - test2

3、playbook的构成

一个playbook文件主要由以下四部分构成:

  • target:定义将要执行playbook的远程主机或主机组
  • variable:定义playbook运行时需要使用到的变量
  • task:定义将要在远程主机上执行的任务列表
  • handler:定义task执行完成后需要调用的任务

4、playbook基础语法详解

4.1、target部分

target中使用以下两个关键字来定义将要执行playbook的主机/主机组以及用户:

  • hosts:用于指定要执行playbook的主机/主机组。每个playbook都必须定义hosts,可以使用通配符,值可以为主机IP、主机组名或者是all(表示主机清单里面的所有主机);hosts写在YAML的第一层级;主机和主机组在主机清单中指定,默认为/etc/ansible/hosts,也可以自定义,在执行ansible-playbook时使用-i选项指定自定义的主机清单;在执行ansible-playbook时使用--list-hosts选项将显示哪些主机将会执行playbook
  • remote_user:指定使用哪个用户身份在被管理主机上执行任务。在playbook中必须定义,写在YAML的第一层级

4.2、variable部分

该部分中使用以下格式定义参数(该部分可以定义在playbook全局中使用的变量,具体任务的变量可以在task部分中定义):

vars:    # 表示接下来是定义的参数,写在YAML的第一层级
  参数1: 值
  参数2: 值
  ...

4.3、task部分

该部分是playbook的主体,在playbook中必须存在。Ansible按从上到下的顺序在指定的主机或主机组上执行任务(在所有主机上完成一个任务后再接下去执行第二个任务),在任务执行过程中如果某个任务发生错误,则所有已经执行的任务都将回滚,因此更正playbook之后必须重新执行一次所有任务。

该部分的格式如下:

tasks:                  # 定义task部分的开始,在YAML中的第一层级
  - name: 自定义任务名    # 可选项,自定义该任务的名称,在playbook执行的时候输出在屏幕上
    Ansible模块: 选项1=值 选项2=值 ...
  - name: 自定义任务名
    Ansible模块: 选项1=值 选项2=值 ...
  ...

忽略playbook中某个task的错误继续执行剩余task

上面我们提到,当playbook在执行任务过程中发生错误,那么已经执行的任务都将回滚。同时ansible-playbook命令将会退出,playbook中剩余的任务将不会继续执行。但是,如果出错的任务影响不大,或者我们需要继续执行playbook中剩余的任务,可以使用以下关键字忽略错误:

ignore_errors: true
# 在具体的任务中设置,默认值为false,发生错误时中断playbook的执行

仅运行或跳过某些task

在执行playbook时,也可以选择仅运行某个task或者跳过某个task。要实现这一功能可以在task部分中使用tags关键字:

tasks:
  - name: 自定义任务名
    Ansible模块: 选项1=值 选项2=值
    tags: 自定义tags名称1    # 自定义的名称,用于在ansible-playbook命令中指定运行或跳过
  - name: 自定义任务名
    Ansible模块: 选项1=值 选项2=值
    tags: 自定义tags名称2

在ansible-playbook命令中使用tags:

# 该playbook名称设置为test.yml

# 仅运行第一个task
ansible-playbook -t|--tags=自定义tags名称1 test.yml

# 不运行第一个task
ansible-playbook --skip-tags=自定义tags名称1 test.yml

注意:每个task除了可以设置自己的tags外,还可以设置相同的tags,以实现一次运行几个task或者一次跳过几个task的功能

tasks:
  - name: test1
    ...
    tags:
      - test11
      - test22
  - name: test2
    ...
    tags:
      - test33
      - test22

4.4、handler部分

该部分的格式如下:

tasks:
  - name: xxx
    Ansible模块: 选项1=值 选项2=值 ...
    notify:             # 在任务执行完调用handler
      - handler name    # 必须与下面handlers中name的值一样
handlers:               # 定义handler,在YAML的第一层级
  - name: handler name
    Ansible模块: 选项1=值 选项2=值 ...

4.5、收集被管理主机信息

在playbook执行的时候,默认会有一个task,而且是playbook中的第一个task,那就是通过setup模块来收集被管理主机的facts信息,这些信息包括被管理主机的发行版、IP地址、CPU、主机名、内存等信息(具体可以查看上篇文章中的setup模块介绍)。Ansible使用JSON格式呈现这些信息。

如果在playbook中的task里没有用到这些facts信息,那么我们可以在target部分中使用以下关键字禁用收集信息的这个task:

gather_facts: false
# 写在YAML中的第一层级,该关键字的值默认为true

4.6、playbook中的条件和循环

在playbook中使用关键字when来进行条件判断,条件表达式使用Python语言编写,如只有在被管理主机的操作系统为CentOS 7时才执行这个task:

tasks:
  - name: xxx
    xxx: xxx=x
    when: ansible_distribution == 'CentOS' and ansible_distribution_major_version == '7'

循环的格式如下:

tasks:
  - name: 自定义任务名
    Ansible模块: 选项={{item}}
    with_items:
      - 值1
      - 值2
      ...

4.7、获取任务执行后的返回结果

在playbook中如果需要获取任务执行后返回的结果,可以使用以下关键字将返回结果赋值给一个自定义变量:

register: 自定义变量

任务执行的返回结果是一个字典。

4.8、playbook执行输出解析

playbook的执行结果使用以下三种颜色表示不同的执行结果:

  • 绿色代表执行成功,但系统没有任何改变
  • 黄色代表执行成功,且系统发生了改变,也就表明执行的操作已经生效
  • 红色代表执行失败,将会输出错误信息

playbook只有在执行错误时才会输出错误信息,执行成功则无详细信息输出。如果需要查看执行成功的信息,可以使用ansible-playbook的-v选项输出更详细的信息。

5、一个例子

编写一个playbook,在centos6组的两台主机上判断是否安装了telnet,如果没有安装的话则使用YUM进行安装。

这里使用rpm –qa|grep telnet命令来判断telnet是否已经安装,如果telnet尚未安装,则该命令无返回值。我们在playbook中执行该命令来查看返回的是什么内容,以便在安装telnet任务中进行判断,playbook文件命名为telnet.yaml,内容如下:

---
- hosts: centos6
  remote_user: root
  gather_facts: false
  tasks:
    - name: judge telnet
      shell: rpm -qa|grep telnet

我们先来执行这个playbook,看下返回的内容:

[root@localhost ~]# ansible-playbook telnet.yaml -k

执行返回:

7

通过返回的信息,我们发现可以通过msg这个键或者rc这个键的值判断命令的运行结果。rpm –qa|grep telnet这个命令如果没有查找的telnet,则返回值为1,Ansible通过返回值来判断命令执行成功与否。rc键即为命令返回值,而msg键则给出了non-zero return code的信息。我们通过这两个键的值就可以判断被管理主机是否安装了telnet。

所以,我们再给这个playbook添加一个任务以执行安装telnet的动作,完整的playbook内容如下:

---
- hosts: centos6
  remote_user: root
  gather_facts: false
  tasks:
    - name: judge telnet                 # 任务一:判断telnet是否已经安装
      shell: rpm -qa|grep telnet
      register: return_msg               # 任务返回值赋值给自定义变量return_msg
      ignore_errors: true                # 忽略该任务的错误,以便下一个任务可以执行
    - name: install telnet               # 任务二:安装telnet
      yum: name=telnet state=installed
      when: return_msg["rc"] == 1        # 使用Python语法的表达式,此时return_msg的值为一个字典

执行这个playbook,我们需要任务执行成功的输出信息,使用以下命令:

[root@localhost ~]# ansible-playbook telnet.yaml -v -k

执行的返回:

8

可以看到centos6组的两台主机已经成功安装了telnet。此时再执行开头的那个playbook,看看返回的结果:

9

此时执行rpm –qa|grep telnet已经不会返回错误了。

原文地址:https://www.cnblogs.com/yu2006070-01/p/10174634.html