首页 运维干货Ansible之Playbook

Ansible之Playbook

运维派是国内成立最早的IT运维技术社区,欢迎关注公众号:yunweipai

Playbook简介

palybook 是由一个或多个paly组成的列表。play的主要功能在于将事先归并为一组的主机装扮成事先通过ansible 中的 task 定义好的角色。从根本上来讲,所谓 task 无非是调用 ansible 的一个 module。将多个 play组织在一个 playbook 中,即可以让它们联同起来按事先编排好的机制同唱一台大戏。

一个playbook由以下几个部分组成:

  • Inventory
  • Modules
  • Ad Hoc Commands
  • Playbooks
    • tasks:即调用模块完成的操作
    • variables:变量
    • templates:模板
    • handlers:触发器,由某子任务触发执行操作
    • roles:角色

Inventory

ansible的主要功能在于批量主机操作,为了便捷地使用其中的部分主机,可以在inventory file中将其分组命名。默认的inventory file为/etc/ansible/hosts

inventory文件遵循INI文件风格,中括号中的字符为组名。可以将同一个主机同时归并到多个不同的组中;此外,当如若目标主机使用了非默认的SSH端口,还可以在主机名称之后使用冒号加端口号来标明。

如果主机名称遵循相似的命名模式,还可以使用列表的方式标识各主机,例如:

inventory file 中也可以设置 变量 ,方便后期 ansible 执行调用。

上面配置中 http_port 就是自定义的变量。当然在组中也可以设置该组所有主机相同的变量:

注意:这里 webservers:vars 中 vars 是固定关键字写法。

Inventory 常用参数

这里只是列举常用参数:

Modules

ansible modules 有很多,之后会专门写一篇关于 modules 总结的文档。

Ad Hoc Commands

什么是 ad-hoc ?
当我们需要敲一些命令去快速的查看或者完成一项工作时,而不需要持久的存储这些命令,这样的命令就叫做 ad-hoc
ansible 就提供了两种方式去完成任务,一是 ad-hoc 命令,另一种是 ansible playbook ,前者可以解决一些简单的任务,后者解决较复杂的任务。
比如,当需要马上查看主机端口时,使用 ad-hoc 就是很高效的,
如:ansible [hostname] -m shell -a 'netstat -ntplu'

Playbook

playbook 核心元素:

  1. hosts:执行的远程主机列表
  2. tasks:任务集
  3. variables:内置变量或自定义变量在 playbook中使用
  4. notify 和 handlers 结合使用,由特定的条件触发操作,满足条件执行,否则不执行
  5. tags:标签,指定某条件执行,用于选择运行 playbook 中的部分代码

Playbook 语法

playbook 使用 yaml 语法格式,后缀为 yaml 也可以是 yml 要求及格式如下:

  1. 在单一一个playbook文件中,可以连续三个连子号(---)区分多个play。还有选择性的连续三个点好(...)用来表示play的结尾,也可省略。
  2. 次行开始正常写playbook的内容,一般都会写上描述该playbook的功能。
  3. 使用#号注释代码。
  4. 缩进必须统一,不能空格和tab混用。
  5. 缩进的级别也必须是一致的,同样的缩进代表同样的级别,程序判别配置的级别是通过缩进结合换行实现的。
  6. YAML文件内容和Linux系统大小写判断方式保持一致,是区分大小写的,k/v的值均需大小写敏感
  7. k/v的值可同行写也可以换行写。同行使用:分隔。
  8. v可以是个字符串,也可以是一个列表
  9. 一个完整的代码块功能需要最少元素包括 name: task

下面通过一个安装维护 httpd 服务来逐步引出 playbook中知识点

通过一个简单的示例查看 playbook 语法及格式:
首先在 /etc/ansible/hosts 中定义主机及主机组

编写 playbook 脚本:

前三行基本是固定格式:

  1. hosts: [hostname | groupname] 要执行任务的主机或主机组
  2. remote_user: [username] 在主机组中执行任务的用户名
  3. tasks: 所有需要执行的任务集

示例1:在 test_hosts 主机上安装 httpd 服务 然后启动服务。

上面的这个 playbook 就是安装 httpd 并启动服务,前三行是固定模式,在 tasks 中,每一个以 name 开头的就是一个小任务。所以 tasks中就是由一个一个小任务组成的。

Playbook 中的变量

如果要在 playbook 中使用变量,则需要 vars 关键字来定义:

这里定义了两个变量 package=httpd 和 service=httpd
在引用变量时,用两个大括号:{{ variable_name }}

执行 Playbook

编写好 playbook 后,就需要通过 ansible-playbook 执行,常用参数如下:

通常,直接使用 ansible-playbook apache.yml 执行:

执行 playbook 时

  1. 发现主机是否存在或连通
  2. 开始执行tasks 中的子任务

