如何使用 Salt State?

關(guān)于,SaltStack 這個牛逼的配置管理神器,上周我寫了篇入門級的 《SaltStack 一日游》。

今天,深入點研究 SaltStack 中的精華部分:“Salt States”。

「Salt States」 翻譯成什么好呢?我想了半天,乳頭都快想破了。老外整的這些玩意翻譯成中文就不倫不類了,索性就按照字面意思 one by one 地譯成「鹽態(tài)」好了,蛤蛤~

注:“乳”字,在漢語中除了指“分泌奶水的器官、乳汁”等含義,還有“初生的、幼小的、小”的意思,除了“乳頭”,類似的例子還有:

  1. 我的乳名(小名)叫小明。
  2. 我家門前有條乳溝(小溝)。

今天,我就來講講「鹽態(tài)」到底是怎么回事。以下譯自: HOW DO I USE SALT STATES?

KISS

簡潔,簡潔,簡潔

眾多強(qiáng)大而有力的設(shè)計都建立在簡單的原則之上。Salt State 系統(tǒng)也努力向 K.I.S.S(Keep It Stupidly Simple) 看齊。

SLS(代表 SaLt State文件)是 Salt State 系統(tǒng)的核心。SLS描述了系統(tǒng)的目標(biāo)狀態(tài),由格式簡單的數(shù)據(jù)構(gòu)成,經(jīng)常被稱作配置管理。

只是數(shù)據(jù)而已

深入學(xué)習(xí)之前,明白 SLS文件只是結(jié)構(gòu)化的數(shù)據(jù)而已 是很有用的??炊途帉慡LS文件不需要理解這一點,但會讓你體會到SLS系統(tǒng)的強(qiáng)大。

SLS 文件本質(zhì)上只是一些 dictionaries,listsstringsnumbers。這種設(shè)計讓SLS文件非常靈活,可以滿足開發(fā)者的各種需求,而且可讀性很高。寫得越多,就越清楚到底寫得是什么。最終的結(jié)果是一個簡單易懂的系統(tǒng),它可以隨著開發(fā)者或管理者的需求而變化。

top 文件

下面的 sls 示例文件可以通過一個叫 top.sls 的文件來分派給主機(jī)執(zhí)行。這個文件的詳細(xì)信息可參考 here

默認(rèn)的數(shù)據(jù):YAML

Salt 默認(rèn)使用YAML 這種最簡單的序列化數(shù)據(jù)格式來表達(dá)SLS數(shù)據(jù)。

典型的SLS文件如下:

apache/init.sls:

apache:
   pkg.installed:[]
   service.running
     - require:
       - pkg: apache

這些數(shù)據(jù)確保名為apache的軟件包處于已安裝狀態(tài),服務(wù)進(jìn)程apache處于運行狀態(tài)。

這些數(shù)據(jù)簡潔,易于理解。下面簡單解釋一下:

  • 第 1 行是這段數(shù)據(jù)的ID,被稱作ID聲明。這個ID是將要執(zhí)行的這些命令的名字。
  • 第 2、3 行包含了要執(zhí)行的State 模塊方法,它的格式為<模塊名>.<方法名>。pkg.installed 使用系統(tǒng)本地的軟件包管理器管理將要安裝的軟件;service.running確保指定的服務(wù)必須運行。
  • 最后,是關(guān)鍵字require,它是必要語句 Requisite,確保了apache服務(wù)只有在成功安裝軟件包后才會啟動。

添加配置文件和用戶

部署像apache這樣的web服務(wù)器時,還需要添加其他的內(nèi)容。需要管理apache的配置文件,需要添加運行apache服務(wù)的用戶和組。

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大大擴(kuò)展了上面的例子,增加了配置、用戶、組,還有一個新的必要語句:watch。

添加 state 非常簡單:usergroup這兩個state添加在apache這個ID下,所以增加的usergroup名字都是apache。require語句確保了只有在apache這個group存在時才建立user,只有在apache這個package成功安裝后才會建立group。

