Ansible如何使用CallBack插件分析Playbook执行性能
写在前面
- 和小伙伴们分享一些分析Ansible回调插件的笔记
- 一个好的剧本,执行起来会很是丝滑,良好的执行体验让你甚至感觉不到执行了很久,哈…
- Ansible提供了CallBack插件来处理playbook中的回调事件。我们可以通过回调插件分析剧本资源利用率、消耗时间,从而优化剧本。
- 博文涉及内容:
- 查看Callback插件以及插件说明
- 分析控制节点执行剧本CPU和内存的消耗
- 统计任务和角色剧本的执行时间
- 自定义一个callBack插件实现执行完剧本打开博客
- 食用方式
- 了解 Ansible 基础知识
- 理解不足小伙伴帮忙指正
一个好的剧本,执行起来会很是丝滑,良好的执行体验让你甚至感觉不到执行了很久,哈…。--------山河已无恙
对这方面感兴趣的小伙伴可以到官网看下:https://docs.ansible.com/ansible/2.8/plugins/callback.html
什么是Ansible Callback插件
关于回调插件,官网文档中这样讲,Ansible的回调插件可以在响应事件
时向 Ansible 添加新行为。默认情况下,回调插件控制在运行命令行程序时看到的大部分输出,但也可用于添加额外的输出、与其他工具集成以及将事件编组到存储后端。如有必要,也可以创建自定义回调插件
开发
的方式理解,
- 从细粒度编码角度理解,可以理解为钩子,回调函数,类比的话,类似后端JVM中的钩子进程,在JVM进程结束时运行的进程。处理一些资源释放。前端VUE的8个生命周期方法,从指令编译到数据加载、模板渲染,DOM挂载等不同时期都会触发对应的回调函数。(Ansible 的回调也同样基于剧本生命周期方法实现)
- 从粗粒度编程思想理解,类似面向切面编程(AOP),把代码的执行逻辑块之间的连接点看做是一个个切入点,把一些不重要,但是需要的东西做成切面,在必要时织入到逻辑块内。
运维
的方式理解:
类似Linux
开机,启动的第一个进程systemd要引导一些系统必要的启动项,当然内核版本不同,对应的启动规则不同,但是如果你配置的服务设置了开启自启,会在启动级别的target目录下建一个指向服务service文件的软连接,即服务一定是某个启动级别target的正向依赖。这里的配置开启自启的服务可以理解为我们给Ansible配置回调插件。
亦或者我们之前讲的 剧本中的任务控制指令pro_task和post_taks
,K8s中的 pod hook
,通过poststart和prestop
,配置在pod创建和死亡的回调处理等等。
那么在Ansible中通过CallBack
插件调整对各种事件的响应
来扩展 Ansible
。其中一些插件也会修改命令行工具
(如ansible-playbook 命令)的输出,以提供额外的信息。
不只是剧本可以使用,临时命令的方式也可以使用回调。感兴趣小伙伴可以看看官网
需要说明的是Ansible
附带的大多数回调默认情况下是禁用
的,需要在ansible.cfg
文件中列入白名单
才能正常工作,通过 callback_whitelist
指令在ansible.cfg
中启用这些插件,这里2.8和2.9的版本还有些区别。我们主要看下2.8的版本
ansible.cfg
的配置,下面的配置中,在插件白名单里添加了timer, profile_tasks, cgroup_perf_recap
这三个回调
[ defaults]
inventory=inventory
remote_user=devops
callback_whitelist=timer, profile_tasks, cgroup_perf_recap
使用ansible-doc -t callback -l
命令可以列出可用的插件
$ ansible-doc -t callback -l
actionable shows only items that need attention
aws_resource_actions summarizes all "resource:actions" completed
cgroup_memory_recap Profiles maximum memory usage of tasks and full execution using cgroups
cgroup_perf_recap Profiles system activity of tasks and full execution using cgroups
context_demo demo callback that adds play/task context
counter_enabled adds counters to the output items (tasks and hosts/task)
debug formatted stdout/stderr display
.....
.....
$
使用ansible-doc -t callback plugin-name
查看指定插件的文档:下面是我们查看的timer
这个插件
$ ansible-doc -t callback timer
> TIMER (/usr/lib/python3.6/site-packages/ansible/plugins/callback/timer.py)
This callback just adds total play duration to the play stats.
* This module is maintained by The Ansible Community
REQUIREMENTS: whitelist in configuration
CALLBACK_TYPE: aggregate
METADATA:
status:
- preview
supported_by: community
。。。。。。。。。
可以看到,这个插件用于将总的play
执行时间添加到当前play
的最后输出中。来简单看一下怎么实现的。
[root@foundation0 ~]# cat /usr/lib/python3.6/site-packages/ansible/plugins/callback/timer.py
# (c) 2017 Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
# Make coding more python3-ish
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
DOCUMENTATION = '''
callback: timer
callback_type: aggregate
requirements:
- whitelist in configuration
short_description: Adds time to play stats
version_added: "2.0"
description:
- This callback just adds total play duration to the play stats.
'''
from datetime import datetime
from ansible.plugins.callback import CallbackBase
class CallbackModule(CallbackBase):
"""
This callback module tells you how long your plays ran for.
"""
CALLBACK_VERSION = 2.0
CALLBACK_TYPE = 'aggregate'
CALLBACK_NAME = 'timer'
CALLBACK_NEEDS_WHITELIST = True
def __init__(self):
super(CallbackModule, self).__init__()
self.start_time = datetime.utcnow()
def days_hours_minutes_seconds(self, runtime):
minutes = (runtime.seconds // 60) % 60
r_seconds = runtime.seconds % 60
return runtime.days, runtime.seconds // 3600, minutes, r_seconds
def playbook_on_stats(self, stats):
self.v2_playbook_on_stats(stats)
def v2_playbook_on_stats(self, stats):
end_time = datetime.utcnow()
runtime = end_time - self.start_time
self._display.display("Playbook run took %s days, %s hours, %s minutes, %s seconds" % (self.days_hours_minutes_seconds(runtime)))
[root@foundation0 ~]#
逻辑很简单,我们可以看到CallbackModule继承了CallbackBase
,覆盖了需要回调的方法。
$ cat /usr/lib/python3.6/site-packages/ansible/plugins/callback/__init__.py | grep -A 2 playbook_on_stats
def playbook_on_stats(self, stats):
pass
--
def v2_playbook_on_stats(self, stats):
self.playbook_on_stats(stats)
playbook_on_stats
、v2_playbook_on_stats
,这两个方法中,后者是在play中分配对象的回调,前者用于在play结束时的回调。 看一下CallbackBase
的注释
$ cat /usr/lib/python3.6/site-packages/ansible/plugins/callback/__init__.py | grep -A 6 CallbackBase | tail -n 7
class CallbackBase(AnsiblePlugin):
'''
This is a base ansible callback class that does nothing. New callbacks should
use this class as a base and override any callback methods they wish to execute
custom actions.
'''
$
这是一个基本的ansible回调类,它什么都不做。新的回调使用这个类作为基类,重写他们希望执行的任何回调方法自定义操作。
如果需要编写一些自定义的回调插件,我们可以以同样的方法来尝试
下面来看看如何通过利用CallBack插件统计资源消耗
和执行时间
来分析Playbook的执行性能。
我们编写一个剧本用于测试,
$ cat tags.yaml
---
- name: tags Demo 1
hosts: servera
tags:
- play-tag-1
roles:
- role: tag_role
tags:
- role-tags
tasks:
- name: task 1 tag
shell: echo 'tags to task 1'
tags:
- task-tags-1
- name: include or import a tasks file
include_tasks:
file: tasks_file
tags:
- include-import
- block:
- name: task 1 in block
shell: echo 'task 1 in block'
- name: task 2 in block
shell: echo 'task 2 in block'
tags:
- block-tags
- name: tags Demo 2
hosts: servera
tags:
- play-tag-2
tasks:
- name: task 2 tag
shell: echo 'tags to task 2'
tags:
- task-tag-2
执行测试一下
$ ansible-playbook copy_task.yaml
PLAY [Deploy the w eb content on the web servers] ******************************************************************
TASK [copy demo] ***************************************************************************************************
ok: [servera]
ok: [serverc]
ok: [serverd]
ok: [serverf]
ok: [serverb]
ok: [servere]
PLAY RECAP *********************************************************************************************************
servera : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
serverb : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
serverc : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
serverd : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
servere : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
serverf : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Playbook run took 0 days, 0 hours, 0 minutes, 1 seconds
统计Playbook执行性能(控制节点 CPU 和内存)
cgroup_perf_recap
插件可以分析playbook
运行期间的控制节点性能。在playbook
执行结束时,它将显示全局摘要和每个任务的摘要。这些摘要包括 CPU 和内存消耗,以及在 playbook 和 tasks 执行期间启动的进程
的最大数量。
来看下插件文档,= is mandatory
修饰的变量为强制需要,所以我们还需要定义变量用于执行中那个控制组下执行
$ ansible-doc -t callback cgroup_perf_recap
> CGROUP_PERF_RECAP (/usr/lib/python3.6/site-packages/ansible/plugins/callback/cgroup_perf_recap.py)
This is an ansible callback plugin utilizes cgroups to profile system activity of
ansible and individual tasks, and display a recap at the end of the playbook
execution
* This module is maintained by The Ansible Community
OPTIONS (= is mandatory):
= control_group
Name of cgroups control group
set_via:
env:
- name: CGROUP_CONTROL_GROUP
ini:
- key: control_group
section: callback_cgroup_perf_recap
......
cgroup_perf_recap
CallBack插件依赖于 Linux 控制组(cgroup)
功能来监控和分析 ansible-playbook命令。
在 Linux 系统上,可以使用控制组来限制和监控一组进程可以消耗的资源,如内存或 CPU。若要设置这些限值,可以创建⼀个新组,设置限值,然后将进程添加到该组中。
需要安装cgcreate所在的安装包
$ sudo yum provides */cgcreate
Last metadata expiration check: 0:00:45 ago on Sun 14 Aug 2022 08:35:18 PM CST.
libcgroup-tools-0.41-19.el8.x86_64 : Command-line utility programs, services and daemons for libcgroup
Repo : rhel-8.0-for-x86_64-baseos-rpms
Matched from:
Filename : /usr/bin/cgcreate
$ yum -y install libcgroup-tools-0.41-19.el8.x86_64
使用 root 用户通过 cgcreate 命令创建专用控制组:
$ sudo cgcreate-a user:user-t user:user -g cpuacct,memory,pids:ansible_profile
$ sudo cgcreate -a student:student -t student:student -g cpuacct,memory,pids:ansible_profile
[sudo] password for student:
- -a 和 -t 选项显示可以访问和管理控制组的用户和组。
- -g 选项指定新控制组的名称
下一步,是在ansible.cfg
文件中启用插件:
[defaults]
inventory=inventory
remote_user=devops
roles_path=roles
gathering=explicit
forks=10
callback_whitelist = cgroup_perf_recap
[callback_cgroup_perf_recap]
control_group=ansible_profile
[privilege_escalation]
become=True
become_method=sudo
become_user=root
become_ask_pass=False
在新控制组中运行ansible-playbook
命令:
$ ansible-playbook tags.yaml
PLAY [tags Demo 1] ***************************************************************************************
TASK [tag_role : tags roles] *****************************************************************************
changed: [servera]
TASK [task 1 tag] ****************************************************************************************
changed: [servera]
TASK [include or import a tasks file] *******************************************************************
included: /home/student/DO447/labs/task-execution/tasks_file for servera
TASK [task 1] ********************************************************************************************
changed: [servera]
TASK [task 2] ********************************************************************************************
changed: [servera]
TASK [task 1 in block] ***********************************************************************************
changed: [servera]
TASK [task 2 in block] ***********************************************************************************
changed: [servera]
PLAY [tags Demo 2] ***************************************************************************************
TASK [task 2 tag] ****************************************************************************************
changed: [servera]
PLAY RECAP ***********************************************************************************************
servera : ok=8 changed=7 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
CGROUP PERF RECAP ****************************************************************************************
Memory Execution Maximum: 17.70MB
cpu Execution Maximum: 0.00%
pids Execution Maximum: 0.00
memory:
tag_role : tags roles (52540000-fa09-85ab-8a5c-000000000010): 17.70MB
task 1 tag (52540000-fa09-85ab-8a5c-000000000012): 17.70MB
include or import a tasks file (52540000-fa09-85ab-8a5c-000000000013): 17.70MB
task 1 (52540000-fa09-85ab-8a5c-000000000033): 17.70MB
task 2 (52540000-fa09-85ab-8a5c-000000000034): 17.70MB
task 1 in block (52540000-fa09-85ab-8a5c-000000000015): 17.70MB
task 2 in block (52540000-fa09-85ab-8a5c-000000000016): 17.70MB
task 2 tag (52540000-fa09-85ab-8a5c-000000000019): 17.70MB
cpu:
tag_role : tags roles (52540000-fa09-85ab-8a5c-000000000010): 0.00%
task 1 tag (52540000-fa09-85ab-8a5c-000000000012): 0.00%
include or import a tasks file (52540000-fa09-85ab-8a5c-000000000013): 0.00%
task 1 (52540000-fa09-85ab-8a5c-000000000033): 0.00%
task 2 (52540000-fa09-85ab-8a5c-000000000034): 0.00%
task 1 in block (52540000-fa09-85ab-8a5c-000000000015): 0.00%
task 2 in block (52540000-fa09-85ab-8a5c-000000000016): 0.00%
task 2 tag (52540000-fa09-85ab-8a5c-000000000019): 0.00%
pids:
tag_role : tags roles (52540000-fa09-85ab-8a5c-000000000010): 0.00
task 1 tag (52540000-fa09-85ab-8a5c-000000000012): 0.00
include or import a tasks file (52540000-fa09-85ab-8a5c-000000000013): 0.00
task 1 (52540000-fa09-85ab-8a5c-000000000033): 0.00
task 2 (52540000-fa09-85ab-8a5c-000000000034): 0.00
task 1 in block (52540000-fa09-85ab-8a5c-000000000015): 0.00
task 2 in block (52540000-fa09-85ab-8a5c-000000000016): 0.00
task 2 tag (52540000-fa09-85ab-8a5c-000000000019): 0.00
$
统计任务和角色阶段耗时
timer
、profile_tasks
和 profile_roles
CallBack插件可⽤于确定速度较慢的任务和角色。
timer
插件显示playbook
执行的持续时间。profile_tasks
添加每个任务的开始时间,并在 playbook 执行结束时显示每个任务所用的时间,按降序排列。profile_roles
在结束时显示每个角色所用的时间,按降序排列。
激活这些插件需要在ansible.cfg
文件中添加或更新callback_whitelist
指令:
[defaults]
inventory=inventory
remote_user=devops
roles_path=roles
gathering=explicit
forks=10
callback_whitelist = timer,profile_roles,profile_tasks
[privilege_escalation]
become=True
become_method=sudo
become_user=root
become_ask_pass=False
执行的输出:
$ ansible-playbook tags.yaml
PLAY [tags Demo 1] ***************************************************************************************
TASK [tag_role : tags roles] *****************************************************************************
Monday 15 August 2022 23:46:17 +0800 (0:00:00.021) 0:00:00.021 *********
Monday 15 August 2022 23:46:17 +0800 (0:00:00.021) 0:00:00.021 *********
changed: [servera]
TASK [task 1 tag] ****************************************************************************************
Monday 15 August 2022 23:46:18 +0800 (0:00:01.154) 0:00:01.176 *********
Monday 15 August 2022 23:46:18 +0800 (0:00:01.154) 0:00:01.176 *********
changed: [servera]
TASK [include or import a tasks file] *******************************************************************
Monday 15 August 2022 23:46:19 +0800 (0:00:00.341) 0:00:01.518 *********
Monday 15 August 2022 23:46:19 +0800 (0:00:00.341) 0:00:01.518 *********
included: /home/student/DO447/labs/task-execution/tasks_file for servera
TASK [task 1] ********************************************************************************************
Monday 15 August 2022 23:46:19 +0800 (0:00:00.018) 0:00:01.537 *********
Monday 15 August 2022 23:46:19 +0800 (0:00:00.019) 0:00:01.537 *********
changed: [servera]
TASK [task 2] ********************************************************************************************
Monday 15 August 2022 23:46:19 +0800 (0:00:00.333) 0:00:01.871 *********
Monday 15 August 2022 23:46:19 +0800 (0:00:00.333) 0:00:01.870 *********
changed: [servera]
TASK [task 1 in block] ***********************************************************************************
Monday 15 August 2022 23:46:19 +0800 (0:00:00.345) 0:00:02.216 *********
Monday 15 August 2022 23:46:19 +0800 (0:00:00.345) 0:00:02.216 *********
changed: [servera]
TASK [task 2 in block] ***********************************************************************************
Monday 15 August 2022 23:46:20 +0800 (0:00:00.332) 0:00:02.548 *********
Monday 15 August 2022 23:46:20 +0800 (0:00:00.332) 0:00:02.548 *********
changed: [servera]
PLAY [tags Demo 2] ***************************************************************************************
TASK [task 2 tag] ****************************************************************************************
Monday 15 August 2022 23:46:20 +0800 (0:00:00.344) 0:00:02.893 *********
Monday 15 August 2022 23:46:20 +0800 (0:00:00.344) 0:00:02.893 *********
changed: [servera]
PLAY RECAP ***********************************************************************************************
servera : ok=8 changed=7 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Monday 15 August 2022 23:46:20 +0800 (0:00:00.348) 0:00:03.241 *********
===============================================================================
shell ------------------------------------------------------------------- 2.05s
tag_role ---------------------------------------------------------------- 1.15s
include_tasks ----------------------------------------------------------- 0.02s
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
total ------------------------------------------------------------------- 3.22s
Monday 15 August 2022 23:46:20 +0800 (0:00:00.348) 0:00:03.241 *********
===============================================================================
tag_role : tags roles ----------------------------------------------------------------------------- 1.15s
task 2 tag ---------------------------------------------------------------------------------------- 0.35s
task 2 -------------------------------------------------------------------------------------------- 0.35s
task 2 in block ----------------------------------------------------------------------------------- 0.34s
task 1 tag ---------------------------------------------------------------------------------------- 0.34s
task 1 -------------------------------------------------------------------------------------------- 0.33s
task 1 in block ----------------------------------------------------------------------------------- 0.33s
include or import a tasks file ------------------------------------------------------------------- 0.02s
Playbook run took 0 days, 0 hours, 0 minutes, 3 seconds
$
我们可以在剧本输出中看到每个任务的执行时间。对于时间长的可以调整剧本优化,关于优化方式,小伙伴可以看看我之前的文章,关于其他的插件,小伙伴可以官网看看。具体的版本不同,插件使用方式略有差异。
自定义一个callBack插件
上面的都是社区或者官方的一些插件,下面我们看看如何自己编写一个插件
这里我们做一个简单Demo,所以这个插件的的功能就是在剧本执行完,在浏览器打开我的博客,…………
# -*- encoding: utf-8 -*-
"""
@File : disblog.py
@Time : 2022/09/01 00:09:06
@Author : Li Ruilong
@Version : 1.0
@Contact : 1224965096@qq.com
@Desc : ansible callback plugins
执行完剧本浏览器打开我的博客
"""
# here put the import lib
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
DOCUMENTATION = '''
callback: disblog
callback_type: aggregate
requirements:
- whitelist in configuration
short_description: 执行完剧本浏览器打开我的博客
version_added: "2.0"
description:
- 执行完剧本浏览器打开我的博客
'''
from datetime import datetime
import webbrowser
from ansible.plugins.callback import CallbackBase
class CallbackModule(CallbackBase):
"""
执行完剧本浏览器打开我的博客
"""
CALLBACK_VERSION = 2.0
CALLBACK_TYPE = 'aggregate'
CALLBACK_NAME = 'disblog'
CALLBACK_NEEDS_WHITELIST = True
def __init__(self):
super(CallbackModule, self).__init__()
def playbook_on_stats(self, stats):
webbrowser.open('https://liruilong.blog.csdn.net/');
放到:/usr/lib/python3.6/site-packages/ansible/plugins/callback/
目录下
我们可以通过命令查看插件
$ vim disblog.py
$ ansible-doc -t callback -l | grep disblog
disblog 执行完剧本浏览器打开我的博客
$ ansible-doc -t callback disblog
> DISBLOG (/usr/lib/python3.6/site-packages/ansible/plugins/callback/disblog.py)
执行完剧本浏览器打开我的博客
* This module is maintained by The Ansible Community
REQUIREMENTS: whitelist in configuration
CALLBACK_TYPE: aggregate
METADATA:
status:
- preview
supported_by: community
$
配置文件添加插件到白名单
[root@foundation0 resource_stat]# cat ansible.cfg
[defaults]
inventory = ./inventory
remote_user = devops
ask_pass = false
callback_whitelist = disblog
[privilege_escalation]
become = false
become_method = sudo
become_user = root
become_ask_pass = false
[root@foundation0 resource_stat]#
在剧本执行完后,直接打开了我的博客主页,当前这里需要考虑启动级别
博文参考
《Red Hat Ansible Engine 2.8 DO447》
- 点赞
- 收藏
- 关注作者
评论(0)