深入了解SLS的可以參考這篇博文:http://www.ituring.com.cn/article/42238?
個人覺得這篇文章翻譯的不錯,所以轉載過來。
Salt Sates 眾多強大而有力的涉及都是建立在簡單的原則之上。Salt SLS系統也是努力想K.I.S.S看齊。(Keep It Stupidly Simple)
SLS(代表Salt State文件)是Salt Sate系統的核心,SLS描述了系統的目標狀態,由格式簡單的數據構成。這經常被稱作配置管理。
只是數據而已
深入學習之前,明白SLS文件只是結構化的數據而已是很有用的,看懂和編寫SLS文件不需要理解這一點,但會讓你體會到SLS系統的強大。
SLSL文件本質上只是一些dictionaries,lists,strings和numbers。這種設計讓SLS文件非常靈活,可以滿足開發者的各種需求,而且可讀性很高,寫的越多,就越清楚到底寫的是什么。
默認的數據? -YAML
Salt默認使用能戰斗奧的最簡單的序列化數據格式----- YAML,來表達SLS數據。典型的SLS文件如下:
1 2 3 4 5 6 7 | apache: ?? pkg: ???? -?installed ?? service: ???? -?running ???? -?require: ?????? -?pkg:?apache |
這些數據確保名為Apache的軟件包處于已安裝狀態(如果不是,那么就安裝Apache),服務進程Apache處于運行狀態。這些數據簡潔易于理解。下面簡單解釋一下:
第1行 是這段數據的ID,被稱作ID聲明。這個ID是將要執行的這些命令的名字。
第2行和第4行表示State聲明的開始,使用了pkg和service這兩個states,pkg使用系統本地的軟件管理器管理將要安裝的軟件,service管理系統守護進程。
第3行和第5行是要執行的函數。這些函數定義了名字為ID的軟件包和服務的目標狀態。此例中,軟件包應當處于安裝狀態,服務必須運行。
最后,第6行是關鍵字require。這被稱為必要語句(Requisite),它確保了Apache服務只有在成功安裝軟件包后才會啟動。
添加配置文件和用戶
部署像Apache這樣的web服務器時,還需要添加其他的內容。需要管理Apache的配置文件,需要添加運行Apache服務的用戶和用戶組
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | apache: ??? pkg: ????? -?installed ??? service: ????? -?running ????? -? watch : ??????? -?pkg:?apache ??????? -? file :? /etc/httpd/conf/httpd .conf ??????? -?user:?apache ??? user.present: ????? -?uid:?87 ????? -?gid:?87 ????? -?home:? /var/www/html ????? -?shell:? /bin/nologin ????? -?require: ??????? -?group:?apache ??? group.present: ????? -?gid:?87 ????? -?require: ??????? -?pkg:?apache ? /etc/httpd/conf/httpd .conf: ??? file .managed: ????? -? source :?salt: //apache/httpd .conf ????? -?user:?root ????? -?group:?root ????? -?mode:?644 |
這個SLS大大擴展了上面的例子,增加了配置、用戶、組,還有一個新的必要語句:watch。
user和group這兩個state添加在Apache的ID下,所以增加的user和group名字都是Apache。require語句確保了只有在Apache這個group存在時才建立user,只有在Apache這個package成功安裝后才會建立group。
service中的require語句換成了watch,從需要1個軟件包改為監視3個state(分別是pkg、file和user)。watch語句和require很相似,都能保證被監視或者需要的state在自己之前被執行,但是watch還有其他作用。在被監視的state發生變化時,定義watch語句的state會被執行自己的watcher函數。也就是說,更新軟件包,修改配置文件,修改Apache用戶的uid都會觸發service state的watcher函數。在這個例子中,service state的watcher會重啟Apache服務。
1 2 3 4 | Note Salt的watcher概念非常有意思。Puppet中功能類似的是notify,也可以觸發服務重啟。Salt的watcher 非常靈活,watcher本質上是在state的代碼中定義的名為mod_watch()的函數,在這個函數中想做什么事 情完全就看你的需求了。我沒有仔細看Puppet的notify如何實現,不知道是否有這么靈活。 |
多個SLS文件
在更有擴展性的部署Salt State時,需要用到不止一個SLS文件。上面的例子中只使用了1個SLS文件,2個或者多個SLS文件可以結合形成State Tree。上面的例子還使用了一個奇怪的文件來源--salt://apache/httpd.conf,這個文件究竟在什么位置呢?
SLS文件一定是目錄結構哦分布在master上;SLS和要下發到minion上的文件都只是普通文件。
上面的例子中的文件再Salt的根目錄(見《SaltStack中的文件服務器》)分布如下:
apache/init.sls
apache/httpd.conf
httpd.conf只是Apache目錄下的一個普通文件,可以直接引用。使用多個SLS文件可以更加靈活方便,以SSH為例:
ssh/init.sls:
1 2 3 4 5 6 7 8 9 10 | openssh-client: ??? pkg.installed ? /etc/ssh/ssh_config : ??? file .managed: ????? -?user:?root ????? -?group:?root ????? -?mode:?644 ????? -? source :?salt: //ssh/ssh_config ????? -?require: ??????? -?pkg:?openssh-client |
ssh/server.sls
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | include: ??? -? ssh ? openssh-server: ??? pkg.installed ? sshd: ??? service.running: ????? -?require: ??????? -?pkg:?openssh-client ??????? -?pkg:?openssh-server ??????? -? file :? /etc/ssh/banner ??????? -? file :? /etc/ssh/sshd_config ? /etc/ssh/sshd_config : ??? file .managed: ????? -?user:?root ????? -?group:?root ????? -?mode:?644 ????? -? source :?salt: //ssh/sshd_config ????? -?require: ??????? -?pkg:?openssh-server ? /etc/ssh/banner : ??? file : ????? -?managed ????? -?user:?root ????? -?group:?root ????? -?mode:?644 ????? -? source :?salt: //ssh/banner ????? -?require: ??????? -?pkg:?openssh-server |
1 2 3 4 | Note在ssh/server.sls中,用了兩種不同的方式來表示用Salt管理一個文件。在ID為 /etc/ssh/sshd_config段中,直接使用file.managed作為state聲明,而在ID為/etc/ssh/banner段中, 使用file作為state聲明,附加一個managed屬性。兩種表示方法的含義與結果完全一樣,只是寫法不同。 現在State?Tree如下(有些被引用的文件沒有給出內容,不影響立即): |
1 2 3 4 5 6 7 | apache /init .sls apache /httpd .conf ssh /init .sls ssh /server .sls ssh /banner ssh /ssh_config ssh /sshd_config |
ssh/server.sls中使用了include語句。include將別的SLS添加到當前文件中,所以可以require或watch被引用的SLS中定義的內容,還可以extend其內容(馬上講到)。include語句使得state可以跨文件引用。使用include相當于把被引用的內容文件添加到自身。
擴展被引用的SLS數據 Extend
擴展是什么意思呢?比如在ssh/server.sls中定義了一個apache通用的服務器,現在要增加一個帶mod_python模塊的apache,不需要重頭寫新的SLS,直接include原來的server.sls,然后增加安裝mode_python的state,再在apache service的watch列表中增加mod_python即可。python/mod_python.sls內容如下:
1 2 3 4 5 6 7 8 9 | include: ??? -?apache ? extend: ??? apache: ????? service: ??????? -? watch : ????????? -?pkg:?mod_python ? mod_python: ??? pkg.installed |
這個例子中,先將apache目錄下的init.sls文件包含進來(在include一個目錄時,Salt會自動查找init.sls文件),然后擴展了ID為apache下的service state中的watch列表。
也可以在Extending中修改文件的下載位置。ssh/custom-server.sls:
1 2 3 4 5 6 | include: ??? -? ssh .server ? extend: ??? /etc/ssh/banner : ????? file : ??????? -? source :?salt: //ssh/custom-banner |
Extend使得Salt的SLS更加靈活。為什么SLS能夠做Extend呢?文章一開始最強調了,SLS中的文件僅僅是結構化的data而已,在處理SLS時,會將其中的內容解析成Python中的dict(當然這個dict中會嵌套dict和list)。修改apache watch的內容,相當于往list里面添加一個元素;修改banner文件的下載路徑相當于修改dict中的某個key對應的值。在extending時,會附加加require/watch的內容,而不是覆蓋。
理解渲染系統 Render System
因為SLS僅僅是data,所以不是非得用YAML來表達。Salt默認使用YAML,只是因為易學易用。只要有對應的renderer,SLS文件可以用任何方式表達(Salt關心的是最終解析出來的數據結構,只要你的renderer能夠按要求返回這個數據結構,Salt干嘛關心你如何書寫源文件呢?)。
Salt默認使用yaml_jinja渲染器。yaml_jinjia先用jinja2模板引擎處理SLS,然后再調用YAML解析器。這種設計的好處是,可以在SLS文件使用所有的編程結構(jinja2能怎么用,這里就能怎么用。條件,循環,Python代碼,什么都可以)。
其他可用的渲染器還包括:yaml_mako,使用Mako模板引擎;yaml_wempy,使用Wempy模板引擎;py,直接使用Python寫SLS文件;pydsl,建立在Python語法基礎上的描述語言。
簡單介紹默認的渲染器 —— yaml_jinja
關于jinja模板引擎的使用請參考其官方文檔
在基于模板引擎的渲染器里,可以從3個組件中獲取需要的數據:salt,grains和pilla。在模板文件中,可以用salt對象執行任意的Salt function,使用grains訪問Grains數據。示例如下:
apache/init.sls:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | apache: ??? pkg.installed: ????? {%? if ?grains[ 'os' ]?==? 'RedHat' %} ????? -?name:?httpd ????? {%?endif?%} ??? service.running: ????? {%? if ?grains[ 'os' ]?==? 'RedHat' %} ????? -?name:?httpd ????? {%?endif?%} ????? -? watch : ??????? -?pkg:?apache ??????? -? file :? /etc/httpd/conf/httpd .conf ??????? -?user:?apache ??? user.present: ????? -?uid:?87 ????? -?gid:?87 ????? -?home:? /var/www/html ????? -?shell:? /bin/nologin ????? -?require: ??????? -?group:?apache ??? group.present: ????? -?gid:?87 ????? -?require: ??????? -?pkg:?apache ? /etc/httpd/conf/httpd .conf: ??? file .managed: ????? -? source :?salt: //apache/httpd .conf ????? -?user:?root ????? -?group:?root ????? -?mode:?644 |
這個例子很容易理解,用到了jinja中的條件結構,如果grains中的os表明minion的操作系統是Red Hat,那么Apache的軟件包名和服務名應當是httpd。
再來一個更NB的例子,用到了jinja的循環結構,在設置MooseFs分布式chunkserver的模塊中:
moosefs/chunk.sls:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | include: ??? -?moosefs ? {%? for ?mnt? in ?salt[ 'cmd.run' ]( 'ls?/dev/data/moose*' ). split ()?%} ? /mnt/moose {{?mnt[-1]?}}: ??? mount .mounted: ????? -?device:?{{?mnt?}} ????? -?fstype:?xfs ????? -?mkmnt:?True ??? file .directory: ????? -?user:?mfs ????? -?group:?mfs ????? -?require: ??????? -?user:?mfs ??????? -?group:?mfs ? {%?endfor?%} ? '/etc/mfshdd.cfg' : ??? file .managed: ????? -? source :?salt: //moosefs/mfshdd .cfg ????? -?user:?root ????? -?group:?root ????? -?mode:?644 ????? -?template:?jinja ????? -?require: ??????? -?pkg:?mfs-chunkserver ? '/etc/mfschunkserver.cfg' : ??? file .managed: ????? -? source :?salt: //moosefs/mfschunkserver .cfg ????? -?user:?root ????? -?group:?root ????? -?mode:?644 ????? -?template:?jinja ????? -?require: ??????? -?pkg:?mfs-chunkserver ? mfs-chunkserver: ??? pkg: ????? -?installed ? mfschunkserver: ??? service: ????? -?running ????? -?require: ? {%? for ?mnt? in ?salt[ 'cmd.run' ]( 'ls?/dev/data/moose*' )?%} ??????? -? mount :? /mnt/moose {{?mnt[-1]?}} ??????? -? file :? /mnt/moose {{?mnt[-1]?}} ? {%?endfor?%} ??????? -? file :? /etc/mfschunkserver .cfg ??????? -? file :? /etc/mfshdd .cfg ??????? -? file :? /var/lib/mfs |
這個例子展示了jinja的強大,多個for循環用來動態地檢測并掛載磁盤,多次使用salt對象(這里使用了cmd.run這個執行模塊)執行shell命令來收集數據。
簡單介紹Python和PyDSL渲染器
在任務邏輯非常復雜時,默認的yaml_jinja渲染器不一定滿足要求,這時可以使用Python渲染器。如何在State tree中添加使用py渲染器的SLS文件呢?簡單。 一個非常簡單的基本Python SLS文件:
python/django.sls:
1 2 3 4 5 6 7 | #!py ? def?run(): ????? '' ' ????? Install?the?django?package ????? '' ' ????? return ?{ 'include' :?[ 'python' ], ????????????? 'django' :?{ 'pkg' :?[ 'installed' ]}} |
這個例子也很好理解,第1行告訴Salt不使用默認的渲染器,而是用py。接著定義了函數run,這個函數的返回值必須符合Salt的要求,即HighState數據結構(我接下來就寫關于HighState的文章,現在不必關心其細節,反正就是一個dict,key和value都有規定好的含義)。 如果換用pydsl渲染器,上面的例子會更簡潔:
python/django.sls:
1 2 3 | #!pydsl include( 'python' ,?delayed = True ) state( 'django' ).pkg.installed() |
如果用YAML,會是下面這個樣子:
1 2 3 4 | include: ?? -?python django: ?? pkg.installed |
這也可以看出,正常情況下使用YAML是非常合適的,但如果有需要時,使用純粹的Python SLS可以非常NB。
運行和調試Salt States
寫好的SLS如何才能應用到minion呢?在SaltStack中,遠程執行是一切的基礎。執行命令salt '*' state.highstate
會讓所有的minion到master上來取走自己的SLS定義,然后在本地調用對應的state module(user,pkg,service等)來達到SLS描述的狀態。如果這條命令只返回minion的主機名加一個':',多半是哪一個SLS文件有錯。如果minion是以服務進程啟動,執行命令salt-call state.highstate -l debug
可以看到錯誤信息,便于調試。minion還可以直接在前臺以debug模式運行:salt-minion -l debug
。