接下來,service中的require語句換成了watch,從需要 1 個軟件包改為監(jiān)視 3 個state(分別是pkgfileuser)。watch語句和require很相似,都能保證被監(jiān)視或需要的state在自己之前執(zhí)行,但是watch還有其他作用。在被監(jiān)視的state發(fā)生變化時,定義watch語句的state會執(zhí)行自己的watcher函數(shù)。也就是說,更新軟件包、修改配置文件、修改apache用戶的uid都會觸發(fā)service statewatcher函數(shù)。在這個例子中,service statewatcher會重啟apache服務(wù)。

多個SLS文件

要想可擴(kuò)展性地部署 Salt State 系統(tǒng),將會用到不止一個 SLS 文件。上面的例子中只使用 1 個SLS文件,2 個或多個SLS文件可以結(jié)合形成State Tree。上面的例子還使用了一個奇怪的文件來源 salt://apache/httpd.conf,這個文件也必須要找的到。

SLS文件以一定的目錄結(jié)構(gòu)分布在master上;SLS和要下發(fā)到minion上的文件都只是普通文件。

上面例子中的文件在 Salt根目錄(/etc/salt/)下:

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:

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

注:在ssh/server.sls中,用了兩種不同的方式來表示用Salt管理一個文件。在ID/etc/ssh/sshd_config段中,直接使用file.managed作為state聲明,而在ID/etc/ssh/banner段中,使用file作為state聲明,附加一個managed屬性。兩種表示方法的含義與結(jié)果完全一樣,只是寫法不同。

現(xiàn)在 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添加到當(dāng)前文件中,所以可以requirewatchextend憋著急,下面馬上會講到)被引用的SLS中定義的內(nèi)容。

include語句使得state可以跨文件引用,使用include相當(dāng)于把被引用的內(nèi)容文件添加到自身。

注:你可能注意到有些 SLS 文件叫 init.sls,有些又不是,關(guān)于它的約定規(guī)則可以參考 States Tutorial

Extend:擴(kuò)展被引用的SLS數(shù)據(jù)

有的時候,SLS 文件需要擴(kuò)展,也許是 apache 服務(wù)需要監(jiān)聽另外一個文件,或者在某種特殊條件下,某個文件需要添加進(jìn)來。

在下面的例子中,第一個將添加一個自定義的 banner 文件到 ssh,第二個多添加一個watcherapache 以便引入mod_python。

ssh/custom-server.sls:

include:
  - ssh.server

extend:
  /etc/ssh/banner:
    file:
      - source: salt://ssh/custom-banner

python/mod_python.sls:

include:
  - apache

extend:
  apache:
    service:
      - watch:
        - pkg: mod_python

mod_python:
  pkg.installed

custom-server.sls 文件使用 extend 語法來覆蓋banner 的下載路徑文件,相當(dāng)于替換了banner的配置文件。

mod_python.sls 文件中, 添加了 mod_python,但是更關(guān)鍵的是 apache 服務(wù)擴(kuò)展成為它還要額外監(jiān)聽這個 mod_python 包。

Extend 使得 SLS更加靈活,在處理SLS時,會將其中的內(nèi)容解析成Python中的dict(當(dāng)然這個dict中會嵌套dictlist)。

  • 擴(kuò)展 apachewatch,相當(dāng)于往list里面 添加 一個元素。
  • 修改 banner 文件的下載路徑相當(dāng)于 修改 dict中的某個key對應(yīng)的值。

注:在使用 extend時,會添加 require/watch 的內(nèi)容,而不是覆蓋。

Render System:理解渲染系統(tǒng)

由于SLS僅僅是數(shù)據(jù),所以它不是一定得用YAML來表達(dá)。Salt默認(rèn)使用YAML,只是因為易學(xué)易用。只要有對應(yīng)的渲染器,SLS文件可以用任何方式表達(dá)。

注:Salt關(guān)心的是最終解析出來的數(shù)據(jù)結(jié)構(gòu),只要你的渲染器能夠按要求返回這個數(shù)據(jù)結(jié)構(gòu),它不關(guān)心你是如何編寫的。