上面的 playbook中只有2个子任务,通过执行过程可以看出,ansible 在执行 playbook 时,是按照任务为中心的思想来执行的, 也就是 第一个任务,在所有的主机上执行完毕,然后在将第二个任务在所有主机上执行。其中 ok 表示每一步执行的是否成功,而 changed 则表示执行该playbook 被管理主机是否发生了更改,如果被管理主机没有发生更改则不会有 changed,再次执行该playbook:

因为第一次已经安装启动了, 再次执行 playbook 则不发生任何更改。
需求又来了, 要修改主机的 httpd 端口为 8080
思路:ansible 主机需要有一份 修改好端口的配置文件,将配置文件推送到被管理主机,然后重启服务。
修改如下:

copy: src=/root/conf/httpd.conf dest=/etc/httpd/conf/httpd.conf
/root/conf/httpd.conf 为 ansible 主机本地路径,在该配置文件中修改端口为: 8080 覆盖到被管理主机的 /etc/httpd/conf/httpd.conf
对比刚开始的 playbook 做了改动,加入了-name: copy configration file 并将 start httpd 修改为 restart 执行如下:

OK,执行没有任何问题,以后每次修改端口都可以直接在本地修改,然后执行下 playbook 推送再重启就好了,但是上面的写法并不完美。就算配置文件没有修改依然会重启服务,这是没有必要的。有没有一种方法,当修改了配置文件才重启服务, 如果没有修改则不重启呢?这就需要用到 notify + handlers 处理机制。

notify + handlers

Handlers 和 notify 结合使用,由特定条件触发的操作,满足条件才执行,否则不执行。这里需要满足的条件是,当配置文件修改,playbook 如下:

在 copy 下一行加入了 notify 然后在最后添加 handlers 注意格式!
修改配置文件:/root/conf/httpd.conf Listen:8000 然后执行 playbook

配置文件修改,在执行子任务时触发了 notify 定义触发器,执行了 restart ,再次执行 playbook 试试:

再次执行时,配置文件并没有发生任何变化,所以这里没有触发 restart httpd 这样比上面 每次执行都重启要智能很多了吧?但是依然不完美。每次执行 playbook 都会执行一些没必要的子任务,比如:TASK [install httpd] 和 TASK [start httpd] 这两个子任务在安装执行之后一般不会在用到了, 但是删除了又不能保证 playbook 的完整性,这时候就需要 tags 出马了。

Tags

tags 便签的意思,也就是为子任务打一个标签,然后就可以通过 ansible-playbook 执行打标签的部分,其他子任务不予执行,如下:

[name: copy configuration file] 子任务最后加入了 tags: updateConf ,然后修改配置文件 /root/conf/httpd.conf端口为 9090
通过 --list-tags 查看标签

通过 ansible-playbook apache.yml -t updateConf 执行打标签的子任务:

可以看到,所有子任务中,只是执行了 TASK [copy configuration file] 子任务,这样的 playbook 就趋近完美了。可以再次执行,再次执行时由于httpd.conf 没有发生修改,所以不会触发 restart httpd,如下:

总结一下:

  1. 通过上面的安装、维护 httpd 服务编写的 playbook 中,使用到了:
  2. 变量:通过 vars 关键字定义变量;
  3. notify + handlers 子任务触发器,触发执行,不触发则不执行;
  4. tags:标签,使用 ansible-playbook xxx.yml -t [tag_name] 只执行打标签的子任务,其他任务不予执行。

除了上面,还有一些功能也是非常使用的。

条件判断

很多文中这里都是 流程控制,我觉得用 条件判断 来定义更简单易懂。
playbook 中使用 when 关键字来进行条件判断,这里的 when 相当于 shell 中的 if ,它是 jinja2 的语法。
有这样一个需求:如果主机的 IP 为: 192.168.118.15 则打印它的主机名,实现如下:

有这样一个需求:如果主机的 IP 为: 192.168.118.15 则打印它的主机名,实现如下:

关键字: when 定义条件判断, 当 ip 为:192.168.118.15 的时候打印 主机的 fqdn 否则跳过,执行如下:

定义了两台主机,其中 node3 不满足条件, 则跳过 skip

循环

在playbook中使用循环的场景还是很多的, 比如安装一些 程序包,处理一堆文件,创建一批用户等。
playbook 中还有循环功能,关键字: item 和 with_items

需求:为 test_hosts 主机组创建一批新用户

item 为固定变量关键字,循环内容为 with_items 中的值,执行结果如下

reigster

在 playbook 中 task 之间 可以通过 register 接收结果并传递

执行结果:

通过上面的示例,可以观察出 子任务1通过 register获取到执行结果,在子任务2中通过 变量名 info 打印出来。这样的方式可以通过执行命令来判断结果是否是想要的结果。

原创作者:hukey
原创地址:https://www.cnblogs.com/hukey/p/13220448.html

本文链接:http://www.yunweipai.com/36323.html

网友评论comments

发表评论

电子邮件地址不会被公开。 必填项已用*标注

暂无评论

Copyright © 2012-2020 YUNWEIPAI.COM - 运维派
扫二维码
扫二维码
返回顶部