Ansible之Playbook的任务控制

2023-09-16 17:06:57

一)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

二)条件判断

解决第一个问题:Nginx启动逻辑⽋缺考虑。 若Nginx的配置⽂件语法错误则会导致启动Nginx失败,以⾄于PlayBook执⾏失败。
如果我们能够在启动之前去对Nginx的配置⽂件语法做正确性的校验,只有当校验通过的时候我们才去启动或者重启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中怎样使用
通过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:

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

以上的逻辑,只要语法检查通过都会去执⾏ "start nginx server"这个TASK。 在这个问题的解决⾥,我们学习了when 条件判断和注册变量的结合使⽤。学习了when条件判断中是可以⽀持复杂逻辑的。⽐如现在⽤到的逻辑运算符 and。
另外 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 循环遍历变量这个变量来达到创建⽤户的⽬的。

- 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

解决了以上问题,整个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

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

观察结果,会发现 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

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

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

五)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

在改进的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

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

 ansible-playbook -i hosts site.yml -t updateconfig 1
更多推荐

Java开发 - Canal进阶之和Redis的数据同步

前言Canal在数据同步中是非常常见的,一般我们会用它来做MySQL和Redis之间、MySQL和ES之间的数据同步,否则就是手动通过代码进行同步,造成代码耦合度高的问题,这并不是我们愿意看见的,今天这篇博客博主将给大家演示Canal的数据同步做法,敲小黑板了啊,实战中基本也是这么做的,有需要的小伙伴可以仔细研究。前文

【Vue3 源码解析】reactive 全家桶

//泛型约束:只能传入引用类型exportfunctionreactive<Textendsobject>(target:T):UnwrapNestedRefs<T>//判断只读,否则创建reactive响应式对象exportfunctionreactive(target:object){//iftryingtoobs

Dubbo高手之路3,Dubbo服务消费详解

目录引言1.介绍Dubbo服务消费的详解的目的和背景2.概述Dubbo服务消费的过程和核心概念一、Dubbo服务消费的基础知识1.Dubbo服务消费的架构和流程2.Dubbo服务消费的基本配置和使用方法二、Dubbo服务消费的注册与发现1.Dubbo服务消费的注册中心和发布中心的基本概念和特点1.1服务消费的注册中心:

从源码全面解析 dubbo 服务端服务调用的来龙去脉

👏作者简介:大家好,我是爱敲代码的小黄,独角兽企业的Java开发工程师,CSDN博客专家,阿里云专家博主📕系列专栏:Java设计模式、Spring源码系列、Netty源码系列、Kafka源码系列、JUC源码系列、duubo源码系列🔥如果感觉博主的文章还不错的话,请👍三连支持👍一下博主哦🍂博主正在努力完成20

Qt+GDAL开发笔记(二):在windows系统msvc207x64编译GDAL库、搭建开发环境和基础Demo

若该文为原创文章,转载请注明原文出处本文章博客地址:https://hpzwl.blog.csdn.net/article/details/132077288红胖子网络科技博文大全:开发技术集合(包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬结合等等)持续更新中…Qt开发

QT中进程的创建

文章目录前言一、QProcess类介绍二、创建进程代码三、QT中进程的创建和Linux中创建线程对比总结前言本篇文章将带大家学习QT中进程的创建。一、QProcess类介绍QProcess类是Qt中用于启动和控制外部进程的类。它提供了一系列方法来执行外部命令、与进程进行交互,并获取进程的输出信息。下面是一些QProce

Qt+GDAL开发笔记(一):在windows系统mingw32编译GDAL库、搭建开发环境和基础Demo

若该文为原创文章,转载请注明原文出处本文章博客地址:https://hpzwl.blog.csdn.net/article/details/131931309红胖子网络科技博文大全:开发技术集合(包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬结合等等)持续更新中…Qt开发

R语言绘制染色体变异位置分布图,RIdeogram包

变异位点染色体分布图今天分享的内容是通过RIdeogram包绘制染色体位点分布图,并介绍一种展示差异位点的方法。在遗传学研究中,通过测序等方式获得了基因组上某些位置的基因型信息。如下表,第一列是变异位点的ID,第二列是染色体,第三列是物理位置,最后两列是两个样品的基因型。这个文件通常有好几万行,要想快速从中获得有效信息

数字孪生行业相关政策梳理--智慧水利领域相关政策(可下载)

&nbsp;&nbsp;&nbsp;&nbsp;自2021年国家“十四五”规划纲要提出“探索建设数字孪生城市”以来,国家发展和改革委员会、工业和信息化部、住房和城乡建设部、水利部、农业农村部等部门纷纷出台政策,大力推动数字孪生在千行百业的落地发展。这些政策不仅为数字孪生的应用提供了广阔的舞台,也为相关产业的发展提供了坚

数据结构----链式栈

目录前言链式栈操作方式1.存储结构2.初始化3.创建节点4.判断是否满栈5.判断是否空栈6.入栈7.出栈8.获取栈顶元素9.遍历栈10.清空栈完整代码前言前面我们学习过了数组栈的相关方法,(链接:线性表-----栈(栈的初始化、建立、入栈、出栈、遍历、清空等操作)_灰勒塔德的博客-CSDN博客)那么今天我们就开始学习新

初识Java 9-1 内部类

目录创建内部类到外部类的链接使用.this和.new内部类和向上转型在方法和作用域中的内部类匿名内部类嵌套类接口中的类从多嵌套的内部类中访问外部人员本笔记参考自:《OnJava中文版》定义在另一个类中的类称为内部类。利用内部类,将逻辑上存在关联的类组织在一起,并且可以控制一个类在另一个类中的可见性。创建内部类创建内部类

热文推荐