Salt默認(rèn)使用yaml_jinja渲染器,yaml_jinja渲染器先用jinja2模板引擎處理SLS源文件,然后再調(diào)用YAML解析器。這種設(shè)計的好處是: 可以在SLS文件中使用所有的編程結(jié)構(gòu)。

jinja2能怎么用,這里就能怎么用。條件,循環(huán),Python代碼……神馬都可以

其他可用的渲染器還包括:yaml_mako,使用 Mako模板引擎;yaml_wempy,使用Wempy模板引擎;py,直接使用PythonSLS文件;pydsl,建立在Python語法基礎(chǔ)上的描述語言。

yaml_jinja: 默認(rèn)的渲染器

關(guān)于jinja模板引擎的使用請參考其 官方文檔

Salt在和渲染器工作時,已經(jīng)往里面?zhèn)鬟M(jìn)去了一些十分有用的數(shù)據(jù)。在基于模板引擎的渲染器里,可以從3個組件中獲取需要的數(shù)據(jù):salt,grainspilla。在模板文件中,可以用salt對象執(zhí)行任意的Salt function,使用grains訪問Grains數(shù)據(jù)。示例如下:

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中的條件結(jié)構(gòu),如果grains中的os表明minion的操作系統(tǒng)是Red Hat,那么Apache的軟件包名和服務(wù)名應(yīng)當(dāng)是httpd。

再來一個更niubility的例子,用到了jinja的循環(huán)結(jié)構(gòu),在設(shè)置 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的強(qiáng)大,多個for循環(huán)用來動態(tài)地檢測并掛載磁盤,多次使用salt對象(這里使用了cmd.run這個執(zhí)行模塊)執(zhí)行shell命令來收集數(shù)據(jù)。

簡單介紹Python和PyDSL渲染器

在任務(wù)邏輯非常復(fù)雜時,默認(rèn)的yaml_jinja渲染器不一定滿足要求,這時可以使用Python渲染器。

Normally a YAML renderer should be used for the majority of SLS files, but an SLS file set to use another renderer can be easily added to the tree.

正常情況下,YAML的渲染器應(yīng)該可以適用于絕大部分 SLS 文件,但是使用其他的渲染器的 SLS 文件同樣可以輕易地適配到 sls tree 中。

下面是一個非常簡單的基本Python SLS文件:

python/django.sls:

#!py

 def run():
     '''
     Install the django package
     '''
     return {'include': ['python'],
             'django': {'pkg': ['installed']}}

這個例子也很好理解,第 1 行告訴Salt不使用默認(rèn)的渲染器,而是用py。接著定義了函數(shù)run,這個函數(shù)的返回值必須符合Salt的要求,即HighState數(shù)據(jù)結(jié)構(gòu)。

如果換用pydsl渲染器,上面的例子會更簡潔:

python/django.sls:

#!pydsl

include('python', delayed=True)
state('django').pkg.installed()

如果用YAML,會是下面這個樣子:

include:
  - python

django:
  pkg.installed

這也可以看出,正常情況下使用YAML是非常合適的,但如果有需要時,使用純粹的Python SLS可以非常犀利地裝逼哦。

運行和調(diào)試 Salt States

寫好的SLS如何才能應(yīng)用到minion呢?

SaltStack中,遠(yuǎn)程執(zhí)行是一切的基礎(chǔ)。執(zhí)行命令salt '*' state.apply 會讓所有的minionmaster上來取走自己的SLS文件,然后在本地調(diào)用對應(yīng)的state模塊(user,pkg,service等,內(nèi)置的 state 模塊列表在 這里)來達(dá)到SLS描述的狀態(tài)。

如果這條命令只返回minion的主機(jī)名加一個':',多半是哪一個SLS文件有錯。如果minion是以服務(wù)進(jìn)程啟動,執(zhí)行命令:

salt-call state.aply -l debug

可以看到錯誤信息,便于調(diào)試。minion還可以直接在前臺以debug模式運行:

salt-minion -l debug

What's next?

這篇文章只是對 Salt States 的初步介紹,下一步請繼續(xù)閱讀 Pillar 部分,官方文檔 在此。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容