首页 > 其他分享 >Ansible的灵魂:playbook

Ansible的灵魂:playbook

时间:2025-01-18 23:43:16浏览次数:1  
标签:play ok name 192.168 Ansible playbook 执行 灵魂

ansible命令每次只能执行一个任务,这种运行方式称为Ad-hoc(点对点模式),不考虑Ansible特性的话,这功能比ssh远程执行命令还要弱。

所以,Ansible靠ansible命令是撑不起自动化管理这把大伞的,Ansible真正强大的是playbook,它才是Ansible撬动自动化管理的结实杠杆。

1、playbook、play和task的关系

在前面介绍inventory的时候,我将它类比为演员表,在这里,我继续对playbook、play和task跟拍电影中的一些过程做个对比。

playbook译为剧本,就像电影、电视剧的剧本一样,剧本中记录了电影的每一片段应该怎么拍,包括:拍之前场景布置、拍之后的清场、每一个演员说什么话做什么动作、每一个演员穿什么样的衣服,等等。

Ansible的playbook也如此,电影的每一个片段可以对应于playbook中的每一个play,每一个play都可以有多个任务(tasks),tasks可以对应于电影片段中的每一幕。所以,playbook可以用来组织多个任务,然后让这些任务统一执行,就像shell脚本组织多个命令一样,这种组织多个事件、多个任务的行为,有一个更高大上的术语:"编排"。

还可以继续更细致的对应起来。比如每一个play都可以定义自己的环境,比如play级别的变量,对应于电影片段的场景布置,每一个play都需要指定要执行该play的主机,即先确定好这个电影片段中涉及的演员,每一个Play可以有pre_tasks,对应于正式开拍之前的布置,每一个play可以有post_tasks,对应于拍完之后的清场。

而我们人,既是编写playbook的编剧,也是让playbook跑起来的导演。

简单总结一下playbook、play和task的关系:

1、playbook中可以定义一个或多个play

2、每个play中可以定义一个或多个task

其中还可以定义两类特殊的task:pre_tasks和post_tasks

pre_tasks表示执行执行普通任务之前执行的任务列表

post_tasks表示普通任务执行完之后执行的任务列表

3、每个play都需要通过hosts指令指定要执行该play的目标主机

4、每个play都可以设置一些该play的环境控制行为,比如定义play级别的变量

如图:

【例如】,下面是一个playbook示例,文件名为first.yml,内容如下:

---
-name:play1
hosts:nginx
gather_facts:false
tasks:
    -name:task1inplay1
      debug:
        msg:"output task1 in play1"

    -name:task2inplay1
      debug:
        msg:"output task2 in play1"

-name:play2
hosts:apache
gather_facts:false
tasks:
    -name:task1inplay2
      debug:
        msg:"output task1 in play2"

    -name:task2inplay2
      debug:
        msg:"output task2 in play2"

先不管这个playbook中的内容具体是什么含义,后面会为大家介绍playbook的写法。不过,我想大家从名称或从缩进级别上大致也能看出这个playbook中包含两个play:"play 1"和"play 2",每个play中又包含了两个task。且执行"play 1"的是nginx主机组中的主机节点,执行"play 2"的是apache主机组中的主机节点。

使用ansible-playbook命令执行这个playbook:

$ ansible-playbook first.yml

输出结果:

PLAY [play 1] **************************

TASK [task1 in play1] ******************
ok: [192.168.200.27] => {
    "msg": "output task1 in play1"
}
ok: [192.168.200.28] => {
    "msg": "output task1 in play1"
}
ok: [192.168.200.29] => {
    "msg": "output task1 in play1"
}

TASK [task2 in play1] ******************
ok: [192.168.200.27] => {
    "msg": "output task2 in play1"
}
ok: [192.168.200.28] => {
    "msg": "output task2 in play1"
}
ok: [192.168.200.29] => {
    "msg": "output task2 in play1"
}

PLAY [play 2] **************************

TASK [task1 in play2] ******************
ok: [192.168.200.30] => {
    "msg": "output task1 in play2"
}
ok: [192.168.200.31] => {
    "msg": "output task1 in play2"
}
ok: [192.168.200.32] => {
    "msg": "output task1 in play2"
}
ok: [192.168.200.33] => {
    "msg": "output task1 in play2"
}

