1. playbooks介绍

如果说ansible的modules是工具,inventory配置文件是原材料,那么playbook就是一封说明书,这里会记录任务是如何如何执行的,当然如果你愿意,这里也可以定义一些变量、连接参数等等。

playbook可以由单个或者多个play组成。

单个play示例:

---
- hosts: webserversvars:http_port: 80max_clients: 200remote_user: roottasks:- name: ensure apache is at the latest versionyum:name: httpdstate: latest- name: write the apache config filetemplate:src: /srv/httpd.j2dest: /etc/httpd.confnotify:- restart apache- name: ensure apache is runningservice:name: httpdstate: started

上面的示例中所有的任务作用于webservers所包含的主机,通过root用户连接到目的主机,对apache服务进行了安装、配置、启动等操作,当配置文件有更改时,会触发hanlders里的重启apache操作,vars里定义的“http_port”和 “ max_clients”将会在模版文件“/srv/httpd.j2”中遵循Jinja2语法被使用到。

playbooks是使用yaml语法格式,所以看起来比较通俗易懂。通过上面的示例可以看出一个play可以包含如下内容:

  • hosts:主机组,后面定义的task将作用于该主机组的所有主机
  • vars:变量定义,在后面的task中可以引用
  • remote-user:连接参数,例如remote-user,become,become-user等等,这些参数将会覆盖ansible.cfg配置文件里的参数
  • tasks:任务,可以看作很多modules的集合,这些modules可以使用vars定义的变量
  • handlers:触发才会执行的task,很多情况下,当其他task被执行并且状态有改变后,我们希望会触发一些任务,那些被触发的任务可以写在这里

一个playbooks也可以编写多个play,示例如下:

---
- hosts: webserversremote_user: roottasks:- name: ensure apache is at the latest versionyum:name: httpdstate: latest- name: write the apache config filetemplate:src: /srv/httpd.j2dest: /etc/httpd.conf
- hosts: databasesremote_user: roottasks:- name: ensure postgresql is at the latest versionyum:name: postgresqlstate: latest- name: ensure that postgresql is startedservice:name: postgresqlstate: started 

上面的示例中,第一个play通过root用户连接到webservers主机组,进行了apache服务的安装和配置操作;第二个play通过root用户链接到databases主机组,进行了数据库的安装和启动操作。

2.可重复利用的playbooks

上一章节中我们说到,一个playbooks可以放置多个play,一个play里面可以有多个tasks(modules),但是,当要管理的资源越来越多时,我们发现将所有play都写在一个yml文件里会很臃肿,不好维护。

此时我们可以通过“import_playbook”方法引用其他的playbooks文件;

此时我们可以通过“import_playbook”方法引用其他的playbooks文件;使用“import_tasks”、“include_tasks”、“import_role”、“include_role”、“roles”引用其他的tasks文件。

import_playbook

比较简单,直接上示例,文件main.yml:

- import_playbook: webservers.yml
- import_playbook: databases.yml

上述示例中使用import_playbook将webservers.yml和databases.yml文件里的play引用到main.yml,和直接将两个文件里的内容直接粘过来是一样的效果,执行顺序自然也会按照play定义的顺序执行。

import_tasks和include_tasks

可以参考笔者之前写的文章 ansible中include_tasks和import_tasks

import_role和include_role

ansible2.3引入了include_role,ansible 2.4版本后,新增了import_role,通过这两个方法可以在tasks里面导入role,示例如下:

---
- hosts: webserverstasks:- debug:msg: "before we run our role"- import_role:name: example- include_role:name: example- debug:msg: "after we ran our role"

从上面的示例可以看出,在tasks中使用import_role和include_role方法导入了role example,role里面的task会按顺序执行。

当然我们也可以引用的同时定义变量:

---
- hosts: webserversroles:- common- role: foo_app_instancevars:dir: '/opt/a'app_port: 5000- role: foo_app_instancevars:dir: '/opt/b'app_port: 5001

也可以给role打tag:

---
- hosts: webserverstasks:- import_role:name: footags:- bar- baz

使用条件语句(后面有详细写when语句用法):

---
- hosts: webserverstasks:- include_role:name: some_rolewhen: "ansible_os_family == 'RedHat'"

roles

除了使用import_role和include_role导入role,我们也可以直接使用roles方法来导入,示例如下:

--- - hosts: webservers roles: - common - webservers ###OR - hosts: webservers roles: - role: '/path/to/my/roles/common'

