175SaltStack 运维通关手册--Salt 结果返回器及
Returners 返回器介绍
默认情况下,发送给 Salt minions 的命令的返回值将返回给 Salt master,但是我们还可以很多其它的方式来使用这份结果数据。
通过使用 Salt returner,可以将结果数据重定向到外部数据存储服务以做进一步的分析和归档。
Returners 从 Salt minions 中提取它们的配置信息,且仅支持在程序起动时加载一次配置信息。
Returners 接口允许将返回数据发送到可以接收数据的任何系统。 这意味着可以将返回数据发送到 Redis 服务器,MongoDB 服务器,MySQL 服务器或任何系统。
Salt 已经自带多个返回器供我们使用,下面是一个 Redis returner 配置方法。
我们需要先安装 redis 并启动。
使用 state 模块安装并启动 redis,编辑文件 /etc/salt/srv/salt/base/redis.sls,如果之前已经编辑,可以跳过。
redis:
pip.installed
redis-server:
pkg:
- installed
service.running:
- require:
- pkg: redis-server
然后执行:
salt '*' state.apply redis
完成 Redis 配置之后,我们要求 salt 的执行结果通过自带的 returner 写入到 Redis,最简单的方案是指定相关参数,命令如下:
salt '*' test.version --return redis --return_kwargs '{"db":"2", "host":"127.0.0.1"}'
命令中,我们通过 --return 指定的返回器,--return_kwargs 指定返回器的相关参数,执行后,我们可以使用 redis-cli 查看。
redis-cli
> SELECT 2
> KEYS *
image.png
如果不希望每次都指定参数或者执行返回器,可以写入到 /etc/salt/minion 配置文件中。示例如下:
# 指定返回器为 redis
return: redis
# 指定返回器参数
redis.db: "0"
redis.host: "127.0.0.1"
redis.port: 6379
另外,如果修改 minion 配置文件,需要重启才能生效。
自定义一个返回器
自定义一个 returner 将结果写入 redis。这个并非我们要重复造轮子,只是自定义的一个示例,方便大家按照示例开发符合自己需求的组件。
Returner 是一个 Python 模块,至少包含一个 return 方法。 可以包含其他可选功能,以支持使用 master_job_cache,在外部系统中存储作业结果以及 Event Returners 等功能。
returner 函数必须接受单个参数。 该参数包含来自被调用的 minion 函数的返回数据。 如果调用 minion 函数 test.version,则参数的值将是字典类型。
新建目录 /etc/salt/srv/salt/base/_returners/,然后新建文件示例 /etc/salt/srv/salt/base/_returners/myredis.py。
注意,自定义的返回器放在 file_roots 中的 _returners 目录下, file_roots 配置在 /etc/salt/master 中指定。
#coding: utf8
# 文件: /etc/salt/srv/salt/base/_returners/myredis.py
import redis
import json
import salt.utils.json
def returner(ret):
'''
将返回结果写入 Redis 中
'''
# 建立一个 redis 连接对象
serv = redis.Redis(
host='127.0.0.1',
port=6379,
db='0')
serv.set('Salt:%s:%s' % (ret['jid'],ret['id']), salt.utils.json.dumps(ret))
注意,返回器的工作流程是 Salt-master 将任务发送给 Salt-minion,Salt-minion 执行完成后调用返回器进行结果处理,所以生成环境中需要写入具体的远程服务器地址,当前环境为同一台服务器,所以使用了 127.0.0.1 地址。
当调用以下任何一个函数时,都将触发分发自定义 returners 的操作:
state.apply
saltutil.sync_returners
saltutil.sync_all
我们也可以手动同步分发自定义 returner 到 minion 服务器
salt '*' saltutil.sync_returners
# 或者
salt '*' saltutil.sync_all
image.png
执行
# --return 指定自定义的 returner
salt '*' test.ping --return myredis
如果不想每次都指定 --return,可在 /etc/salt/master 配置文件中添加:
return: myredis
然后进行同步操作 salt '*' saltutil.sync_all,这个无需重启 salt 进程。
现在我们看下是否有数据写入到 Redis:
使用方案
如果在命令行中使用 salt 进行服务器管理,返回器几乎没有太大作用,但如果使用 api 或者整合自动化运维平台的话,返回器可以用来持久化保存任务结果,方便后续任务回溯等操作。
Runners
Salt runners 是使用 salt-run 命令执行的便捷应用程序。
Salt runners 与 Salt 执行模块的工作方式类似,但是它们需要在 Salt master 节点本身而不是远程在 Salt minions 上执行。
Salt runner 可以是简单的客户调用,也可以是复杂的应用程序。
Salt runner 程序以类似于 Salt 执行模块的方式编写。 两者都是包含函数的 Python 模块,每个公共函数都是一个可以通过 salt-run 命令执行的 runner。
Salt runner 常见的使用模块
state 模块
state.orchestrate 执行编排任务
任务编排我们下一章专门去讲,现在简单做个示例。
新建文件:/etc/salt/srv/salt/base/test_orch.sls,
# 一个测试的 orch sls 文件
test.ping:
salt.function:
- tgt: "*"
执行
salt-run state.orchestrate test_orch
image.png
state.event 监听 Event
执行命令:
# 监听事件,按行读取并进行 jq 解析输出
salt-run state.event | while read -r tag data; do echo $tag; echo $data | jq --color-output .; done
然后打开一个新的终端发送一个测试事件:
salt '*' event.send '测试发送 Event 事件'
config.get 获取 master 配置项
salt-run config.get roster_file
salt-run config.get presence_events
image.png
manage.alived 返回 alive 状态的 minion
manage.down 返回已下线的 minion
manage.not_alived 返回不存活的 minion
manage.list_state 返回状态为存活的 minion
示例:
# 查看当前在线的 minion
salt-run manage.alived
# kill minion 进程
pkill salt-minion
# 查看当前下线的 minion,并删除对应的 key
salt-run manage.down removekeys=True
salt-key -L
image.png
# 启动 minion 进程
salt-minion -d -l info
# 接受密钥
salt-key -A -y
# 查看存活的 minion,并显示 ip
salt-run manage.list_state show_ip=True
image.png
jobs 管理模块我们下一章专门讲解
自定义 runner
我们需要修改 master 配置文件 /etc/salt/master,指定存放命令。
runner_dirs: ["/etc/salt/runners"]
创建文件夹 /etc/salt/runners,然后新建自定义 runner 的对应文件: /etc/salt/runners/up.py
#coding: utf8
# 如果 salt 在 python2 下运行,需要指定 coding
# 导入 salt 模块
import salt.client
def up():
'''
输出在线 minion 的版本
'''
client = salt.client.LocalClient(__opts__['conf_file'])
# 返回一个字典, {'www.sublimetext.com': '3002.2'}
minions = client.cmd('*', 'test.version', timeout=1)
for minion,result in minions.items():
print(minion, '\n\t\33[34m%s\33[0m' % result)
return '执行完成'
# 自定义 runnner 使用基本遵循 <文件名>.<函数> 的调用方式
salt-run up.up
image.png
Renderers 渲染器
Salt 状态系统通过从开发人员熟悉的常用数据类型(如列表,字典和字符串)收集信息来运行。
Salt Renderers 用于将输入数据从其编写的格式转换为 Python 的数据结构。
通过在 master/minion 配置文件中的 renderer 配置选项来指定默认渲染器,默认为 jinja|yaml。
根据输出的内容,渲染器分为两类:文本或数据。 唯一的例外是 pure python 渲染器,可以在多场景中使用。
文本渲染器返回文本数据,包括模板引擎,如 jinja,mako 和 genshi,以及 gpg 渲染器。 以下是所有文本渲染器:
jinja
py
数据渲染器返回一个 Python 的数据结构 (最典型的就是,一个字典数据),下面是所有的数据类型渲染器:
json
py
yaml
以下是使用 pure python 渲染器安装包的示例:
新建文件 /etc/salt/srv/salt/base/test_render_py.sls
#!py
# 执行时自动寻找 run 方法,所以这个必须存在
def run():
'''
调用了 python/python-libs.sls 文件,并安装 python3-wget
'''
return {
'include': ['python.python-libs'],
'python3-wget': {
'pkg.installed': [
{'version': '3.2-1'},
]
}
}
文件 /etc/salt/srv/salt/base/python/python-libs.sls 我们在第五章创建过,内容如下:
python-dateutil: pkg.installed
test_render_py.sls 与下面的常规方法在效果上相同:
# 常规方法
include:
- python.python-libs
python3-wget:
pkg.installed:
- version: "3.2-1"
我们执行测试一下。
cd /etc/salt/srv/salt/base/
salt '*' state.apply test_render_py
image.png
自定义渲染器
自定义渲染器必须是实现渲染功能的 Python 模块。 此函数必须实现三个位置参数:
data - 参数名称可以随意使用,参数值是提供给渲染器的输入。 saltenv sls 第一个参数是最重要的,也必须包含第二个和第三个,因为 Salt 需要将此信息传递给每个渲染器,即使它仅由模板渲染器使用。
编写渲染器,以便 data 参数可以接受字符串或类文件对象作为输入。
自定义渲染器应放在 salt://_renderers/ 中,以便它们可以同步到 minions。 运行以下任何一个命令时,会触发同步操作:
state.apply
saltutil.sync_renderers
saltutil.sync_all
任何已同步到 minion 的自定义渲染器(与 Salt 的默认渲染器之一有相同的名称)将取代具有相同名称的默认渲染器。
创建目录 /etc/salt/srv/salt/base/_renderers,然后创建示例文件:/etc/salt/srv/salt/base/_renderers/myrender.py:
import salt.utils.yaml
from salt.utils.yamlloader import SaltYamlSafeLoader
from salt.ext import six
def render(yaml_data, saltenv='', sls='', **kws):
if not isinstance(yaml_data, six.string_types):
yaml_data = yaml_data.read()
data = salt.utils.yaml.safe_load(yaml_data)
return data if data else {}
注意,我们自定义的这个渲染器并没有做什么工作,只是解析了 yaml 数据格式;实际工作中可以按自己的运维环境进行功能开发。
执行同步命令 salt '*' saltutil.sync_renderers:
image.png
编写一个使用自定义渲染器的 sls 文件,路径:/etc/salt/srv/salt/base/test_myrender.sls
#!myrender
# 第一行必须指定 render 渲染器
nginx:
pkg:
- installed
第一行指定了使用我们自定义的渲染器 myrender,由于我们的渲染器只是解析 yaml 数据格式,所以只需要按照标准 yaml 语法编写内容即可。
执行
salt '*' state.apply test_myrender
image.png
使用技巧
如果我们只是在命令行使用 salt,或者通过 api 进行一些管理操作,自定义渲染器几乎没有必要;但是如果整合 CMDB 进行配置管理,业务部署,自动化运维等功能,自定义渲染器可以进一步提升定制化操作的设计规划。
Salt Engines 引擎
Salt Engines,是长期运行的外部系统流程,其可以按需利用 Salt。
引擎可以访问 Salt 配置、执行模块和 runners 程序(__opts __,salt 和 runners)。
引擎在由 Salt 监视的单独进程中执行。 如果 Salt 引擎停止,它将自动重启。
引擎可以在 Salt master 和 Salt minions 上运行。
自定义 Salt Engines
自定义 salt 引擎必须包含 start 方法,示例如下
提前创建对应目录 mkdir /etc/salt/srv/salt/base/_engines/,然后创建文件:/etc/salt/srv/salt/base/_engines/eng_test.py:
# -*- coding: utf-8 -*-
'''
一个简单的 Salt 测试 Engine, 无实际功能
监听 Event 事件并将事件写入到 Redis
'''
# 导入 python 库
from __future__ import absolute_import, print_function, unicode_literals
import redis
import json
# 导入 salt 库
import salt.utils.event
import salt.utils.json
def event_bus_context(opts):
if opts['__role'] == 'master':
event_bus = salt.utils.event.get_master_event(
opts,
opts['sock_dir'],
listen=True)
else:
event_bus = salt.utils.event.get_event(
'minion',
transport=opts['transport'],
opts=opts,
sock_dir=opts['sock_dir'],
listen=True)
print('启动测试 Salt 引擎')
return event_bus
def start(host='127.0.0.1', port=6379, db=0, key_name='SaltEvent'):
'''
监听 Salt Event 并作出相关操作
'''
r = redis.Redis(host=host, port=port, db=db)
with event_bus_context(__opts__) as event_bus:
while True:
event = event_bus.get_event()
jevent = salt.utils.json.dumps(event)
if event:
r.rpush(key_name, json.dumps(jevent))
配置 Salt Engines
Salt 引擎配置在 Salt maste 或 Salt minion 配置中的 engines 顶级部分下。
现在修改 master 的配置文件 /etc/salt/master
# 指定自定义引擎的目录
engines_dirs:
- /etc/salt/srv/salt/base/_engines
engines:
- eng_test:
host: "127.0.0.1"
port: 6379
如上,我们配置使用自定义的 eng_test 引擎,并传入 host 和 port 两个参数
重启 salt master:
pkill salt-master
salt-master -d
发送一个事件信息 salt-call event.send 'myco/mytag/success' '{success: True, message: "参数 Salt Engines"}',然后我们去 Redis 中查看信息:
redis-cli
> KEYS *
> LRANGE SaltEvent 0 -1
image.png