TASK [task2 in play2] ******************
ok: [192.168.200.30] => {
    "msg": "output task2 in play2"
}
ok: [192.168.200.31] => {
    "msg": "output task2 in play2"
}
ok: [192.168.200.32] => {
    "msg": "output task2 in play2"
}
ok: [192.168.200.33] => {
    "msg": "output task2 in play2"
}

PLAY RECAP ****************************
192.168.200.27  : ok=2  changed=0  ......
192.168.200.28  : ok=2  changed=0  ......
192.168.200.29  : ok=2  changed=0  ......
192.168.200.30  : ok=2  changed=0  ......
192.168.200.31  : ok=2  changed=0  ......
192.168.200.32  : ok=2  changed=0  ......
192.168.200.33  : ok=2  changed=0  ......

输出结果有点长,但是初学playbook,有必要了解一下输出结果中一些内容的含义。

首先执行的是playbook中的"play 1",nginx主机组(有3个节点)要执行这个play,且这个play中有两个任务要执行,所以输出结果为:

PLAY [play 1] **************************

TASK [task1 in play1] ******************
ok: [192.168.200.27] => {}
ok: [192.168.200.28] => {}
ok: [192.168.200.29] => {}

TASK [task2 in play1] ******************
ok: [192.168.200.27] => {}
ok: [192.168.200.28] => {}
ok: [192.168.200.29] => {}

其中ok表示任务执行成功,且PLAY和TASK后面都指明了play的名称、task的名称。

执行完"play 1"之后,执行"play 2",apache主机组(有3个节点)要执行这个play,且这个play中有两个任务要执行,所以输出的输出结果和上面的类似。

最后输出的是每个主机执行任务的状态统计,比如某个主机节点执行成功的任务有几个,失败的有几个。

PLAY RECAP ****************************
192.168.200.27  : ok=2  changed=0  ......
192.168.200.28  : ok=2  changed=0  ......
192.168.200.29  : ok=2  changed=0  ......
192.168.200.30  : ok=2  changed=0  ......
192.168.200.31  : ok=2  changed=0  ......
192.168.200.32  : ok=2  changed=0  ......
192.168.200.33  : ok=2  changed=0  ......

介绍完playbook并演示完它的用法之后,接下来该学playbook的写法了。

2、 playbook的语法:YAML

ansible的playbook采用yaml语法,它以非常简洁的方式实现了json格式的事件描述。yaml之于json就像markdown之于html一样,极度简化了json的书写。

YAML文件后缀通常为.yaml.yml

YAML在不少工具里都使用,学习它是"一次学习、终生受益"的,所以很有必要把yaml的语法格式做个梳理,系统性地去学一学。

YAML的基本语法规则如下:

YAML支持三种数据结构:

  • 对象:key/value格式,也称为哈希结构、字典结构或关联数组

  • 数组:也称为列表

  • 标量(scalars):单个值

可以去找一些在线YAML转换JSON网站,比如http://yaml-online-parser.appspot.com,通过在线转换可以验证或查看自己所写的YAML是否出错以及哪里出错。也可以安装yq(yaml query)命令将yaml数据转换成json格式数据。

yum -y install jq
pip3 install yq

用法:

cat a.yml | yq .

1、对象

一组键值对,使用冒号隔开key和value。注意,冒号后必须至少一个空格。

name: junmajinlong

等价于json:

{
  "name": "junmajinlong"
}

2、 数组

---
- Shell
- Perl
- Python

等价于json:

["Shell","Perl","Python"]

也可以使用行内数组(内联语法)的写法:

---
["Shell","Perl","Python"]

再例如:

---
- lang1: Shell
- lang2: Perl
- lang3: Python

等价于json:

[
  {"lang1": "Shell"}, 
  {"lang2": "Perl"}, 
  {"lang3": "Python"}
]

将对象和数组混合:

---
languages:
  - Shell
  - Perl
  - Python

等价于json:

{
  "languages": ["Shell","Perl","Python"]
}

3 、字典

---
person1:
name:junmajinlong
age:18
gender:male

person2:
name:xiaofanggao
age:19
gender:female

等价于json:

{
  "person2": {
    "gender": "female", 
    "age": 19, 
    "name": "xiaofanggao"
  }, 
  "person1": {
    "gender": "male", 
    "age": 18, 
    "name": "junmajinlong"
  }
}

也可以使用行内对象的写法:

---
person1: {name: junmajinlong, age: 18, gender: male}

4、 复合结构

