章工运维 章工运维
首页
  • linux
  • windows
  • 中间件
  • 监控
  • 网络
  • 存储
  • 安全
  • 防火墙
  • 数据库
  • 系统
  • docker
  • 运维工具
  • other
  • elk
  • K8S
  • ansible
  • Jenkins
  • GitLabCI_CD
  • 随笔
  • 面试
  • 工具
  • 收藏夹
  • Shell
  • python
  • golang
友链
  • 索引

    • 分类
    • 标签
    • 归档
    • 首页 (opens new window)
    • 关于我 (opens new window)
    • 图床 (opens new window)
    • 评论 (opens new window)
    • 导航栏 (opens new window)
周刊
GitHub (opens new window)

章工运维

业精于勤,荒于嬉
首页
  • linux
  • windows
  • 中间件
  • 监控
  • 网络
  • 存储
  • 安全
  • 防火墙
  • 数据库
  • 系统
  • docker
  • 运维工具
  • other
  • elk
  • K8S
  • ansible
  • Jenkins
  • GitLabCI_CD
  • 随笔
  • 面试
  • 工具
  • 收藏夹
  • Shell
  • python
  • golang
友链
  • 索引

    • 分类
    • 标签
    • 归档
    • 首页 (opens new window)
    • 关于我 (opens new window)
    • 图床 (opens new window)
    • 评论 (opens new window)
    • 导航栏 (opens new window)
