nodegrouphtml
复杂的slsnode
自定义动态garinspython
salt的拓展web
salt的用户认证管理api
minion信息的集中获取服务器
自定义salt modules网络
nodegroupssh
salt的命令管理在对批量的机器进行操做(若是是单个的机器进行命令操做,ssh是最直接的方法)的时候才能更显示出他的部分强大。有时候咱们经过target进行各类匹配,虽然能够写的很强大,强大到咱们能够匹配出任何的知足咱们需求的节点,可是写这个target的时候,若是过于复杂就要花费稍微长点的时间,因此在这个时候nodegroup能够很知足咱们的需求,可是呢,直接写这个group分组也是很麻烦的,有没有更好的方法呢?分布式
前提:master支持部分配置的动态加载,好比nodegroup,实现的方式是动态的读取/etc/salt/master.d/*.conf内容,咱们只要去更新nodegroup中的内容就能够了ide
我这里有多个用户都会去操做(每一个用户管理的salt的机器不同)salt,而salt-master同一个配置只能加载一次,因此我只能去维护一个定义了nodegroup文件
实现方式:
每一个salt用户(在salt服务器上也是一个用户:普通用户)的~/groups文件夹中定义了一个个文件,每一个文件有一堆的minion ID列表,而后写个脚本去读取(~/groups)文件夹中的全部文件,而后生产跟文件名对应的group名
以下:
# ls ~/groups/
test1.txt test2.txt test3.txt
而后执行以下命令: (这个命令为本身实现)
[halfss@salt ~]# opstack update_groups
组更新完毕
组生成成功后:
[halfss@salt ~]$ salt -N test1 test.ping
minion1:
True
minion2:
True
minion3:
True
update_groups的代码大概(我线上部分调整后直接粘贴过来,未测试)以下:
def update_groups():
file_dir = '%s/groups' % os.path.expandvars('$HOME')
groups_re = '#%s_start\n.*\n#%s_end\n' % (user,user)
groups = ''
for group_file in os.listdir(file_dir):
if group_file.split('.')[-1] != 'txt':
continue
group_file = '%s/%s' % (file_dir,group_file)
servers = [ server[:1] for server file(group_file).readlines()]
groups += " %s: L@%s\n" % (group_file.split('/')[-1].split('.')[0],','.join(servers))
groups_tmp = '#%s_start\n%s#%s_end\n' % (user,groups,user)
nodegroups = file('/etc/salt/master.d/nodegroups.conf','r').read()
nodegroups,re_count = re.subn(r'%s' % groups_re, groups_tmp,node groups
if re_count == 0:
nodegroups += groups_tmp
file('/etc/salt/master.d/nodegroups.conf','w').write(nodegroups)
print "组更新完毕")
复杂的sls
有些时候默认的提供的sls的语法并不能知足实际需求,好在灵活强大的salt已经支持sls拓展(详情能够访问:http://docs.saltstack.com/topics/tutorials/starting_states.html )
能够直接写python代码,只要返回值相似yaml风格同样东西就OK
好比我要对节点的hosts中的某个域名作管理,找最近的IP去解析
实例以下:
import os
import re
def run():
hosts = [ #这里的IP是模拟IP
"192.168.1.2",
"10.0.0.1",
]
hosts_time = {}
for host in hosts:
cmd = "ping -c 4 %s" % host
content = os.popen(cmd).read()
use_time = re.findall(r'time=(.*)ms',content)
hosts_time[host] = sum([float(u) for u in use_time])
hosts_time = sorted(hosts_time.items(),key=lambda hosts_time:hosts_time[1])
ip = hosts_time[0][0]
dict = {
'download':{'host.present':[{'ip':ip,'names':['download.cn']}]}
}
return dict
salt会用yaml去解析返回的这个字典
自定义动态garins
salt中自定义的minion ID,通常遵照fqdn规范,以尽量他提供更多的信息方便管理员进行管理,可是fqdn不是万能的,不必定能包含须要的全部信息,这个时候自定义的grains就有用了
这里自定义了个grain,会根据一个URL返回的值生产一个字典,返回给salt解析
/srv/salt/_grains/ops_user.py
import urllib2
def ops_user():
grains = {}
ops_user = urllib2.urlopen('https://test.com/api/opsuser').read() #这里放回的是一个以逗号分割的字符串
ops_user = ops_user.split(',')
grains['ops_user'] = ops_user
return grains
if __name__ == '__main__':
print ops_user()
而后同步grains,以后全部的minion都会有和这个grain的属性了 saltutil.sync_grains
不过这里有一个小问题,这个granis是静态值,除非指定节点去刷新,不然grains不会改变
salt的拓展
salt的master和minion的交互很大程度上都和网络有关系,好比在管理多个国家的机器的时候(好比大中华局域网),这个时候,用一个master来管理,先不说体验上的问题,自己就是不现实的,这个时候怎么搞呢? 分布式
一个master控制多个master,同时被控制的master又能够控制不少的minion
这个时候我们的问题就好处理的多了,固然不能说彻底没有问题
中心master
指定开启syndic模式,这样消息才能发送到syndic节点上
# grep order_masters /etc/salt/master
order_masters: True
指定为中心master节点,启动syndic服务
被管理的master
# grep syndic_master /etc/salt/master
syndic_master: salt.lightcloud.cn
/etc/init.d/salt-syndic start
好比总的master为master,syndic节点为syndic1
将minion1的master制定为syndic,启动minion服务
而后在syndic1节点就能够看到未接受的key,接受后,syndic就能够管理minion1了,同时master也能够管理minion1了
问题:key的管理这块,仍是仅仅minoin直接链接的节点才能够管理,也就是说刚才minion1的接受key的那个操做,只有在syndic1才能够完成,master是不行的
salt的用户认证管理
在salt服务器上能够用root来管理全部的minions,使用全部的功能,可是实际生产环境中,机器有不少,不是全部的人都要管理这些机器,就须要把这些机器分给不一样的用户进行管理,这里可使用salt的external_auth模块来作处理
官方文档:http://docs.saltstack.com/topics/eauth/index.html
官方的例子中写的很清晰,好比master配置文件中以下的配置
external_auth: #制定启用认证模块
pam: #指定所使用的认证模块,还有其余的认证模块可使用好比ldap
thatch: #指定用户名(master服务器的系统用户名)
- 'web*': #指定匹配的minion 这里有点操蛋的是,不能使用compund模式
- test.* #这里指定了可使用那些模块,后面是并列的
- network.*
steve:
- .*
这里的这个用户thatch,能够对minion id中以web开头的使用test和network模块的全部功能,而steve这个用户就NB了,能够管理全部的minion,并且可使用说有的功能
若是在长期业务固化的系统中,这样的设定原本没什么问题,可是在业务快速迭代的系统中,业务会总是变来变去业务的负责人也一样会变来编曲,可是业务的主机名不会常常变化,这样的设定就会有问题,我的认为最好的解决方案应该是基于minion的某些属性来设定权限(能够动态的去管理这些属性);这样在业务变化的时候让这些属性也动态的去变化,权限也就动态的变化了
但是默认的salt不支持这样的功能(已经跟官方反馈,我的认为这个功能在不久的未来会加上);本身也不能干等着,因而我就个全部的minion加另外一个ops_user的属性(方法参考: 自定义动态garins),这里定义完了,怎么用呢?调整external的用户认证以下:
external_auth:
pam:
halfss:
- '*':
- '*'
halfss1:
- '*':
- '*'
这里咱们看到了,我给了这2个用户halfss halfss1全部机器的全部权限,若是这样设置的是,基本上对minion的权限管理是废了,可是还有一步,调整下salt的一段代码,以下:
调整用户权限:
/usr/lib/python2.6/site-packages/salt
diff client.py client.py_back
969,971d968
< if self.salt_user != 'root':
< tgt = '%s and G@ops_user:%s' % (tgt,self.salt_user)
< expr_form = 'compound'
979a977
>
这样普通用户即便在执行 salt '*' test.ping 的时候也会成功,并且仅仅是有他权限的机器执行,这样我就完成了对minion动态的分配权限.并且还带来一个好处是,普通用户的体验会更好一些,在官方的代码中,若是普通用户没有全部机器的权限,那么他直接这样执行是会报错的,官方代码中(即便是普通用户),"*" 理解为salt-master中的全部minion,而不是改用户的全部minon(这个跟他的广播机制有关) 这个功能也已经跟官方反馈,他会在0.16中实现这个功能
minion信息的集中获取
master默认会将minion是信息(pillar和grains)存储在/var/cache/salt/master/minions/下(以minoin id建立一个目录,该目录下有个data.p的文件);这样的方式并不便于minoin信息是采集与管理(若是有不少的机器,而后获取全部机器的minion信息的时慢的要死,固然这个不能怪salt);咱们能够把这些信息都放到一个文件中,便于信息的采集与管理,这里提供对信息统一收集的基础代码,以下:
获取minion的grain及pillar
/usr/lib/python2.6/site-packages/salt/master.py
cdir = os.path.join(self.opts['cachedir'], 'minions', load['id'])
if not os.path.isdir(cdir):
os.makedirs(cdir)
datap = os.path.join(cdir, 'data.p')
+ file('/var/log/salt/minions','w+').write(str({
+ 'minion_id':load['id'],
+ 'grains': load['grains'],
+ 'pillar': data})+'\n')
with salt.utils.fopen(datap, 'w+') as fp_:
fp_.write(
self.serial.dumps(
{'grains': load['grains'],
自定义salt modules
salt中自定义modules,实在是太简单了,为了让你详细,先来个最简单的
# cat /srv/salt/_modules/custom.py
def test():
return 'i am test'
同步到全部minion
# salt '*' saltutil.sync_modules
直接就可使用了
[root@localhost _modules]# salt '*' custom.test #调用方法,文件名.方法名
minion1:
i am test
这个是最简单的;可是有时候,咱们须要实现一些比较复杂的功能,而这些功能有的salt已经帮咱们实现了,咱们仅仅须要直接拿来用就行了;还有的咱们须要使用minion的中grains或者pillar的信息;在有其余的功能,咱们就须要本身是实现了,先看看刚才的2个怎么搞
1. 调用先有的module来显现自定义module中须要的功能
salt salt内置的一个字典,包含了全部的salt的moudle
[root@localhost _modules]# cat /srv/salt/_modules/custom.py
def test(cmd):
return __salt__['cmd.run'](cmd)
[root@localhost _modules]# salt '*' custom.test ls
minion1:
'
anaconda-ks.cfg
install.log
install.log.syslog
match.py
salt
test.py
是否是有点想一想不到的简单?
2. 使用gains中信息
[root@localhost _modules]# cat /srv/salt/_modules/custom.py
def test():
return __grains__['id']
[root@localhost _modules]# salt '*' custom.test
minion1:
minion1
将自定义的modules文件放在配置文件中定义的file_roots(默认为/srv/salt)下的 _modules目录下,会在执行highstate的时候自动同步,或者按照以下方式,手工推送
salt '*' saltutil.sync_modules 或者 salt '*' saltutil.sync_all