---
-person1:
name:junmajinlong
age:18
langs:
    -Perl
    -Ruby
    -Shell

-person2:
name:xiaofanggao
age:19
langs:
    -Python
    -Javascript

等价于json:

[
  {
    "langs": [
      "Perl", 
      "Ruby", 
      "Shell"
    ], 
    "person1": null, 
    "age": 18, 
    "name": "junmajinlong"
  }, 
  {
    "person2": null, 
    "age": 19, 
    "langs": [
      "Python", 
      "Javascript"
    ], 
    "name": "xiaofanggao"
  }
]

5、 字符串续行

字符串可以写成多行,从第二行开始,必须至少有一个单空格缩进。换行符会被转为空格。

str: hello
  world
  hello world

等价于json:

{
  "str": "hello world hello world"
}

也可以使用>换行,它类似于上面的多层缩进写法。此外,还可以使用|在换行时保留换行符。

this: |
  Foo
  Bar
that: >
  Foo
  Bar

等价于json:

{'that': 'Foo Bar', 'this': 'Foo\nBar\n'}

6、 空值

YAML中某个key有时候不想为其赋值,可以直接写key但不写value,另一种方式是直接写null,还有一种比较少为人知的方式:波浪号~。

例如,下面几种方式全是等价的:

key1: 
key2: null
key3: Null
key4: NULL
key5: ~

7、 YAML中的单双引号和转义

YAML中的字符串是可以不用使用引号包围的,但是如果包含了特殊符号,则需要使用引号包围。

单引号包围字符串时,会将特殊符号保留。

双引号包围字符串时,反斜线需要额外进行转义。

例如,下面几对书写方式是等价的:

- key1:"~"
-key2:'~'

-key3:'\.php$'
-key4:"\\.php$"
-key5:\.php$

-key6:\n
-key7:'\n'
-key8:"\\n"

等价于json:

[
  { "key1": "~" },
  { "key2": "~" },
  { "key3": "\\.php$" },
  { "key4": "\\.php$" },
  { "key5": "\\.php$" },
  { "key6": "\\n" },
  { "key7": "\\n" },
  { "key8": "\\n" }
]

3、 playbook的写法

了解YAML写法之后,就可以来写Ansible的playbook了。

回顾一下前文对playbook、play和task关系的描述,playbook可以包含一个或多个play,每个play可以包含一个或多个任务,且每个play都需要指定要执行该play的目标主机。

于是,将下面这个ad-hoc模式的ansible任务改成等价的playbook模式:

$ ansible nginx -m copy -a 'src=/etc/passwd dest=/tmp'

假设这个playbook的文件名为copy.yml,其内容如下:

---
- hosts: nginx
  gather_facts: false

  tasks: 
    - copy: src=/etc/passwd dest=/tmp

然后使用ansible-playbook命令执行该playbook。

$ ansible-playbook copy.yml

再来解释一下这个playbook文件的含义。

playbook中,每个play都需要放在数组中,所以在playbook的顶层使用列表的方式- xxx:来表示这是一个play(此处是- hosts:)。

每个play都必须包含hosts和tasks指令。

hosts指令用来指定要执行该play的目标主机,可以是主机名,也可以是主机组,还支持其它方式来更灵活的指定目标主机。具体的规则后文再做介绍。

tasks指令用来指定这个play中包含的任务,可以是一个或多个任务,任务也需要放在play的数组中,所以tasks指令内使用- xxx:的方式来表示每一个任务(此处是- copy:)。

gather_facts是一个play级别的指令设置,它是一个负责收集目标主机信息的任务,由setup模块提供。默认情况下,每个play都会先执行这个特殊的任务,收集完信息之后才开始执行其它任务。但是,收集目标主机信息的效率很低,如果能够确保playbook中不会使用到所收集的信息,可以显式指定gather_facts: no来禁止这个默认执行的收集任务,这对效率的提升是非常可观的。

此外每个play和每个task都可以使用name指令来命名,也建议尽量为每个play和每个task都命名,且名称具有唯一性。

所以,将上面的playbook改写:

---
-name:firstplay
hosts:nginx
gather_facts:false

tasks:
    -name:copy/etc/passwdto/tmp
      copy:src=/etc/passwddest=/tmp

4、 playbook模块参数的传递方式

在刚才的示例中,copy模块的参数传递方式如下:

  tasks: 
    - name: copy /etc/passwd to /tmp
      copy: src=/etc/passwd dest=/tmp

