天天看點

自動化運維之saltstack(二)states深入了解

深入了解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      

運作和調試Salt States

繼續閱讀