和import和include方法相比,roles方法是仅仅可以导入role类型的playbook,而上述两个方法可以在其他tasks中穿插一些role类型的playbook。

在生产中,roles是比较常用的所以后面的章节会有对roles的单独讲解,这里就不在展开了。

通过以上的总结,我们可以看出,在ansible里,如果我们想复用其他文件的playbooks,可以使用include、import、roles三种方法,据我所知也只有这三种方法。

2.1 动态和静态

至此,我们知道了可以使用import*和include*导入其他的playbooks,那么这两者的区别是什么呢?

在ansible 2.4版本中引入了dynamic和static的概念,在这之前只能使用include来导入其他的tasks文件,现在include也能用,但官方在考虑在未来版本废弃掉。

静态指所有import*的方法,动态指include*的方法。

关于动态和静态的两点区别,总结如下:

  • import_tasks(Static)方法会在playbooks解析阶段将父task变量和子task变量全部读取并加载
  • include_tasks(Dynamic)方法则是在执行play之前才会加载自己变量
  • include_tasks方法调用的文件名称可以加变量
  • import_tasks方法调用的文件名称不可以有变量

具体介绍可以参考笔者之前写的文章ansible中include_tasks和import_tasks

3.playbooks变量

3.1定义变量

ansible中可以定义变量的地方可以有很多,在这里主要写下playbooks里面的变量定义,其他部分的变量会在后续的“ansible基础-变量”详细阐述。

变量的定义通常使用YAML语法格式,示例如下:

---
vars:field1: one
字典变量:
---
foo:field1: onefield2: two

play中定义全局变量

---
- hosts: webserversvars:http_port: 80

上面示例中 http_port参数可以在这个play中的tasks、playbooks、roles中引用。

tasks中定义变量

当然,我们也可以在某个task中定义局部变量,这个变量只能在本task内使用,示例如下:

---
- hosts: node1gather_facts: falsetasks:- name: Use var debugvars:- name: weimeng- age: 26debug:var: name,age

include和import中定义变量

include_role定义变量只在被引用的role中生效:

- hosts: node1gather_facts: falsetasks:- include_role:name: role_Avars:age: 24

include_tasks定义变量只在被引用的task中生效:

tasks:
- import_tasks: wordpress.ymlvars:wp_user: timmy
- import_tasks: wordpress.ymlvars:wp_user: alice
- import_tasks: wordpress.ymlvars:wp_user: bob

roles中定义变量

playbook引用role也可以直接定义变量,示例如下:

---
- hosts: webserversroles:- role: bartags: ["foo"]# using YAML shorthand, this is equivalent to the above- { role: foo, tags: ["bar", "baz"] }

注册变量

在playbook中,我们可以将一个task的执行结果注册为一个变量,供另外一个task使用。例如:

---
- hosts: webserversroles:- role: bartags: ["foo"]# using YAML shorthand, this is equivalent to the above- { role: foo, tags: ["bar", "baz"] }

将一个task的结果注册为一个变量,然后通过这个变量判断另外一个task是否执行,这是注册变量很常用的方式。

通过命令行定义变量

在我们执行playbook时可以在命令行中指定自定义变量,例如:

ansible-playbook release.yml --extra-vars "version=1.23.45 other_variable=foo”

在同一个scope内,如果与其他地方的变量冲突,命令行指定的参数优先级最高。

3.2引用变量文件

上面介绍了在playbook中如何定义变量,那么变量能否和task一样定义在单独的yml文件内,然后使用类似于include_tasks的语句引用过来呢? 答案是肯定的。

在playbook内引用变量文件使用的是vars_files:语句,示例如下:

---
- hosts: allremote_user: rootvars:favcolor: bluevars_files:- /vars/external_vars.ymltasks:- name: this is just a placeholdercommand: /bin/echo foo

在变量文件/vars/external_vars.yml中,我们只需要使用YAML语法格式进行变量定义即可。

3.3 facts

除了我们自定义的变量,ansible还支持另外一种变量,这个变量类似于puppet的facter,ansible叫做fact。

ansible的fact会根据目的主机的系统信息生成一个json格式的变量集合,我们在play中可以直接引用。例如比较常用的变量:ip地址、主机名、操作系统类型等等。

puppet的facter依赖ruby的一个安装包,通过ruby程序收集系统信息,而ansible的fact是通过python程序收集。

我们可以通过setup模块来获取目的主机的fact信息:

ansible hostname -m setup