这是标准的yaml语法,参数部分src=/etc/passwd dest=/tmp是一个字符串,当作copy对应的值。

根据前面介绍的yaml语法,还可以换行书写。有以下几种方式:

---
-name:firstplay
hosts:nginx
gather_facts:false
tasks:
    -copy:
        src=/etc/passwddest=/tmp

    -copy:
        src=/etc/passwd
        dest=/tmp

    -copy:>
        src=/etc/passwd
        dest=/tmp

    -copy: |
        src=/etc/passwd
        dest=/tmp

除此之外,Ansible还提供了另外两种传递参数的方式:

将参数和参数值写成key: value的方式

使用args参数声明接下来的是参数

通过示例便可对其用法一目了然:

---
-name:firstplay
hosts:nginx
gather_facts:false
tasks:
    -name:copy1
      copy:
        src:/etc/passwd
        dest:/tmp

    -name:copy2
      copy:
      args:
        src:/etc/passwd
        dest:/tmp

大多数时候,使用何种方式传递参数并无关紧要,只要个人觉得可读性高、方便、美观即可。

5、 指定执行play的目标主机

每一个play都包含hosts指令,它用来指示在解析inventory之后选择哪些主机执行该play中的tasks。

hosts指令通过pattern的方式来筛选节点,pattern的指定方式有以下几种规则:

直接指定inventory中定义的主机名

hosts: localhost

直接指定inventory中的主机组名

hosts: nginx

hosts: all

使用组名时,可以使用数值索引的方式表示组中的第几个主机

hosts: nginx[1]:mysql[0]

可使用冒号或逗号隔开多个pattern

hosts: nginx:localhost

可以使用范围表示法

hosts: 192.168.200.3[0:3]
hosts: web[A:D]

可以使用通配符*

hosts: *.example.com

hosts: *,这等价于hosts: all

可以使用正则表达式,需使用~开头

hosts: ~(web|db)\.example\.com

此外:

所有pattern选中的主机都是包含性的,第一个pattern选中的主机会添加到下一个pattern的范围内,直到最后一个pattern筛选完,于是取得了所有pattern匹配的主机

pattern前面加一个&符号表示取交集

pattern1:&pattern2要求同时存在于pattern1和pattern2中的主机

pattern前面加一个!符号表示排除

pattern1:!pattern2要求出现在pattern1中但未出现在pattern2中

6、 默认的任务执行策略

最后,再来简单探究一下默认情况下Ansible是以什么样的策略去控制多个节点执行多个任务的(如果你愿意,还可以将这个执行策略跟拍戏进行类比,我就不再多说了,毕竟我是IT攻城狮不是编剧也不是导演啊)。

假设有10个目标节点要执行某个play中的3个任务:tA、tB、tC。

默认情况下,会从10个目标节点中选择5个节点作为第一批次的节点执行任务tA,第一批次的5个节点都执行tA完成后,将选择剩下的5个节点作为第二批次执行任务tA。

所有节点都执行完任务tA后,第一批次的5节点开始执行任务tB,然后第二批次的5个节点执行任务tB。

所有节点都执行完任务tB后,第一批次的5节点开始执行任务tC,然后第二批次的5个节点执行任务tC。

整个过程如下:

这个流程图虽然简单形象,但是不严谨,稍后会解释为何不严谨。

这里提到的5个节点的数量5,是由配置文件中forks指令的值决定的,默认值为5。

$ grep 'fork' /etc/ansible/ansible.cfg
#forks          = 5

forks指令用来指定Ansible最多要创建几个子进程来执行任务,每个节点默认对应一个ansible-playbook进程和ssh进程,例如forks=5表示最多创建5个ansible-playbook子进程。所以,forks的值也代表了最多有几个节点同时执行任务。

【例如】,将hosts指令指定为all,并将gather_facts指令取消注释,因为这个任务执行比较慢,方便观察进程列表。

---
- name: first play
  hosts: all 
  #gather_facts: false

执行该playbook。

$ ansible-playbook test.yaml

然后在另外一个终端上去查看进程列表:

根据上面对forks指令的效果描述,前面的执行策略流程图并不严谨。因为forks的效果并不是选中一批节点,本批节点执行完任务才选下一批节点。forks是保证最多有N个节点同时执行任务,但有的节点可能执行任务较慢。比如有10个节点,且forks=5时,第一批选中5个节点执行任务,假如第1个节点先执行完任务,Ansible主控进程不会等待本批中其它4个节点执行完任务,而是直接创建一个新的Ansible进程,让第6个节点执行任务。

