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