我也只是SaltStack的初學者,若是文中有錯誤的地方,請不吝賜教。html
在學習的過程,我也作了很多實驗,犯了很多錯,積累了一些經驗,對SaltStack的運行也有必定了解,若是有什麼問題,或是不太理解的地方,很是歡迎留言交流!python
參考連接:官方文檔web
簡潔,簡潔,簡潔shell
衆多強大而有力的設計都創建在簡單的原則之上。Salt SLS系統也努力向K.I.S.S看齊。(Keep It Stupidly Simple)apache
SLS(表明SaLt State文件)是Salt State系統的核心。SLS描述了系統的目標狀態,由格式簡單的數據構成。這常常被稱做配置管理。django
Note 這篇文章從總體上介紹了Salt States,之後還會增長對各組件的深刻介紹。
深刻學習以前,明白SLS文件只是結構化的數據而已經是頗有用的。看懂和編寫SLS文件不須要理解這一點,但會讓你體會到SLS系統的強大。編程
SLS文件本質上只是一些dictionaries
,lists
,strings
和numbers
。這種設計讓SLS文件很是靈活,能夠知足開發者的各類需求,並且可讀性很高。寫得越多,就越清楚到底寫得是什麼。服務器
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行是要執行的function。這些function定義了名字爲ID的軟件包和服務的目標狀態。此例中,軟件包應當處於已安裝狀態,服務必須運行。
最後,第6行是關鍵字require。這被稱爲必要語句(Requisite),它確保了apache服務只有在成功安裝軟件包後纔會啓動。ssh
部署像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如何實現,不知道是否有這麼靈活。
在更有擴展性的部署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至關於把被引用的內容文件添加到自身。
擴展是什麼意思呢?好比在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的內容,而不是覆蓋。
由於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語法基礎上的描述語言。
關於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命令來收集數據。
在任務邏輯很是複雜時,默認的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渲染器,上面的例子會更簡潔:
python/django.sls:
#!pydsl include('python', delayed=True) state('django').pkg.installed()
若是用YAML,會是下面這個樣子:
include: - python django: pkg.installed
這也能夠看出,正常狀況下使用YAML是很是合適的,但若是有須要時,使用純粹的Python SLS能夠很是NB。
寫好的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
。