链接:https://www.cnblogs.com/f-ck-need-u/p/17718463.html

(版权归原作者所有,侵删)

标签:play,ok,name,192.168,Ansible,playbook,执行,灵魂
From: https://www.cnblogs.com/o-O-oO/p/18679038

相关文章

  • 【Ansible运维】让Ansible更安全:使用Vault进行加密
    管理目标节点时,有些操作需要使用密码才允许访问,但Ansible是一个自动化配置管理工具,在自动化操作的阶段中要求交互式输入密码的行为应该是一件让人败兴的事。通常,实现非交互式的方案有:(1)将敏感数据写入文件(比如写入变量文件),然后读取,这种方案不安全;(2)定义敏感数据对应的环境......
  • 【运维工具】Ansible一款好用的自动化工具
    Ansible一款好用的自动化工具概述一、基本概念与特点二、核心组件三、主要功能与应用场景四、优缺点如何使用一、安装Ansible二、配置Ansible三、使用Ansible四、注意事项Playbook语法详解一、YAML文件的基本结构二、Playbook的主要组成部分三、Playbook示例四、注意事......
  • 【Ansible】重要概念(一)
    目录1、Ansible核心特点1)无代理架构2)基于SSH3)声明式任务定义2、主机清单3、配置文件1、Ansible核心特点1)无代理架构Ansible的无代理架构意味着不需要在被管理的节点上安装任何专门的代理软件。它通过SSH与被控节点通信,实现任务的执行和数据的传输。优点:①简化......
  • kolla-ansible 部署多region集群
    1、先说什么是多Region2、多Region的应用场景:•1、Openstack集群位于不同的区域时,可以用多Region来管理,比如阿里云的北京地区的云主机、上海区的云主机等•2、可用于异构管理,比如当Kvm和Vcenter同时被Openstack管理时,由于网络、镜像等原因必须使用独立的环境来纳管,此时......
  • Ansible(自动化运维)环境搭建及ansible-vault加密配置
    前言:原先这篇博客是在《Linux系统综合配置:yum源设置、逻辑卷制作》里的,现在想着ansible-vault加密配置是可以单独出一期的,就拆分出来了。一、安装ansible命令:sudodnfupdate命令:sudodnfinstallpython3查看版本:python3-V命令:sudodnfinstallpython3-pip命令:p......
  • 实践项目-Ansible+Playbook自动化部署服务器上线
    (241223)环境系统ip主机名域名debian12.8192.168.100.6ansible-mainansible-main.example.comdebian12.8192.168.100.12ansible-node1ansible-node1.example.comdebian12.8192.168.100.15ansible-node2ansible-node2.example.comdebian12.8192.168.......
  • 告别机器人味:如何让ChatGPT写出有灵魂的内容
    目录ChatGPT的一些AI味道小问题1.提供编辑指南2.提供样本3.思维链大纲4.融入自己的想法5.去除重复增加多样性6.删除废话ChatGPT的一些AI味道小问题        大多数宝子们再使用ChatGPT进行写作时,发现我们的老朋友ChatGPT在各类写作上还有点“机器人味”太重,是......
  • Ansible:一键部署Keepalived高可用集群
    使用Ansible工具一键部署Keepalived服务1.需求分析使用ansible部署keepalived服务的过程中,需要实现:1.1多系统支持根据不同的系统,自动选择对应的安装方式。可通过相关的环境变量结合 when实现。1.2源码安装考虑到rpm安装的方式会需要依赖一些基础环境,以及版本较低,将采用源......
  • 自动化工具ansible部署和实践
    1介绍和部署1.1介绍ansible的功能我爱你在当今的IT自动化领域,Ansible无疑是一个无法被忽视的重要角色。其便利性和高效性受到了广大开发者和系统管理员的一致好评,成为了配置管理和应用部署的首选工具。然而,对于一些初学者来说,Ansible的概念和架构可能会显得有些复杂和难......
  • 【转载】Ansible - 基础应用
    原作:https://www.cnblogs.com/keerya/p/7987886.htmlansible自动化运维工具实现了批量系统配置、批量程序部署、批量运行命令等功能。 使用yum安装我们需要先安装一个 epel-release 包,然后再安装我们的ansible即可。yuminstallepel-release-yyuminstallans......