周刊
GitHub (opens new window)
  • ansible系列文章

    • ansible入门
    • anisble批量安装node_exporter
    • ansible-playbook中的变量
    • Ansible性能优化——提升ansible执行效率
    • ansible之roles简单使用
    • ansible中template简单使用
    • playbook详解
      • ansible-playbook编排使用tips
      • ansible优秀案例
      • 如何优雅向chatgpt提问ansible相关问题
    • Kubernetes笔记

    • elk

    • jenkins

    • GitLabCI_CD

    • 专题
    • ansible系列文章
    章工运维
    2022-12-09
    目录

    playbook详解

    # Ansible 中的 playbook 详解 (opens new window)

    目录

    • 一、playbook
      • 1.1 playbook是什么 (opens new window)
      • 1.2 playbook的语法结构 (opens new window)
      • 1.3 限定主机范围执行 (opens new window)
      • 1.4 ansible-palybook的小技巧 (opens new window)
      • 1.5 ansible-playbook中的handlers (opens new window)
      • 1.6 使用handlers的注意事项 (opens new window)
    • 二、变量
      • 2.1 playbook中的变量 (opens new window)
      • 2.2 playbook中使用vars代码块定义变量 (opens new window)
      • 2.3 使用独立的文件来定义playbook变量 (opens new window)
      • 2.4 inventory文件中的变量 (opens new window)
      • 2.5 主机变量和组变量 (opens new window)
      • 2.6 巧用主机变量和组变量 (opens new window)
      • 2.7 注册变量 (opens new window)
    • 三、高阶变量
      • 3.1 fasts变量信息 (opens new window)
      • 3.2 本地facts变量 (opens new window)
    • 四、if/when/while流程控制语句
      • 4.1 when条件判断 (opens new window)
    • 五、任务间的流程控制
      • 5.1 任务委托 (opens new window)
      • 5.2 任务暂停 (opens new window)
      • 5.3 交互式提示 (opens new window)
    • 六、tags标签 (opens new window)
    • 七、Block块 (opens new window)

    # 一、playbook

    # 1.1 playbook是什么

    根本上说playbook和shell脚本没有任何的区别,playbook就像shell一样,也是把一堆的命令组合起来,然后加入对应条件判断等等,在shell脚本中是一条一条的命令,而在playbook中是一个一个的task任务构成,每个task任务可以看做shell中的一条命令;shell脚本一般只是在当前服务器上执行,而playbook则是在不止一个服务器上执行,因此playbook需要在其中指定运行该playbook的服务器名。

    # 1.2 playbook的语法结构

    playbook使用yml标记语言,这是一种标记语言,这种标记语言在文件的最开始需要使用三个“-”来说明文件开始,然后使用缩进来说明代码块的范围。下面通过一个简易的实例,来说明playbook的语法。

    ---      # 标记文件的开始
    - hosts: webservers   # 指定该playbook在哪个服务器上执行
      vars:         # 表示下面是定义的变量,
        http_port: 80    # 变量的形式,key: value,这里http_port是变量名,80是值
        max_clients: 200
      remote_user: root  # 指定远程的用户名,这里缩进和vars保持了一致,说明变量的代码块已经结束。
      tasks:  # 下面构成playbook的tasks,每个task都有 - name: 开始,name指定该任务的名称。
      - name: ensure apache is at the latest version  # 指定该任务的名称。
        yum: pkg=httpd state=latest  # yum说明要是用的模板名称,后面指定对应的参数,这两行结合起来就相当于一个shell命令。
    
      - name: write the apache config file      # 每个task之间可以使用空行来做区分。
        template: src=/srv/httpd.j2 dest=/etc/httpd.conf
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12

    需要说明的是缩进的意义和python中缩进的意义是一样,是来区分代码块的。

    一个简单的实例:检查MySQL的运行状态

    ---
     - hosts: all
       remote_user: root
       gather_facts: no   # 不收集对应主机的信息,这样运行会快点。
       tasks:
         - name: check the mysql stauts
           service: name=mysqld state=running
    
    1
    2
    3
    4
    5
    6
    7

    运行playbook:

    $ ansible-playbook test.yml
    
    PLAY [all] ********************************************************************
    
    TASK: [check the mysql stauts] ************************************************
    ok: [10.0.102.200]
    ok: [10.0.102.162]
    ok: [10.0.102.212]
    
    PLAY RECAP ********************************************************************
    10.0.102.162               : ok=1    changed=0    unreachable=0    failed=0
    10.0.102.200               : ok=1    changed=0    unreachable=0    failed=0
    10.0.102.212               : ok=1    changed=0    unreachable=0    failed=0
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13

    # 1.3 限定主机范围执行

    虽然playbook中定义了执行的主机,但是有时候我们可能仅想在定义的主机中的部分机器上执行,这时候怎么办?修改playbook中的hosts的范围,但是每次改变主机就修改一次,比较麻烦,我们可以使用--limit参数,指定该playbook在指定的主机上执行。有以下inventory文件,我们想在dbservers上执行上面测试用的playbook内容。

    [all]
    10.0.102.212
    10.0.102.200
    10.0.102.162
    
    [dbservers]
    10.0.102.162
    
    1
    2
    3
    4
    5
    6
    7

    上面测试的playbook中hosts定义all,我们想仅在dbservers上执行。

    $ ansible-playbook test.yml --limit dbservers
    
    PLAY [all] ********************************************************************
    
    TASK: [check the mysql stauts] ************************************************
    ok: [10.0.102.162]
    
    PLAY RECAP ********************************************************************
    10.0.102.162               : ok=1    changed=0    unreachable=0    failed=0
    
    1
    2
    3
    4
    5
    6
    7
    8
    9

    查看当前playbook在哪些主机上执行

    $ ansible-playbook test.yml --list-hosts
    
    playbook: test.yml
    
      play              # 1 (all): host count=3
        10.0.102.162
        10.0.102.212
        10.0.102.200
    
    1
    2
    3
    4
    5
    6
    7
    8

    # 1.4 ansible-palybook的小技巧

    • --inventory=path,指定inventory文件,默认是在/etc/ansible/hosts下面。
    • --verbose,显示详细的输出,使用-vvvv显示精确到每分钟的输出。
    • --extra-vars=vars:定义在playbook使用的变量。
    • --forks:指定并发的线程数,默认是5.
    • --connection=type:指定远程连接主机的方式,默认是ssh,设置为local时,则只在本地执行playbook、
    • --check:检测模式,playbook中定义的所有任务将在每台主机上检测,但是并不执行。

    # 1.5 ansible-playbook中的handlers

    在系统中,我们修改了服务器的配置文件,这时候就需要重启操作服务,就可以使用到handlers。

    handlers:             # 定义两个handlers
        - name: restart memcached
          service:  name=memcached state=restarted
        - name: restart apache
          service: name=apache state=restarted
    
    - name: template configuration file
      template: src=template.j2 dest=/etc/foo.conf  # 修改了配置文件然后依次启动memcached和apache服务。
      notify:        # 使用notify来声明引用handlers。
         - restart memcached
         - restart apache
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11

    # 1.6 使用handlers的注意事项

    • Handlers只有在其所在的任务被执行时,才会被运行;如果一个任务中定义了notify调用Handlers,但是由于条件判断等原因,该任务未被执行,那么Handlers同样不会被执行。
    • Handlers只会在每一个play的末尾运行一次;如果想在一个playbook中间运行Handlers,则需要使用meta模块来实现。例如:-meta: flush_handlers.
    • 如果一个play在运行到调用Handlers的语句之前失败了,那么这个Handlers将不会被执行。我们可以使用meta模块的--force-handlers选项来强制执行Handlers,即使Handlers所在的play中途运行失败也能执行。

    # 二、变量

    这个变量我们来说明ansible中变量(不包含role中的变量)用法。

    # 2.1 playbook中的变量

    在运行playbook的时候使用--extra-vars来指定变量

    有如下playbook脚本:

    ---
     - hosts: all
       remote_user: root
       gather_facts: no
       tasks:
         - name: test playbook variables
           command: echo {{ test_var }}   # 打印出变量test_var的值。
    
    1
    2
    3
    4
    5
    6
    7

    运行playbook:

    $ ansible-playbook test.yml --extra-vars "test_var=test" -v    
    # 加上-v选项,会显示详细的信息
    
    PLAY [all] ********************************************************************
    
    TASK: [test playbook variables] ***********************************************
    changed: [10.0.102.212] => {"changed": true, "cmd": ["echo", "test"], "delta": "0:00:00.006045", "end": "2019-02-15 23:04:49.789452", "rc": 0, "start": "2019-02-15 23:04:49.783407", "stderr": "", "stdout": "test"}
    changed: [10.0.102.200] => {"changed": true, "cmd": ["echo", "test"], "delta": "0:00:00.005318", "end": "2019-02-15 23:04:52.976471", "rc": 0, "start": "2019-02-15 23:04:52.971153", "stderr": "", "stdout": "test"}
    changed: [10.0.102.162] => {"changed": true, "cmd": ["echo", "test"], "delta": "0:00:00.005082", "end": "2019-02-15 23:04:52.424959", "rc": 0, "start": "2019-02-15 23:04:52.419877", "stderr": "", "stdout": "test"}
    
    PLAY RECAP ********************************************************************
    10.0.102.162               : ok=1    changed=1    unreachable=0    failed=0
    10.0.102.200               : ok=1    changed=1    unreachable=0    failed=0
    10.0.102.212               : ok=1    changed=1    unreachable=0    failed=0
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14

    上面详细信息的标准输出为test,说明变量的值已经传递了。

    # 2.2 playbook中使用vars代码块定义变量

    $ cat test.yml
    ---
     - hosts: all
       remote_user: root
       gather_facts: no
       vars:                  # 在这里使用了vars代码块来定义变量
           test_var: Hello World
       tasks:
         - name: test playbook variables
           command: echo {{ test_var }}
    
    $ ansible-playbook test.yml  -v
    
    PLAY [all] ********************************************************************
    
    TASK: [test playbook variables] ***********************************************
    changed: [10.0.102.162] => {"changed": true, "cmd": ["echo", "Hello", "World"], "delta": "0:00:00.004940", "end": "2019-02-15 23:20:06.541672", "rc": 0, "start": "2019-02-15 23:20:06.536732", "stderr": "", "stdout": "Hello World"}
    changed: [10.0.102.212] => {"changed": true, "cmd": ["echo", "Hello", "World"], "delta": "0:00:00.004843", "end": "2019-02-15 23:20:03.957950", "rc": 0, "start": "2019-02-15 23:20:03.953107", "stderr": "", "stdout": "Hello World"}
    changed: [10.0.102.200] => {"changed": true, "cmd": ["echo", "Hello", "World"], "delta": "0:00:00.004219", "end": "2019-02-15 23:20:07.166900", "rc": 0, "start": "2019-02-15 23:20:07.162681", "stderr": "", "stdout": "Hello World"}
    
    PLAY RECAP ********************************************************************
    10.0.102.162               : ok=1    changed=1    unreachable=0    failed=0
    10.0.102.200               : ok=1    changed=1    unreachable=0    failed=0
    10.0.102.212               : ok=1    changed=1    unreachable=0    failed=0
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24

    # 2.3 使用独立的文件来定义playbook变量

    playbook的内容:

    ---
     - hosts: all
       remote_user: root
       gather_facts: no
       vars_files:       # 这里使用了vars_files来引入变量文件
         - vars.yml
       tasks:
         - name: test playbook variables
           command: echo {{ test_var }}
    
    1
    2
    3
    4
    5
    6
    7
    8
    9

    变量文件的定义:

    $ cat vars.yml
    ---
      test_var: Hello World
    
    1
    2
    3

    执行的结果:

    $ ansible-playbook test.yml  -v
    
    PLAY [all] ********************************************************************
    
    TASK: [test playbook variables] ***********************************************
    changed: [10.0.102.212] => {"changed": true, "cmd": ["echo", "Hello", "World"], "delta": "0:00:00.005198", "end": "2019-02-15 23:23:16.397557", "rc": 0, "start": "2019-02-15 23:23:16.392359", "stderr": "", "stdout": "Hello World"}
    changed: [10.0.102.200] => {"changed": true, "cmd": ["echo", "Hello", "World"], "delta": "0:00:00.004359", "end": "2019-02-15 23:23:19.629804", "rc": 0, "start": "2019-02-15 23:23:19.625445", "stderr": "", "stdout": "Hello World"}
    changed: [10.0.102.162] => {"changed": true, "cmd": ["echo", "Hello", "World"], "delta": "0:00:01.006185", "end": "2019-02-15 23:23:20.039320", "rc": 0, "start": "2019-02-15 23:23:19.033135", "stderr": "", "stdout": "Hello World"}
    
    PLAY RECAP ********************************************************************
    10.0.102.162               : ok=1    changed=1    unreachable=0    failed=0
    10.0.102.200               : ok=1    changed=1    unreachable=0    failed=0
    10.0.102.212               : ok=1    changed=1    unreachable=0    failed=0
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13

    # 2.4 inventory文件中的变量

    在ansible中,inventory文件通常是指ansible的主机和组定义文件hosts。在hosts文件中,变量会被定义在主机名后面或组名的下方。

    为特定的主机定义变量,变量名跟在对应主机的后边。

    inventory文件如下:

    $ cat /etc/ansible/hosts
    [all]
    10.0.102.212 test_var=212
    10.0.102.200 test_var=200
    10.0.102.162 test_var=162
    # 为三个主机定义了同名的变量,但是变量值却不一样。
    
    1
    2
    3
    4
    5
    6

    playbook的内容如下:

    ---
     - hosts: all
       remote_user: root
       gather_facts: no
       tasks:
         - name: test playbook variables
           command: echo {{ test_var }}
    
    1
    2
    3
    4
    5
    6
    7

    执行这个playbook,结果如下(对应的主机显示了各自对应的变量值):

    $ ansible-playbook test.yml -v
    
    PLAY [all] ********************************************************************
    
    TASK: [test playbook variables] ***********************************************
    changed: [10.0.102.212] => {"changed": true, "cmd": ["echo", "212"], "delta": "0:00:00.004399", "end": "2019-02-15 23:31:20.648111", "rc": 0, "start": "2019-02-15 23:31:20.643712", "stderr": "", "stdout": "212"}
    changed: [10.0.102.200] => {"changed": true, "cmd": ["echo", "200"], "delta": "0:00:00.005932", "end": "2019-02-15 23:31:23.873082", "rc": 0, "start": "2019-02-15 23:31:23.867150", "stderr": "", "stdout": "200"}
    changed: [10.0.102.162] => {"changed": true, "cmd": ["echo", "162"], "delta": "0:00:00.006723", "end": "2019-02-15 23:31:23.287861", "rc": 0, "start": "2019-02-15 23:31:23.281138", "stderr": "", "stdout": "162"}
    
    PLAY RECAP ********************************************************************
    10.0.102.162               : ok=1    changed=1    unreachable=0    failed=0
    10.0.102.200               : ok=1    changed=1    unreachable=0    failed=0
    10.0.102.212               : ok=1    changed=1    unreachable=0    failed=0
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13

    给主机组定义变量,作用范围为整个主机组。

    $ cat /etc/ansible/hosts
    [all]
    10.0.102.212
    10.0.102.200
    10.0.102.162
    
    
    [all:vars]                            #给主机组定义变量
    test_var=Hello World
    
    $ ansible-playbook test.yml -v
    
    PLAY [all] ********************************************************************
    
    TASK: [test playbook variables] ***********************************************
    changed: [10.0.102.212] => {"changed": true, "cmd": ["echo", "Hello", "World"], "delta": "0:00:00.003923", "end": "2019-02-15 23:37:29.322158", "rc": 0, "start": "2019-02-15 23:37:29.318235", "stderr": "", "stdout": "Hello World"}
    changed: [10.0.102.200] => {"changed": true, "cmd": ["echo", "Hello", "World"], "delta": "0:00:00.004161", "end": "2019-02-15 23:37:32.548947", "rc": 0, "start": "2019-02-15 23:37:32.544786", "stderr": "", "stdout": "Hello World"}
    changed: [10.0.102.162] => {"changed": true, "cmd": ["echo", "Hello", "World"], "delta": "0:00:00.006090", "end": "2019-02-15 23:37:32.005067", "rc": 0, "start": "2019-02-15 23:37:31.998977", "stderr": "", "stdout": "Hello World"}
    
    PLAY RECAP ********************************************************************
    10.0.102.162               : ok=1    changed=1    unreachable=0    failed=0
    10.0.102.200               : ok=1    changed=1    unreachable=0    failed=0
    10.0.102.212               : ok=1    changed=1    unreachable=0    failed=0
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23

    回想一下,这种方法定义变量虽然简单直观,但是若是变量特别多的情况下,会怎么样?特别是给对应的主机定义变量,若是变量太多,则管理起来会很不方便的,因此引入了主机变量和组变量。

    # 2.5 主机变量和组变量

    inventory文件仍然使用上面的文件!

    在执行ansbile命令时,ansible默认会从/etc/ansible/host_vars/和/etc/amsible/group_vars/两个目录下读取变量定义,如果/etc/ansible下面没有这两个目录,可以直接手动创建,并且可以在这两个目录中创建与hosts(这里是指inventory文件)文件中主机名或组名同名的文件来定义变量。

    先来看主机变量

    $ tree /etc/ansible/
    .
    ├── group_vars
    ├── hosts
    └── host_vars                 # 定义与主机名同名的文件
        ├── 10.0.102.162
        ├── 10.0.102.200
        └── 10.0.102.212
    
    2 directories, 4 files
    
    # 文件中的内容如下:
    $ cat host_vars/10.0.102.162
    ---
    test_var: 162
    $ cat host_vars/10.0.102.200
    ---
      test_var: 200
    $ cat host_vars/10.0.102.212
    ---
      test_var: 212
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21

    playbook的内容如下,执行结果如下:

    $ cat test.yml
    ---
     - hosts: all
       remote_user: root
       gather_facts: no
       tasks:
         - name: test playbook variables
           command: echo {{ test_var }}
    
    $ ansible-playbook test.yml -v
    
    PLAY [all] ********************************************************************
    
    TASK: [test playbook variables] ***********************************************
    changed: [10.0.102.212] => {"changed": true, "cmd": ["echo", "212"], "delta": "0:00:00.003767", "end": "2019-02-15 23:55:58.595282", "rc": 0, "start": "2019-02-15 23:55:58.591515", "stderr": "", "stdout": "212"}
    changed: [10.0.102.162] => {"changed": true, "cmd": ["echo", "162"], "delta": "0:00:00.006254", "end": "2019-02-15 23:56:01.235307", "rc": 0, "start": "2019-02-15 23:56:01.229053", "stderr": "", "stdout": "162"}
    changed: [10.0.102.200] => {"changed": true, "cmd": ["echo", "200"], "delta": "0:00:01.004509", "end": "2019-02-15 23:56:02.775410", "rc": 0, "start": "2019-02-15 23:56:01.770901", "stderr": "", "stdout": "200"}
    
    PLAY RECAP ********************************************************************
    10.0.102.162               : ok=1    changed=1    unreachable=0    failed=0
    10.0.102.200               : ok=1    changed=1    unreachable=0    failed=0
    10.0.102.212               : ok=1    changed=1    unreachable=0    failed=0
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22

    再来说明一下主机组变量!

    创建与组名同名的文件:

    $ tree
    .
    ├── group_vars
    │   └── all               #创建与组名同名的文件
    ├── hosts
    └── host_vars
        ├── 10.0.102.162
        ├── 10.0.102.200
        └── 10.0.102.212
    
    2 directories, 5 files
    
    $ cat group_vars/all
    ---
      test_group_var: from group
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15

    执行结果如下:

    $ cat test.yml
    ---
     - hosts: all
       remote_user: root
       gather_facts: no
       tasks:
         - name: test the host variables
           command: echo {{ test_var }}
    
         - name: test host group variables           #写入测试组变量的task
           command: echo {{ test_group_var }}
    $ ansible-playbook test.yml -v
    
    PLAY [all] ********************************************************************
    
    TASK: [test the host variables] ***********************************************
    changed: [10.0.102.212] => {"changed": true, "cmd": ["echo", "212"], "delta": "0:00:00.004613", "end": "2019-02-15 23:59:23.227722", "rc": 0, "start": "2019-02-15 23:59:23.223109", "stderr": "", "stdout": "212"}
    changed: [10.0.102.200] => {"changed": true, "cmd": ["echo", "200"], "delta": "0:00:00.006490", "end": "2019-02-15 23:59:26.422682", "rc": 0, "start": "2019-02-15 23:59:26.416192", "stderr": "", "stdout": "200"}
    changed: [10.0.102.162] => {"changed": true, "cmd": ["echo", "162"], "delta": "0:00:00.004709", "end": "2019-02-15 23:59:25.812786", "rc": 0, "start": "2019-02-15 23:59:25.808077", "stderr": "", "stdout": "162"}
    
    TASK: [test host group variables] *********************************************
    changed: [10.0.102.212] => {"changed": true, "cmd": ["echo", "from", "group"], "delta": "0:00:00.003759", "end": "2019-02-15 23:59:23.519180", "rc": 0, "start": "2019-02-15 23:59:23.515421", "stderr": "", "stdout": "from group"}
    changed: [10.0.102.162] => {"changed": true, "cmd": ["echo", "from", "group"], "delta": "0:00:00.003748", "end": "2019-02-15 23:59:26.109337", "rc": 0, "start": "2019-02-15 23:59:26.105589", "stderr": "", "stdout": "from group"}
    changed: [10.0.102.200] => {"changed": true, "cmd": ["echo", "from", "group"], "delta": "0:00:00.004339", "end": "2019-02-15 23:59:26.724525", "rc": 0, "start": "2019-02-15 23:59:26.720186", "stderr": "", "stdout": "from group"}
    
    PLAY RECAP ********************************************************************
    10.0.102.162               : ok=2    changed=2    unreachable=0    failed=0
    10.0.102.200               : ok=2    changed=2    unreachable=0    failed=0
    10.0.102.212               : ok=2    changed=2    unreachable=0    failed=0
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29

    # 2.6 巧用主机变量和组变量

    有时候在执行ansbile任务时,可能需要从一台远程主机上获取另一台远程主机的变量信息,这时候可以使用hostvars变量,这个变量包含了指定主机上所定义的所有变量。

    譬如,若是想获取host1上变量admin_user的内容,在任意主机上直接上使用下面代码即可。

    {{  hostvars['host1']['admin_user']}}
    
    1

    ansible提供了一些非常有用的内置变量,几个常用的如下:

    • grorps:包含了所有hosts文件里的主机组的一个列表。
    • group_names: 包含了当前主机所在的所有主机组名的一个列表。
    • inventory_hostname: 通过hosts文件定义的主机名。(与ansible_home意义不同)
    • inventory_hostname_short:变量inventory_hostname的第一部分。譬如inventory_hostname的值为books.ansible.com,那么inventory_hostname_short的值就是books。
    • play_hosts: 将执行当前任务的所有主机

    # 2.7 注册变量

    注册变量,其实就是将操作结果,包括标准输出和标准错误输出,保存到变量中,然后再根据这个变量的内容来决定下一步的操作,在这个过程中用来保存操作结果的变量就叫注册变量。

    ---
     - hosts: all
       remote_user: root
       gather_facts: no
       tasks:
         - name: test the register variables
           shell: uptime
           register: results     # 使用关键字register声明注册变量,上面uptime命令产生的结果,存入到results中。结果是字典形式。
    
         - name: print the register result
           debug: msg="{{ results.stdout }}"   # 使用debug模块,打印出上面命令的输出结果。
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11

    上面的playbook执行结果如下:

    $ ansible-playbook test.yml
    
    PLAY [all] ********************************************************************
    
    TASK: [test the register variables] *******************************************
    changed: [10.0.102.212]
    changed: [10.0.102.200]
    changed: [10.0.102.162]
    
    TASK: [print the register result] *********************************************
    ok: [10.0.102.212] => {
        "msg": " 00:18:01 up 3 days,  2:56,  3 users,  load average: 0.02, 0.03, 0.05"          #msg的结果就是注册变量的标准输出
    }
    ok: [10.0.102.200] => {
        "msg": " 00:18:04 up 4 days,  7:45,  3 users,  load average: 0.03, 0.06, 0.05"
    }
    ok: [10.0.102.162] => {
        "msg": " 00:18:04 up 4 days,  7:45,  3 users,  load average: 0.01, 0.02, 0.05"
    }
    
    PLAY RECAP ********************************************************************
    10.0.102.162               : ok=2    changed=1    unreachable=0    failed=0
    10.0.102.200               : ok=2    changed=1    unreachable=0    failed=0
    10.0.102.212               : ok=2    changed=1    unreachable=0    failed=0
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24

    一个注册变量通常会有以下4个属性:

    • changed:任务是否对远程主机造成的变更。
    • delta:任务运行所用的时间。
    • stdout:正常的输出信息。
    • stderr:错误信息。

    # 三、高阶变量

    对于普通变量,在ansible命令行设定的,在hosts文件中定义的,或者在playbook中定义的等,这些都是普通变量,在引用时,可以使用使用的形式。ansible是用python语言写的,因此也支持一种叫做列表的变量,形式如下:

    ---
     - hosts: all
       remote_user: root
       gather_facts: no
       vars:
          var_list:     # 注意形式,定义了var_list列表,取值方法和列表取值一样,不推荐使用jinja2的方法取值。
              - one
              - two
              - three
       tasks:
         - name: test the list variables
           shell: echo {{ var_list[0] }}   # 取列表中的第一个字,也就是one
           register: results
    
         - name: print the register result
           debug: msg="{{ results.stdout }}"
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16

    执行结果如下:

    $ ansible-playbook test.yml
    
    PLAY [all] ********************************************************************
    
    TASK: [test the list variables] ***********************************************
    changed: [10.0.102.212]
    changed: [10.0.102.200]
    changed: [10.0.102.162]
    
    TASK: [print the register result] *********************************************
    ok: [10.0.102.212] => {
        "msg": "one"
    }
    ok: [10.0.102.200] => {
        "msg": "one"
    }
    ok: [10.0.102.162] => {
        "msg": "one"
    }
    
    PLAY RECAP ********************************************************************
    10.0.102.162               : ok=2    changed=1    unreachable=0    failed=0
    10.0.102.200               : ok=2    changed=1    unreachable=0    failed=0
    10.0.102.212               : ok=2    changed=1    unreachable=0    failed=0
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24

    # 3.1 fasts变量信息

    在上面的测试中,我们的playbook都执行了一条命令叫gater_facts:no,加入了这条命令后,playbook脚本的执行速度会快很多,这是因为默认情况下,ansible是会手机远程服务器的主机信息,这些信息包含了服务器的一些基本设置。

    GATHERING FACTS ***************************************************************
    ok: [10.0.102.200]
    ok: [10.0.102.212]
    ok: [10.0.102.162]
    
    1
    2
    3
    4

    收集的主机信息可以使用setup模块查看,一个主机的收集信息如下:

    ansible 10.0.102.162 -m setup
    10.0.102.162 | success >> {
        "ansible_facts": {
            "ansible_all_ipv4_addresses": [
                "10.0.102.162"
            ],
            "ansible_all_ipv6_addresses": [
                "fe80::1392:ecd3:5adf:c3ae"
            ],
            "ansible_architecture": "x86_64",
            "ansible_bios_date": "04/01/2014",
            "ansible_bios_version": "1.9.1-5.el7.centos",
            "ansible_cmdline": {
                "BOOT_IMAGE": "/vmlinuz-3.10.0-514.el7.x86_64",
                "LANG": "en_US.UTF-8",
                "crashkernel": "auto",
                "quiet": true,
                "rd.lvm.lv": "cl/swap",
                "rhgb": true,
                "ro": true,
                "root": "/dev/mapper/cl-root"
            },
            "ansible_date_time": {
                "date": "2019-02-16",
                "day": "16",
                "epoch": "1550248590",
                "hour": "00",
                "iso8601": "2019-02-15T16:36:30Z",
                "iso8601_micro": "2019-02-15T16:36:30.311222Z",
                "minute": "36",
                "month": "02",
                "second": "30",
                "time": "00:36:30",
                "tz": "CST",
                "tz_offset": "+0800",
                "weekday": "Saturday",
                "year": "2019"
            },
            "ansible_default_ipv4": {
                "address": "10.0.102.162",
                "alias": "eth0",
                "gateway": "10.0.100.1",
                "interface": "eth0",
                "macaddress": "fa:0a:e3:54:a6:00",
                "mtu": 1500,
                "netmask": "255.255.252.0",
                "network": "10.0.100.0",
                "type": "ether"
            },
            "ansible_default_ipv6": {},
            "ansible_devices": {
                "sr0": {
                    "holders": [],
                    "host": "IDE interface: Intel Corporation 82371SB PIIX3 IDE [Natoma/Triton II]",
                    "model": "QEMU DVD-ROM",
                    "partitions": {},
                    "removable": "1",
                    "rotational": "1",
                    "scheduler_mode": "cfq",
                    "sectors": "2097151",
                    "sectorsize": "512",
                    "size": "1024.00 MB",
                    "support_discard": "0",
                    "vendor": "QEMU"
                },
                "vda": {
                    "holders": [],
                    "host": "SCSI storage controller: Red Hat, Inc Virtio block device",
                    "model": null,
                    "partitions": {
                        "vda1": {
                            "sectors": "2097152",
                            "sectorsize": 512,
                            "size": "1.00 GB",
                            "start": "2048"
                        },
                        "vda2": {
                            "sectors": "81786880",
                            "sectorsize": 512,
                            "size": "39.00 GB",
                            "start": "2099200"
                        }
                    },
                    "removable": "0",
                    "rotational": "1",
                    "scheduler_mode": "",
                    "sectors": "83886080",
                    "sectorsize": "512",
                    "size": "40.00 GB",
                    "support_discard": "0",
                    "vendor": "0x1af4"
                }
            },
            "ansible_distribution": "CentOS",
            "ansible_distribution_major_version": "7",
            "ansible_distribution_release": "Core",
            "ansible_distribution_version": "7.3.1611",
            "ansible_domain": "",
            "ansible_env": {
                "HOME": "/root",
                "LANG": "en_US.UTF-8",
                "LC_CTYPE": "en_US.UTF-8",
                "LESSOPEN": "||/usr/bin/lesspipe.sh %s",
                "LOGNAME": "root",
                "LS_COLORS": "rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:mi=01;05;37;41:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arc=01;31:*.arj=01;31:*.taz=01;31:*.lha=01;31:*.lz4=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.tzo=01;31:*.t7z=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.lrz=01;31:*.lz=01;31:*.lzo=01;31:*.xz=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.war=01;31:*.ear=01;31:*.sar=01;31:*.rar=01;31:*.alz=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.cab=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.webm=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.axv=01;35:*.anx=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=01;36:*.au=01;36:*.flac=01;36:*.mid=01;36:*.midi=01;36:*.mka=01;36:*.mp3=01;36:*.mpc=01;36:*.ogg=01;36:*.ra=01;36:*.wav=01;36:*.axa=01;36:*.oga=01;36:*.spx=01;36:*.xspf=01;36:",
                "MAIL": "/var/mail/root",
                "PATH": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin",
                "PWD": "/root",
                "SELINUX_LEVEL_REQUESTED": "",
                "SELINUX_ROLE_REQUESTED": "",
                "SELINUX_USE_CURRENT_RANGE": "",
                "SHELL": "/bin/bash",
                "SHLVL": "2",
                "SSH_CLIENT": "10.0.102.204 4242 22",
                "SSH_CONNECTION": "10.0.102.204 4242 10.0.102.162 22",
                "SSH_TTY": "/dev/pts/1",
                "TERM": "xterm",
                "USER": "root",
                "XDG_RUNTIME_DIR": "/run/user/0",
                "XDG_SESSION_ID": "168",
                "_": "/usr/bin/python"
            },
            "ansible_eth0": {
                "active": true,
                "device": "eth0",
                "ipv4": {
                    "address": "10.0.102.162",
                    "netmask": "255.255.252.0",
                    "network": "10.0.100.0"
                },
                "ipv6": [
                    {
                        "address": "fe80::1392:ecd3:5adf:c3ae",
                        "prefix": "64",
                        "scope": "link"
                    }
                ],
                "macaddress": "fa:0a:e3:54:a6:00",
                "module": "virtio_net",
                "mtu": 1500,
                "promisc": false,
                "type": "ether"
            },
            "ansible_form_factor": "Other",
            "ansible_fqdn": "docker4",
            "ansible_hostname": "docker4",
            "ansible_interfaces": [
                "lo",
                "eth0"
            ],
            "ansible_kernel": "3.10.0-514.el7.x86_64",
            "ansible_lo": {
                "active": true,
                "device": "lo",
                "ipv4": {
                    "address": "127.0.0.1",
                    "netmask": "255.0.0.0",
                    "network": "127.0.0.0"
                },
                "ipv6": [
                    {
                        "address": "::1",
                        "prefix": "128",
                        "scope": "host"
                    }
                ],
                "mtu": 65536,
                "promisc": false,
                "type": "loopback"
            },
            "ansible_machine": "x86_64",
            "ansible_memfree_mb": 881,
            "ansible_memtotal_mb": 1839,
            "ansible_mounts": [
                {
                    "device": "/dev/mapper/cl-root",
                    "fstype": "xfs",
                    "mount": "/",
                    "options": "rw,seclabel,relatime,attr2,inode64,noquota",
                    "size_available": 34615087104,
                    "size_total": 39700664320
                },
                {
                    "device": "/dev/vda1",
                    "fstype": "xfs",
                    "mount": "/boot",
                    "options": "rw,seclabel,relatime,attr2,inode64,noquota",
                    "size_available": 918556672,
                    "size_total": 1063256064
                }
            ],
            "ansible_nodename": "docker4",
            "ansible_os_family": "RedHat",
            "ansible_pkg_mgr": "yum",
            "ansible_processor": [
                "QEMU Virtual CPU version 2.5+",
                "QEMU Virtual CPU version 2.5+"
            ],
            "ansible_processor_cores": 2,
            "ansible_processor_count": 1,
            "ansible_processor_threads_per_core": 1,
            "ansible_processor_vcpus": 2,
            "ansible_product_name": "KVM",
            "ansible_product_serial": "NA",
            "ansible_product_uuid": "E5E1D5E6-1A4D-4E0D-98C3-B8AD422B10CC",
            "ansible_product_version": "RHEL 7.3.0 PC (i440FX + PIIX, 1996)",
            "ansible_python_version": "2.7.5",
            "ansible_selinux": {
                "config_mode": "enforcing",
                "mode": "enforcing",
                "policyvers": 28,
                "status": "enabled",
                "type": "targeted"
            },
            "ansible_ssh_host_key_ecdsa_public": "AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEp5iF/lAqB9Q9FNKfnsi3mLJSVvvooVhRRcuGTBHEJs+TaM36oBaIr764IX1zdn2sWFLdYgmcuaAeiPu3fK+UU=",
            "ansible_ssh_host_key_rsa_public": "AAAAB3NzaC1yc2EAAAADAQABAAABAQC6yHI2+V64EMW3jDISBrzKmWurP7uF4IqemJgowpqC3mVlFsPOSqerDoJN9hE34fViXcbLUj9wIi0kc3QzxxNwTefwJCdPSL17ns9eIEDKJqrHswts7OXYC1948bdyhyGnaW57BEfVUJ+Vt8OI1JSKkKsi3aCumaZDz9tNGCVYiqW4PMUQFaT/yEnPqKhSp8mDX/SL/unpVsctB0w37o38ZVApKPaNkHW25uiwroStLGqY4VgoZHTqHUdvqk4EZQOD0+JmBcYKVj2ABBl1sMiH8mmrc2W2Gi0gJx31Ky/t5SWQtXTdMRB3D7N9yRd1pPcnh0zebS/OPnX4G5UWX/aP",
            "ansible_swapfree_mb": 0,
            "ansible_swaptotal_mb": 0,
            "ansible_system": "Linux",
            "ansible_system_vendor": "Red Hat",
            "ansible_user_id": "root",
            "ansible_userspace_architecture": "x86_64",
            "ansible_userspace_bits": "64",
            "ansible_virtualization_role": "guest",
            "ansible_virtualization_type": "kvm",
            "module_setup": true
        },
        "changed": false
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229

    在实际应用中,运用的比较多的facts变量有ansible_os_family,ansible_hostname等,这些变量通常会被拿来作为when条件语句的判断条件,来决定下一步的操作。一个简单的实例:

    ---
     - hosts: all
       remote_user: root
       tasks:
         - name: test the list variables
           shell: echo {{ ansible_os_family }}
           register: results
    
         - name: print the register result
           debug: msg="{{ results.stdout }}"
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10

    执行结果如下:

    ansible-playbook test.yml
    
    PLAY [all] ********************************************************************
    
    GATHERING FACTS ***************************************************************
    ok: [10.0.102.162]
    ok: [10.0.102.212]
    ok: [10.0.102.200]
    
    TASK: [test the list variables] ***********************************************
    changed: [10.0.102.162]
    changed: [10.0.102.212]
    changed: [10.0.102.200]
    
    TASK: [print the register result] *********************************************
    ok: [10.0.102.212] => {
        "msg": "RedHat"                   #对应变量的结果
    }
    ok: [10.0.102.200] => {
        "msg": "RedHat"
    }
    ok: [10.0.102.162] => {
        "msg": "RedHat"
    }
    
    PLAY RECAP ********************************************************************
    10.0.102.162               : ok=3    changed=1    unreachable=0    failed=0
    10.0.102.200               : ok=3    changed=1    unreachable=0    failed=0
    10.0.102.212               : ok=3    changed=1    unreachable=0    failed=0
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29

    # 3.2 本地facts变量

    我们可以自己定义facts变量,把这个变量写入一个以.fact结尾的文件中,这个文件可以是json文件或ini文件,或者是一个可以返回json代码的可执行文件。然后将其放在远程主机的/etc/ansible/facts.d文件夹中,ansible在执行的任务时会自动到这个文件夹中读取变量的信息。

    在远程主机上做如下操作:

    # 自定义fact信息
    $ mkdir -p /etc/ansible/facts.d && cd /etc/ansible/facts.d
    $ cat test.fact
    [test_fact]
    admin=hongkong
    
    1
    2
    3
    4
    5

    然后再ansible主机上获取自定义的信息。

    $ ansible 10.0.102.162 -m setup -a "filter=ansible_local"
    10.0.102.162 | success >> {
        "ansible_facts": {
            "ansible_local": {
                "test": {
                    "test_fact": {
                        "admin": "hongkong"
                    }
                }
            }
        },
        "changed": false
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13

    # 四、if/when/while流程控制语句

    条件判断在ansible任务中的使用频率非常高。我们可以根据一些条件的不一样执行不同的task。

    # 4.1 when条件判断

    很多任务只有在特定条件下才能执行,这就是when语句发挥作用的地方。

    一个简单的实例,关闭掉ip地址为10.0.102.162服务器上的mysql服务,如下:

    [root@test2 playbook]# cat test.yml
    ---
     - hosts: all
       remote_user: root
       tasks:
         - name: shut down the db server
           service: name=mysqld state=stopped
           when: ansible_eth0.ipv4.address  == "10.0.102.162"  # 这里使用了when条件语句
    
    1
    2
    3
    4
    5
    6
    7
    8

    执行的结果如下:

    $ ansible-playbook test.yml
    
    PLAY [all] ********************************************************************
    
    GATHERING FACTS ***************************************************************
    ok: [10.0.102.212]
    ok: [10.0.102.200]
    ok: [10.0.102.162]
    
    TASK: [shut down the db server] ***********************************************
    skipping: [10.0.102.200]
    skipping: [10.0.102.212]
    changed: [10.0.102.162]                      #162的服务状态已经改变
    
    PLAY RECAP ********************************************************************
    10.0.102.162               : ok=2    changed=1    unreachable=0    failed=0
    10.0.102.200               : ok=1    changed=0    unreachable=0    failed=0
    10.0.102.212               : ok=1    changed=0    unreachable=0    failed=0
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18

    这个就是when条件语句的用法很简单。需要注意when语句的作用于paly的作用时间,当when的条件满足时,然后才会执行play中的任务。ansible还提供了另外两个与when相关的语句changed_when和failed_when条件判断。

    # 五、任务间的流程控制

    # 5.1 任务委托

    默认情况下,ansible所有任务都是在我们指定的机器上面运行的,当在一个独立的集群环境配置时,这并没有什么问题。而在有些情况下,比如给某台服务器发送通知或者向监控服务器中添加被监控的主机,这个时候任务就需要在特定的主机上运行,而非一开始指定的所有主机,此时就需要ansible的委托任务。

    使用delegate_to关键字可以配置任务在指定的服务器上执行,而其他任务还是在hosts关键字配置的所有机器上执行,当到了这个关键字所在的任务时,就使用委托的机器运行。

    查看MySQL是否在运行状态,因此在检查之前首先关掉162上的mysql服务。(为了方便查看状态)

    ---
     - hosts: all
       remote_user: root
       tasks:
         - name: stop the db server
           service: name=mysqld state=stopped
           delegate_to: 10.0.102.162       # 这里使用了委托,仅关闭162这台服务器上,这个play仅在162这台服务器上执行。
    
         - name: check mysql status
           service: name=mysqld state=running
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10

    这里委托是在指定的机器上执行,若是想在本地服务器上执行,可以把ip地址换为127.0.0.1即可。也可以使用local_action方法。

    ---
     - hosts: all
       remote_user: root
       tasks:
         - name: create the test file
           local_action: shell touch test1111 # 在本地创建一个测试文件
    
    
         - name: check mysql status
           service: name=mysqld state=running
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10

    结果如下:

    $ ansible-playbook test.yml
    
    PLAY [all] ********************************************************************
    
    GATHERING FACTS ***************************************************************
    ok: [10.0.102.212]
    ok: [10.0.102.200]
    ok: [10.0.102.162]
    
    TASK: [create the test file] **************************************************
    changed: [10.0.102.212 -> 127.0.0.1]
    changed: [10.0.102.200 -> 127.0.0.1]
    changed: [10.0.102.162 -> 127.0.0.1]
    
    TASK: [check mysql status] ****************************************************
    ok: [10.0.102.200]
    ok: [10.0.102.212]
    ok: [10.0.102.162]
    
    PLAY RECAP ********************************************************************
    10.0.102.162               : ok=3    changed=1    unreachable=0    failed=0
    10.0.102.200               : ok=3    changed=1    unreachable=0    failed=0
    10.0.102.212               : ok=3    changed=1    unreachable=0    failed=0
    
    $ ls                     # 默认会在当前目录创建对应的文件
    test1111  test.yml  vars.yml
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26

    # 5.2 任务暂停

    有些情况下,一些任务的运行需要等待一些状态的恢复,比如某一台主机或者应用刚刚重启,我们需要等待它上面的某个端口开启,此时我们就不得不将正在运行的任务暂停,直到其状态满足我们的需求。

    下一个实例:

    - name: wait for webserver to start
       local_action:
            module: wait_for
            host: webserver1
            port: 80
            delay: 10
            timeout: 300
            state: startted
    # 这个实例中,这个任务将会每10s检查一次主机webserver1上面的80端口是否开启,如果超过了300s则失败
    
    1
    2
    3
    4
    5
    6
    7
    8
    9

    # 5.3 交互式提示

    在少数情况下,ansible任务运行的过程中需要用户输入一些数据,这些数据要么比较秘密不方便,或者数据是动态的,不同的用户有不同的需求,比如输入用户自己的账户和密码或者输入不同的版本号会触发不同的后续操作等。ansible的vars_prompt关键字就是用来处理上述这种与用户交互的情况的。下面是一个简单的实例。

    ---
     - hosts: all
       remote_user: root
       vars_prompt:
          - name: share_user
            prompt: "what is your network username?"
            private: no
    
          - name: share_pass
            prompt: "what is your network password"
            private: no
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11

    然后执行上面的playbook,因为我们只是测试,只需要在一台机器上执行,因此加入了--limit参数。

    $ ansible-playbook test.yml --limit 10.0.102.162
    what is your network username?: test        # 需要手动交互输入
    what is your network password: 123456       # 手动输入
    
    PLAY [all] ********************************************************************
    
    GATHERING FACTS ***************************************************************
    ok: [10.0.102.162]
    
    PLAY RECAP ********************************************************************
    10.0.102.162               : ok=1    changed=0    unreachable=0    failed=0
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11

    手动输入的变量值,在后面的play中仍然可以用的形式调用。

    关键字vars_prompt几个常用的选项总结如下:

    • private:默认值为yes,表示用户输入的值在命令行不可见;将值设为no时,用户输入可见。
    • default:为变量设置默认值,以节省用户输入时间。
    • confirm:特别适合输入密码的情况,如果将其设置为yes,则会要求用户输入两次,以增加输入的安全性。

    # 六、tags标签

    默认情况下,ansible在执行一个playbook时,会执行playbook中定义的所有任务。ansible的标签功能可以给角色,文件,单独的任务甚至整个playbook打上标签,然后利用这些标签来指定要运行playbook中的个别任务,或不执行指定的任务,并且它的语法非常简单。

    通过一段代码来说明tags的用法:

    ---
    # 可以给整个playbook的所有任务打一个标签。
      - hosts: all
        tags: deploy
        roles:
         # 给角色打的标签将会应用与角色下所有的任务。
           - {role: tomcat, tags : ["tomcat", "app"]}        # 一个对象添加多个tag的写法之一
        tasks:
           - name: Notify on completion
             local_action:
                module: osx_say
                msg: "{{inventory_hostname}} is finished"
                voice: Zarvox
             tags:      # 一个对象添加多个tag写法之二
                - notifications
                - say
           - include: foo.yml
             tags: foo
    
    # 缩进可能不太对
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20

    将上述代码保存,可以通过以下命令来只执行Notify on completion任务。

    $ ansible-playbook test.yml --tags "say"
    
    1

    如果想忽略掉某个任务,可以使用--skip-tags关键字指定。

    # 七、Block块

    ansible从2.0.0版本开始引入了块功能。块功能可以将任务进行分组,并且可以在块级别上应用任务变量。同时,块功能还可以使用类似于其他编程语言处理异常那样的方法,来处理块内部的任务异常。

    ---
     - hosts: all
       remote_user: root
    
       tasks:
         - block:
              - yum: name=httpd state=present
              - service: name=httpd state=started enabled=no
           when:  ansible_eth0.ipv4.address  == "10.0.102.162"
    
         - block:
              - yum: name=nginx state=present
              - service: name=nginx state=started enabled=no
           when:  ansible_eth0.ipv4.address  == "10.0.102.200"
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14

    运行结果如下:

    $ ansible-playbook -i hosts test.yml
    
    PLAY [all] **************************************************************************************************************************************************************************************
    
    TASK [Gathering Facts] **************************************************************************************************************************************************************************
    ok: [10.0.102.162]
    ok: [10.0.102.200]
    
    TASK [yum] **************************************************************************************************************************************************************************************
    skipping: [10.0.102.200]          # 因为在inventory文件中注释了这一台服务器,因此这里忽略了。
    ok: [10.0.102.162]
    
    TASK [service] **********************************************************************************************************************************************************************************
    skipping: [10.0.102.200]
    changed: [10.0.102.162]
    
    TASK [yum] **************************************************************************************************************************************************************************************
    skipping: [10.0.102.162]
    ok: [10.0.102.200]
    
    TASK [service] **********************************************************************************************************************************************************************************
    skipping: [10.0.102.162]
    changed: [10.0.102.200]
    
    PLAY RECAP **************************************************************************************************************************************************************************************
    10.0.102.162               : ok=3    changed=1    unreachable=0    failed=0
    10.0.102.200               : ok=3    changed=1    unreachable=0    failed=0
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27

    上面的playbook和之前的并没有什么不同,只是假如了block之后,代码更容易查看。

    块功能可以用来处理任务的异常。比如一个ansible任务时监控一个并不太重要的应用,这个应用的正常运行与否对后续的任务并不产生影响,这时候我们就可以通过块功能来处理这个应用的报错。如下代码:

    tasks:
       - block:
            - name: shell script to connect the app ti a mointoring service.
              script: mointoring-connect.sh
              rescue:
                 - name:只有脚本报错时才执行
             debug:msg="There was an error in the block"
              always:
                 - name: 无论结果如何都执行
                   debug: msg="This always executes"
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10

    当块中任意任务出错时,rescue关键字对应的代码块就会被执行,而always关键字对应的代码块无论如何都会被执行。

    *************** 当你发现自己的才华撑不起野心时,就请安静下来学习吧!***************

    原文链接:https://www.cnblogs.com/lvzhenjiang/p/14198755.html

    微信 支付宝
    #ansible
    上次更新: 2024/10/22, 18:10:01

    ← ansible中template简单使用 ansible-playbook编排使用tips→

    最近更新
    01
    不花一分钱从0到1建站教程
    04-22
    02
    批量拿取多台服务器的日志文件
    04-21
    03
    高德MCP智能体搞定旅游计划
    04-19
    更多文章>
    Theme by Vdoing | Copyright © 2019-2025 | 点击查看十年之约 | 鄂ICP备2024072800号
    • 跟随系统
    • 浅色模式
    • 深色模式
    • 阅读模式