Ansible Playbook的任务控制 day5

一、Ansible任务控制基本介绍

这里主要来介绍PlayBook中的任务控制,任务控制类似于编程语言中的if … 、for … 等逻辑控制语句。这里我们给出一个实际场景应用案例去说明在PlayBook中,任务控制如何应用。

在下面的PlayBook中,我们创建了 tomcat、www 和 mysql 三个用户。安装了Nginx 软件包、并同时更新了 Nginx 主配置文件和虚拟主机配置文件,最后让Nginx 服务处于启动状态。整个PlayBook从语法上没有任何问题,但从逻辑和写法上仍然有一些地方需要我们去注意及优化:
1、Nginx启动逻辑欠缺考虑。应该要 若Nginx的配置文件语法错误则会导致启动Nginx失败,以至于PlayBook执行失败。
2、批量创建用户,通过指令的罗列过于死板。如果再创建若干个用户,将难以收场。

二、条件判断

解决第一个问题:
Nginx启动逻辑欠缺考虑。若Nginx的配置文件语法错误则会导致启动Nginx失败,以至于PlayBook执行失败

如果我们能够在启动之前去对Nginx的配置文件语法做正确性的校验,只有当校验通过的时候我们才去启动或者重启Nginx;否则则跳过启动Nginx的过程。这样就会避免Nginx 配置文件语法问题而导致的无法启动的风险。

Nginx 语法校验

- name: check nginx syntax
  shell: /usr/sbin/nginx -t

那如何将Nginx语法检查的TASK同Nginx启动的TASK关联起来呢?

如果我们能够获得语法检查的TASK的结果,根据这个结果去判断“启动NGINX的TASK”是否执行,这将是一个很好的方案。
如何和获取到语法检查TASK的结果呢? 此时就可以使用Ansible中的注册变量。

获取Task任务结果(注册变量)

- name: check nginx syntax
  shell: /usr/sbin/nginx -t
  register: nginxsyntax

此时有可能还有疑问,我获取到任务结果,但是结果里面的内容是个什么样子, 我如何在后续的PlayBook中使用呢?

扫描二维码关注公众号,回复: 11702917 查看本文章

通过debug模块去确认返回结果的数据结构

- name: print nginx syntax result
  debug: var=nginxsyntax

通过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

PlayBook site.yml

---
- 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=virtualhost.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

(注册变量,when注册变量结果)
以上的逻辑,只要语法检查通过都会去执行 “start nginx server"这个TASK。当反复执行这个PlayBook 的,除了第一次外,其他"start nginx server” 的TASK是没有必要的执行的。能否避免这样的问题呢?我们在判断"start nginx server" 这个TASK任务是否启动的条件基础上再加一个条件。只有当语法校验正确等于0、且Nginx 服务没有启动的时候再去启动服务。

另外when支持如下运算符:

==
!=
> >=
< <=
is defined
is not defined
true
false
支持逻辑运算符:and or

在这里插入图片描述

三、循环控制

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

#! /bin/bash
createuser="tomcat mysql www"
for i in `echo $createuser`
do
   useradd $i
done

那么如果PlayBook中也存在这样的循环控制,我们也可以像写shell一样简单的去完成多用户创建工作。
在PlayBook中使用with_items去实现循环控制,且循环时的中间变量(上面shell循环中的$i 变量)只能是
关键字item,而不能随意自定义。

上面的基础上,改进的PlayBook
在这里使用定义了剧本变量createuser(一个列表),然后通过with_items循环遍历变量这个变量来达到创建用户的目的。
PlayBook site.yml

---
- name: task control 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=virtualhost.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

解决了以上问题,整个PlayBook已经有了很大的改进。但我们在生产环境中验证时发现还是不够灵活。
若更新了Nginx 的配置文件后,我们需要通过PlayBook将新的配置发布到生产服务器上,然后再重新加载我们的Nginx 服务。但以现在的PlayBook来说,每次更改Nginx 配置文件后虽然可以通过它发布到生产,但整个PlayBook都要执行一次,这样无形中扩大了变更范围和变更风险

新版本循环

# vim loop.yml
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

在这里插入图片描述
考虑这样一个情况:

若更新了Nginx的配置文件后,我们需要通过PlayBook将新的配置发布到生产服务器上,然后再重新加载我们的Nginx服务。但以现在的PlayBook来说,每次更改Nginx配置文件后虽然可以通过它发布到生产,但整个PlayBook都要执行一次,这样无形中扩大了变更范围和变更风险。
(想挑选某些执行,某些跳过)
下面的Tags 属性就可以解决这个问题。

四、Tags属性

我们可以通过Play中的tags 属性,去解决目前PlayBook变更而导致的扩大变更范围和变更风险的问题。

在改进的PlayBook中,针对文件发布TASK 任务 "update nginx main config""add virtualhost config"
新增了属性 tags ,属性值为updateconfig。

另外我们新增"reload nginx server" TASK任务。当配置文件更新后,去reload Nginx 服务。这样对配置文件更新的操作将很完美。

那重新加载需要依赖于Nginx服务是已经启动状态。所以,还需要进一步通过判断Nngix的pid 文件存在,才证明Nginx服务本身是启动中,启动中才可以reload Nginx服务。

判断一个文件是否存在使用stat模块

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

观察结果,会发现nginxrunning.stat.exists的值是true就表示启动状态,是false就是关闭状态

接下来下来就可以依据这个结果,来决定是否重新加载Nginx服务。

改进PlayBook

---
- name: task control playbook example
  hosts: webservers
  gather_facts: no
  wars:
    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: update

    - name: add virtualhost config
      copy: src=virtualhost.conf dest=/etc/nginx/conf.d/
      tags: update

    - name: check nginx syntax
      shell: /usr/sbin/nginx -t
      register: nginxsyntax
      tags: update
      
    - name: check nginx running
      stat: path=/var/lock/subsys/nginx
      register: nginxrunning
      tags: update
      
    - name: print nginx syntax
      debug: var=nginxsyntax

    - name: start nginx server
      service: name=nginx state=started
      when: nginxsyntax.rc == 0 and nginxrunning.stat.exists == false

指定tags去执行Playbook

// 执行时一定要指定tags,这样再执行的过程中只会执行task 任务上打上tag 标记为 updateconfig 的任务
# ansible-playbook site.yml -t update

但反复执行此PlayBook依然存在问题。当我的配置文件没有发生变化时,每次依然都会去触发TASK “reload nginx server”。如何能做到只有配置文件发生变化的时候才去触发TASK “reload nginx server”,这样的处理才是最完美的实现。此时可以使用handlers 属性。

五、Handiers属性

观察当前的Playbook,不能发现,当我的配置文件没有发生变化时,每次依然都会去触发TASK"reload nginx server"。

如何能做到只有配置文件发生变化的时候才去触发TASK"reload nginxserver",这样的处理才是最完美的实现。此时可以使用handlers属性。

task:
  - name: update nginx config
	notify: reload nginx server
handlers:
  - name: reload nginx server
  	service: name=nginx state=reload
  	when:
  	  - nginxsyntax.rc == 0
  	  - nginxrunning.stat.exists == true

在改进的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 名称对应上。

改进PlayBook

---
- name: task control playbook example
  hosts: web_servers
  wars:
    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: update
      notify: reload nginx server

    - name: add virtualhost config
      copy: src=www.biudefor.com.conf dest=/etc/nginx/conf.d/
      tags: update
      notify: reload nginx server

    - name: check nginx syntax
      shell: /usr/sbin/nginx -t
      register: nginxsyntax
      tags: update
      
    - name: check nginx running
      stat: path=/var/lock/subsys/nginx
      register: nginxrunning
      tags: update
      
    - name: print nginx syntax
      debug: var=nginxsyntax

    - name: start nginx server
      service: name=nginx state=started
      when: nginxsyntax.rc == 0 and nginxrunning.stat.exists == false
	
  handlers:
  	- name: reload nginx server
  	  service: name=nginx state=reload
  	  when:
  	  	- nginxsyntax.rc == 0
  	  	- nginxrunning.stat.exists == true
  	 

执行

// 首次执行,若配置文件没有发生变化。发现根本就没有触发handlers 中TASK任务
# ansible-playbook site.yml -t updateconfig
// 人为对Nginx 配置文件稍作修改,只要MD5校验值发生变化即可。此时再执行,发现触发了handlers 中的TASK任务
# ansible-playbook site.yml -t updateconfig

猜你喜欢

转载自blog.csdn.net/qq_39578545/article/details/107293609