• Ansible之Playbook的任务控制


    一)Ansible 任务控制基本介绍

    这⾥主要来介绍PlayBook中的任务控制。
    任务控制类似于编程语⾔中的if … 、for … 等逻辑控制语句。
    这⾥我们给出⼀个实际场景应⽤案例去说明在PlayBook中,任务控制如何应⽤。
    在下⾯的PlayBook中,我们创建了 tomcat、www 和 mysql 三个⽤户。 安装了Nginx 软件包、并同时更新了 Nginx 主配置⽂件和虚拟主机配置⽂件,最后让Nginx 服务处于启动状态。
    整个PlayBook从语法上没有任何问题,但从逻辑和写法上仍然有⼀些地⽅需要我们去注意及优化:

    1. Nginx启动逻辑⽋缺考虑。若Nginx的配置⽂件语法错误则会导致启动Nginx失败,以⾄于PlayBook执⾏失败。
    2. 批量创建⽤户,通过指令的罗列过于死板。如果再创建若⼲个⽤户,将难以收场。
    ---
    - name: task control playbook example
      hosts: webservers
      tasks:
      - name: create tomcat user
        user: name=tomcat state=present
        name: create www user
        user: name=www state=present
      - name: create mysql user
        user: name=mysql state=present
      - name: yum nginx webserver
        yum: name=nginx state=present
      - name: update nginx main config
        copy: src=nginx.conf dest=/etc/nginx/
      - name: add virtualhost config
        copy: src=www.qfedu.com.conf
              dest=/etc/nginx/conf.d/
      - name: start nginx server
        service: name=nginx state=started
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    二)条件判断

    解决第一个问题:Nginx启动逻辑⽋缺考虑。 若Nginx的配置⽂件语法错误则会导致启动Nginx失败,以⾄于PlayBook执⾏失败。
    如果我们能够在启动之前去对Nginx的配置⽂件语法做正确性的校验,只有当校验通过的时候我们才去启动或者重启Nginx;否则则跳过启动Nginx的过程。这样就会避免Nginx 配置⽂件语法问题⽽导致的⽆法启动Nginx的⻛险。
    nginx语法校验:

    - name: check nginx syntax
      shell: /usr/sbin/nginx -t
    
    • 1
    • 2

    那如何将Nginx语法检查的TASK同Nginx启动的TASK关联起来呢?
    如果我们能够获得语法检查的TASK的结果,根据这个结果去判断“启动NGINX的TASK”是否执⾏,这将是⼀个很好的⽅案。 如何和获取到语法检查TASK的结果呢? 此时就可以使⽤之前学到的 Ansible中的注册变量:
    获取Task任务结果:

    - name: check nginx syntax
      shell: /usr/sbin/nginx -t
      register: nginxsyntax
    
    • 1
    • 2
    • 3

    此时有可能还有疑问,获取到任务结果后,但是结果⾥⾯的内容是个什么样⼦, 我该根据内容在后续的PlayBook中怎样使用
    通过debug模块去确认返回结果的数据结构:

    - name: print nginx syntax result
      debug: var=nginxsyntax
    
    • 1
    • 2

    通过debug模块,打印出来返回结果。那么在变量nginxsyntax的rc为0时语法校验正确。
    通过条件判断(when)指令去使用语法校验的结果:

    - name: check nginx syntax
      shell: /usr/sbin/nginx -t
      register: nginxsyntax
    - name: print nginx syntax
      debug: var=nginxsyntax
     
    - name: start nginx server
      service: name=nginx state=started
      when: nginxsyntax.rc == 0
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    改进后的PlayBook:

    ---
    - name: task control playbook example
      hosts: webservers
      gather_facts: no
      tasks:
      - name: create tomcat user
        user: name=tomcat state=present
      - name: create www user
        user: name=www state=present
      - name: create mysql user
        user: name=mysql state=present
      - name: yum nginx webserver
        yum: name=nginx state=present
      - name: update nginx main config
        copy: src=nginx.conf dest=/etc/nginx/
      - name: add virtualhost config
        copy: src=www.qfedu.com.conf
              dest=/etc/nginx/conf.d/
      - name: check nginx syntax
        shell: /usr/sbin/nginx -t
        register: nginxsyntax
      - name: print nginx syntax
        debug: var=nginxsyntax
     
      - name: start nginx server
        service: name=nginx state=started
        when: nginxsyntax.rc == 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

    以上的逻辑,只要语法检查通过都会去执⾏ "start nginx server"这个TASK。 在这个问题的解决⾥,我们学习了when 条件判断和注册变量的结合使⽤。学习了when条件判断中是可以⽀持复杂逻辑的。⽐如现在⽤到的逻辑运算符 and。
    另外 when ⽀持如下运算符:

    ==
    !=
    > >=
    < <=
    is defined
    is not defined
    true
    false
    #⽀持逻辑运算符: 
    and or
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    三)循环控制

    解决第二个问题:批量创建⽤户,通过指令的罗列过于死板。如果再创建若⼲个⽤户,将难以收场。
    那么如果在创建⽤户时,抛开PlayBook的实现不说, 单纯的使⽤shell去批量的创建⼀些⽤户。通常会怎么写呢?

    #! /bin/bash
    createuser="tomcat mysql www"
    for i in `echo $createuser`
    do
     useradd $i
    done
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    那么如果PlayBook中也存在这样的循环控制,我们也可以像写shell⼀样简单的去完成多⽤户创建⼯作。
    在PlayBook中使⽤with_items 去实现循环控制,且循环时的中间变量(上⾯shell循环中的 $i 变量)只能是关键字 item ,⽽不能随意⾃定义。
    在上⾯的基础上,改进的PlayBook
    在这⾥使⽤定义了剧本变量 createuser(⼀个列表) ,然后通过with_items 循环遍历变量这个变量来达到创建⽤户的⽬的。

    - name: variable playbook example
      hosts: webservers
      gather_facts: no
      vars:
       createuser:
        - tomcat
        - www
        - mysql
      tasks:
       - name: create user
         user: name={{ item }} state=present
         with_items: "{{ createuser }}"
       - name: yum nginx webserver
         yum: name=nginx state=present
       - name: update nginx main config
         copy: src=nginx.conf dest=/etc/nginx/
       - name: add virtualhost config
         copy: src=www.qfedu.com.conf
               dest=/etc/nginx/conf.d/
       - name: check nginx syntax
         shell: /usr/sbin/nginx -t
         register: nginxsyntax
     
       - name: print nginx syntax
         debug: var=nginxsyntax
       - name: start nginx server
         service: name=nginx state=started
         when: nginxsyntax.rc == 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

    解决了以上问题,整个PlayBook已经有了很⼤的改进。
    在这里给大家一个关于遍历的新版本的循环playbook实验:

    - name: loop item
      hosts: all
      gather_facts: no
      vars:
        some_list:
         - "a"
         - "b"
         - "c"
        num_list:
         - 1
         - 2
         - 3
         - 5
     tasks:
     - name: show item
       debug:
         var: "{{ item }}"
       loop: "{{ some_list }}"
    - name: show item when item > 3
      debug:
       var: "{{ item }}"
      loop: "{{ num_list }}"
      when: item > 3
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    image.png

    四)Tags属性

    考虑这样⼀个情况:
    若更新了Nginx 的配置⽂件后,我们需要通过PlayBook将新的配置发布到⽣产服务器上,然后再重新加载我们的Nginx 服务。但以现在的PlayBook来说,每次更改Nginx 配置⽂件后虽然可以通过它发布到⽣产,但整个PlayBook都要执⾏⼀次,这样⽆形中扩⼤了变更范围和
    变更⻛险。
    Tags 属性就可以解决这个问题。
    我们可以通过Play中的tags 属性,去解决⽬前PlayBook变更⽽导致的扩⼤变更范围和变更⻛险的问题。
    在改进的PlayBook中,针对⽂件发布TASK 任务:
    “update nginx main config" 和 “add virtualhost config”。
    新增了属性 tags ,属性值为updateconfig。
    新增"reload nginx server" TASK任务。当配置⽂件更新后,去reload Nginx 服务。
    判断⼀个⽂件是否存在使⽤ stat 模块:

    - name: check nginx running
      stat: path=/var/run/nginx.pid
     register: nginxrunning
    
    • 1
    • 2
    • 3

    观察结果,会发现 nginxrunning.stat.exists 的值是 true 就表示启动状态,是 false 就是关闭状态。
    接下来下来就可以依据这个结果,来决定是否重新加载 Nginx 服务。
    改进后的Playbook:

    - name: tags playbook example
      hosts: webservers
      gather_facts: no
      vars:
       createuser:
       - tomcat
       - www
       - mysql
      tasks:
      - name: create user
        user: name={{ item }} state=present
        with_items: "{{ createuser }}"
      - name: yum nginx webserver
        yum: name=nginx state=present
      - name: update nginx main config
        copy: src=nginx.conf dest=/etc/nginx/
        tags: updateconfig
      - name: add virtualhost config
        copy: src=www.qfedu.com.conf
              dest=/etc/nginx/conf.d/
        tags: updateconfig
      - name: check nginx syntax
        shell: /usr/sbin/nginx -t
        register: nginxsyntax
        tags: updateconfig
      - name: check nginx running
        stat: path=/var/run/nginx.pid
        register: nginxrunning
        tags: updateconfig
      - name: print nginx syntax
        debug: var=nginxsyntax
     
      - name: print nginx syntax
        debug: var=nginxrunning
      - name: reload nginx server
        service: name=nginx state=started
        when: nginxsyntax.rc == 0 and
        nginxrunning.stat.exists == true
        tags: updateconfig
      - name: start nginx server
        service: name=nginx state=started
        when:
         - nginxsyntax.rc == 0
         - nginxrunning.stat.exists == false
         tags: updateconfig
    
    • 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

    执⾏时⼀定要指定tags,这样在执⾏的过程中只会执⾏task 任务上打上tag 标记为 updateconfig 的任务

    ansible-playbook -i hosts site.yml -t updateconfig
    
    • 1

    五)Handlers属性

    观察当前的 Playbook,不能发现,当我的配置⽂件没有发⽣变化时,每次依然都会去触发TASK “reload nginx server”。
    如何能做到只有配置⽂件发⽣变化的时候才去触发TASK “reload nginx server”,这样的处理才是最完美的实现。此时可以使⽤handlers 属性。
    改进的Playbook:

    - name: handlers playbook example
      hosts: webservers
      gather_facts: no
      vars:
       createuser:
        - tomcat
        - www
        - mysql
      tasks:
      - name: create user
        user: name={{ item }} state=present
        with_items: "{{ createuser }}"
      - name: yum nginx webserver
        yum: name=nginx state=present
      - name: update nginx main config
        copy: src=nginx.conf dest=/etc/nginx/
        tags: updateconfig
        notify: reload nginx server
      - name: add virtualhost config
        copy: src=www.qfedu.com.conf
              dest=/etc/nginx/conf.d/
        tags: updateconfig
        notify: reload nginx server
      - name: check nginx syntax
        shell: /usr/sbin/nginx -t
        register: nginxsyntax
        tags: updateconfig
      - name: check nginx running
        stat: path=/var/run/nginx.pid
        register: nginxrunning
        tags: updateconfig
      - name: start nginx server
        service: name=nginx state=started
        when:
         - nginxsyntax.rc == 0
         - nginxrunning.stat.exists == false
     handlers:
       - name: reload nginx server
         service: name=nginx state=reloaded
         when:
          - nginxsyntax.rc == 0
          - nginxrunning.stat.exists == true
    
    • 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

    在改进的PlayBook中,我们针对⽂件发布TASK 任务 “update nginx main config” 和 “add virtualhost config” 增加了新属性 notify, 值为 “reload nginx server”。
    它的意思是说,针对这两个⽂件发布的TASK,设置⼀个通知机制,当Ansible 认为⽂件的内容发⽣了变化(⽂件MD5发⽣变化了),它就会发送⼀个通知信号,通知 handlers 中的某⼀个任务。具体发送到handlers中的哪个任务,由notify 的值"reload nginx server"决定。通知发出后handlers 会根据发送的通知,在handlers中相关的任务中寻找名称为"reload nginx server" 的任务。
    当发现存在这样名字的TASK,就会执⾏它。若没有找到,则什么也不做。若我们要实现这样的机制,千万要注意notify属性设置的值,⼀定要确保能和handlers中的TASK 名称对应上。
    ⾸次执⾏,若配置⽂件没有发⽣变化,可以发现根本就没有触发handlers 中TASK任务

    ansible-playbook -i hosts site.yml -t updateconfig
    
    • 1

    ⼈为对Nginx 配置⽂件稍作修改,只要MD5校验值发⽣变化即
    可。此时再执⾏,发现触发了handlers 中的TASK任务

     ansible-playbook -i hosts site.yml -t updateconfig 1
    
    • 1
  • 相关阅读:
    免费可商用图片素材网站,建议收藏
    MyBatis 分页插件 PageHelper 6.0.0 发布
    <C++>类和对象下|初始化列表|explicit static|友元|内部类|匿名对象|构造函数的优化
    解锁Hutool魔法箱:Java开发者不可错过的神奇工具集
    win11开机音效设置的方法
    Java 性能优化实战高级进阶:JIT 如何影响 JVM 的性能?
    golang 自动生成文件头
    C++: 多态
    青藏高原1-km分辨率生态环境质量变化数据集(2000-2020)
    【数据结构】测试7 图
  • 原文地址:https://blog.csdn.net/xiaoyu070321/article/details/132921081