深入了解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檔案如下:
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服務的使用者和使用者組
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服務。
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:
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
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
Note在ssh/server.sls中,用了兩種不同的方式來表示用Salt管理一個檔案。在ID為
/etc/ssh/sshd_config段中,直接使用file.managed作為state聲明,而在ID為/etc/ssh/banner段中,
使用file作為state聲明,附加一個managed屬性。兩種表示方法的含義與結果完全一樣,隻是寫法不同。
現在State Tree如下(有些被引用的檔案沒有給出内容,不影響立即):
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内容如下:
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:
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:
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:
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:
#!py
def run():
'''
Install the django package
'''
return {'include': ['python'],
'django': {'pkg': ['installed']}}
這個例子也很好了解,第1行告訴Salt不使用預設的渲染器,而是用py。接着定義了函數run,這個函數的傳回值必須符合Salt的要求,即HighState資料結構(我接下來就寫關于HighState的文章,現在不必關心其細節,反正就是一個dict,key和value都有規定好的含義)。
如果換用pydsl渲染器,上面的例子會更簡潔:
#!pydsl
include('python', delayed=True)
state('django').pkg.installed()
如果用YAML,會是下面這個樣子:
include:
- python
django:
pkg.installed