fact会在playbook执行之前收集信息,默认是打开的,我们也可以通过指定gather_fact参数为false/no/False关闭fact。在没有配置fact cache的情况下,如果关闭fact,playbook的执行速度会有一个显著的提升,示例如下:

---
- hosts: whatevergather_facts: no

3.4变量的使用

前面我们介绍了下变量的定义/引用方式和fact变量,那么在playbook中我们如何使用这些变量呢?

变量通常会在模版、条件判断语句、新的变量定义等处能用到。

使用变量的方法很简单,只需要将变量写在两个大括号内并且前后都有空格即可,同时我们必须将这个大括号用双引号引起来,如果变量穿插在字符串内使用,双引号也要将字符串部分引起来。

示例如下:

- hosts: app_serversvars:app_path: "{{ base_path }}/22"

如果一个变量定义比较复杂,例如列表、字典或fact(json格式),我们可以通过如下方式访问:

列表变量访问:

{{ foo[0] }}

字典变量访问:

{{ foo[name] }} 

{{ foo.name }}

json格式访问变量访问:

{{ansible_eth0["ipv4"]["address"] }}

{{ansible_eth0.ipv4.address }}

这里说一个小技巧,在我们排错过程中很多情况我们要debug一些变量。此时,可以使用debug模块输出变量。

debug模块有两种使用方式,vars和msg :

---
- hosts: node1gather_facts: falsevars:- name: weimeng- age: 26tasks:- name: Use var debugdebug:var: name,age- name: Use msg debugdebug:msg: "my name is {{ name }},and my age is {{ age }}"

输入如下:

➜  lab-ansible ansible-playbook playbooks/task_vars.yml[WARNING]: Found variable using reserved name: namePLAY [node1] *******************************************************************TASK [Use var debug] ***********************************************************
ok: [node1] => {"name,age": "(u'weimeng', 26)"
}TASK [Use msg debug] ***********************************************************
ok: [node1] => {"msg": "my name is weimeng,and my age is 26"
}PLAY RECAP *********************************************************************
node1                      : ok=2    changed=0    unreachable=0    failed=0

通过对比我们可以看出,“vars”适用于直接debug变量,而“msg”可以掺杂一些字符串,我们可以根据实际情况来选择使用。

本章节主要介绍了playbook的相关变量。ansible变量的知识点还是很多的,所以我计划在后边会单独介绍ansible的变量,这里就点到为止。

4. 条件语句

ansible条件语句不是很多,比较常用的就是when语句和循环语句。

当满足一定的条件时,我们想要跳过某个task,这时候when语句出场了。当when语句的参数为true时,才会执行这个task,否则反之。

yum模块的name可以以列表的形式指定多个安装包,但是很多其他模块是不支持列表的,例如file的path,copy的src,等等;或者说我们想迭代的将一个列表元素传递给某个模块处理,如果有多少个元素写多个task就很麻烦。此时我们可以使用ansible的循环语句loop(ansible 2.5以后),在2.5版本之前可以使用with_,loop类似于旧版本的with_list语句。

4.1 when语句

ansible的when语句用于判断是否执行这个task,例如

tasks:- name: "shut down Debian flavored systems"command: /sbin/shutdown -t nowwhen: ansible_os_family == "Debian"# note that Ansible facts and vars like ansible_os_family can be used# directly in conditionals without double curly braces

示例中如果系统的类型是“Debian”才会执行/sbin/shutdown -t now命令。

条件语句也可以使用“and”和“or”:

tasks:- name: "shut down CentOS 6 and Debian 7 systems"command: /sbin/shutdown -t nowwhen: (ansible_distribution == "CentOS" and ansible_distribution_major_version == "6") or(ansible_distribution == "Debian" and ansible_distribution_major_version == "7")

条件也可以写成列表的形式,这种形式和and语句起到一样的效果:

tasks:- name: "shut down CentOS 6 systems"command: /sbin/shutdown -t nowwhen:- ansible_distribution == "CentOS"- ansible_distribution_major_version == "6"

register变量条件语句

通过对某个task的执行结果是否成功,决定另外一个task是否要执行:

tasks:- command: /bin/falseregister: resultignore_errors: True- command: /bin/somethingwhen: result is failed# In older versions of ansible use ``success``, now both are valid but succeeded uses the correct tense.- command: /bin/something_elsewhen: result is succeeded- command: /bin/still/something_elsewhen: result is skipped

变量是否被定义语句:

tasks:- shell: echo "I've got '{{ foo }}' and am not afraid to use it!"when: foo is defined- fail: msg="Bailing out. this play requires 'bar'"when: bar is undefined

