zoukankan      html  css  js  c++  java
  • 青蛙学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已经不会返回错误了。

  • 相关阅读:
    【集合遍历-Java】
    【eclipse】使用说明
    【Java IO流】浅谈io,bio,nio,aio
    【Mysql数据库】知识点总结
    【struts2】学习笔记
    【EL&JSTL】学习笔记
    思科交换机-常用命令及配置
    【JDBC-MVC模式】开发实例
    【JDBC】java连接MySQL数据库步骤
    【JDBC】Servlet实例
  • 原文地址:https://www.cnblogs.com/yu2006070-01/p/10174634.html
Copyright © 2011-2022 走看看