4.2 循环语句

上面说到loop类似于旧版本的with_list语句,也就是说loop会将列表的元素逐个传递给上面的module,从而达到重复执行的目的。

最简单的形式:

---
tasks:- command: echo { item }loop: [ 0, 2, 4, 6, 8, 10 ]

loop与when结合使用:

---
tasks:
- command: echo { item }
loop: [ 0, 2, 4, 6, 8, 10 ]
when: item > 5

通常loop语句会结合各式各样的filter去使用,例如“  loop: “{ { [\'alice\', \'bob\'] |product([\'clientdb\', \'employeedb\', \'providerdb\'])|list }}””,这个例子和with_nested语句起到一样的效果。也就是说旧版本的with_ + lookup() 所能实现的,新版本的loop+filter同样能实现。

5. 执行顺序

一般playbook里的task执行顺序和python一样,由上至下,定义的顺序即执行的顺序。同样的,使用include*和import*导入playbook或tasks也会安照导入顺序执行。

5.1 per_tasks和post_tasks

当playbook中有使用roles导入task和自定义tasks时,我们会发现ansible总会先执行roles导入的task,然后执行自定义的tasks,例如:

- hosts: localhostgather_facts: novars:- ff: 1- gg: 2tasks:- debug:var: ffroles:- role: role_B 

输出结果:

➜  lab-ansible ansible-playbook playbooks/roles_vars.ymlPLAY [localhost] ***************************************************************TASK [role_B : debug] **********************************************************
ok: [localhost] => {"a": 2
}TASK [debug] *******************************************************************
ok: [localhost] => {"ff": 1
}PLAY RECAP *********************************************************************
localhost                  : ok=2    changed=0    unreachable=0    failed=0

从上面示例发现,虽然我们将tasks定义在了前面,但是tasks任务还是在roles任务之后执行。此时我们可以使用pre_task和post_task来强制指定执行顺序,例如:

---
- hosts: localhostgather_facts: novars:- ff: 1- gg: 2pre_tasks:- import_role:name: role_Avars:age: 23roles:- role: role_Btasks:- debug:var: ffpost_tasks:- debug:var: gg

总结下playbook里任务的执行顺序:

  • 使用“pre_tasks:”定义的任务

  • 使用“roles:”引用的任务

  • 使用“tasks:”自定义的任务

  • 使用“post_tasks”定义的任务

5.2 handlers

在部署应用时,通常的步骤是安装软件包==>更改配置文件==>初始化数据库==>启动(重启)服务;升级的步骤一般是:升级软件包==>更改配置文件==>初始化数据库==>重启服务。我们发现不管是新部署还是升级,最后一步都是要重新加载程序的,也就是说当我们升级了软件或者更改了配置文件都需要重启一下应用。

为了实现触发服务重启,ansible使用handlers方法定义重启的动作,handlers并不是每次执行playbook都会触发,而是某些指定资源状态改变时才会触发指定的handlers(这里使用“资源”一词借鉴于puppet)。

示例如下:

- name: template configuration filetemplate:src: template.j2dest: /etc/foo.confnotify:- restart memcached- restart apache

上面的示例中,当/etc/foo.conf文件内容有改动时(返回changed),会触发重启memcached和apache服务,如果文件内容没有变化时(返回ok),则不会触发handlers。

ansible执行过程中并不会立即触发handlers动作,而是以play为单位,一个play执行完后最后才会触发handlers。

这样设计也是很合理的,试想在一个play内,如果触发一次就执行一次handlers,那么除了最后一次的重启,前面触发的重启都是无用功。

另外需要注意的一点是,handlers触发的执行顺序是按照定义顺序执行,而不是按照notify指定的顺序执行。

当然如果我们想要立即触发,也是可以的,在play定义“- meta: flush_handlers”即可。

另外需要注意的一点是,handlers触发的执行顺序是按照定义顺序执行,而不是按照notify指定的顺序执行。

6.参考链接

  • https://docs.ansible.com/ansible/latest/user_guide/playbooks_intro.html#
  • https://docs.ansible.com/ansible/2.6/user_guide/playbooks_variables.html
  • https://docs.ansible.com/ansible/2.6/user_guide/playbooks_reuse.html
  • https://docs.ansible.com/ansible/2.6/user_guide/playbooks_templating.html
  • https://docs.ansible.com/ansible/2.6/user_guide/playbooks_conditionals.html
  • https://docs.ansible.com/ansible/2.6/user_guide/playbooks_loops.html

欢迎大家关注我的公众号:

转载于:https://www.cnblogs.com/mauricewei/p/10053649.html

ansible基础-playbooks相关推荐

  1. 《Ansible权威指南 》一第2章 Ansible基础元素介绍

    本节书摘来自华章出版社<Ansible权威指南 >一书中的第2章,第2.1节,李松涛 魏 巍 甘 捷 著更多章节内容可以访问云栖社区"华章计算机"公众号查看. 第2章 ...

  2. ansible基础-Jinja2模版 | 过滤器

    Jinja2模版介绍 注:本文demo使用ansible2.7稳定版 在ansible基础-变量的「8.2 模版使用变量」章节中关于模版与变量也有所提及,有兴趣的同学可以去回顾一下. ansible通 ...

  3. ansible基础-Jinja2模版 | 测试

    ansible基础-Jinja2模版 | 测试 一 简介 注:本文demo使用ansible2.7稳定版 Jinja2的测试语句被用来评估一个条件表达式,并且最终返回True或False,经常和「wh ...

  4. Ansible基础概述

    一.Ansible简介 Ansible基于Python语言实现,由paramiko和PyYAML两个关键模块构建.Ansible的编排引擎可以出色地完成配置管理,流程控制,资源部署等多方面工作.Ans ...

  5. Ansible基础入门

    1.1 Ansible是什么         随着移动互联.物联网.互联网+.大数据.云计算等大规模应用的催生推动,以及人们日常生活的互联网化,互联网的蓬勃发展不仅冲击影响着整个经济体,更对人们的生活 ...

  6. ansible基础配置

    1.基础配置 1.1.环境 主机配置 ansible版本:2.7.4 控制端:centos7.4,IP:192.168.1.213,主机名:operation 被控制端: centos6.5,IP:1 ...

  7. devops工具-Ansible基础

    一.Ansible介绍 简介 Ansible使用Python语言开发,是一个配置管理型工具,与之类似的工具还有Puppet.SaltStack.chef等,默认通过SSH协议进行远程命令执行或下发配置 ...

  8. 36: ansible基础 、 Ansible ad-hoc 、 总结和答疑

    Top NSD AUTOMATION DAY01 案例1:部署Ansible 案例2:Ansible ad-hoc应用一 案例3:Ansible ad-hoc应用二 案例4:Ansible ad-ho ...

  9. Ansible基础一Playbook(二)

    摘自:http://www.ansible.com.cn/docs/playbooks_intro.html Handlers: 在发生改变时执行的操作 (当发生改动时)'notify' action ...

最新文章

  1. SpringBoot 实战 (八) | 使用 Spring Data JPA 访问 Mysql 数据库
  2. CG CTF WEB GBK Injection
  3. 当前线程不在单线程单元中,因此无法实例化 ActiveX 控件“8856f961-340a-11d0-a96“...
  4. 【科学计数法模板讲解】1060 Are They Equal (25 分)
  5. 9.1定时器 小时分秒
  6. 学习教材《构建之法》遇到的问题及思路
  7. 腾讯云与智慧产业总裁汤道生:产业互联网是一场“持久战”
  8. iPhone 12开启5G续航锐减 苹果官方回应了!
  9. 第6章 循环结构程序设计
  10. 计算机本科生毕业设计题目(三)
  11. 简历模板...自行下载
  12. Restful风格的编程
  13. Docker容器 Dead 状态分析
  14. Java实现多线程远程投屏并打包可执行文件(从代码到.exe)
  15. 如何构建自己的知识体系
  16. c语言编程题总结,c语言编程题总结
  17. Win10 Build 14942 Edge浏览器闪退怎么解决?
  18. 视觉人工智能初识 OpenMMLab
  19. Android即时聊天系统设计
  20. 弱电工程LED显示屏日常维护方法

热门文章

  1. 【AMAD】splinter -- 用于测试web app的python框架
  2. Python 之 random模块
  3. python--常用模块:collections 、time、random
  4. ●BZOJ 2669 [cqoi2012]局部极小值
  5. 团队-爬虫豆瓣top250项目-项目进度
  6. [翻译] WPAttributedMarkup
  7. 噪声dba是什么单位_在职DBA : 工作多年为什么还是选择报读工商管理博士
  8. 配置apache服务器的文件名,apache服务器配置文件名是
  9. android 仿京东toolbar,仿京东商城系列2------自定义toolbar
  10. android 图片在哪里设置时间,android 按时间显示图片