Salt状态管理

 

前言

上一篇文章概括性的介绍了Salt的用途和它的基本组成和实现原理,也深入的的介绍了Salt的命令编排和批量执行,但是对于状态管理只是简单的介绍了一下,因为状态管理是一个比较重要且常用的功能,单独的介绍状态管理会比较适合。本文将会首先介绍Salt状态管理的一些概念,然后会通过实例来演示Salt状态管理的使用,实例的演示基于Vagrant和Vagrant的Salt插件。

Salt状态管理的关键概念

状态树

在Salt中,所有的状态都是通过状态描述文件来定义的,而它们都存储在master节点(masterless情况除外)。Salt通过状态树定义了不同'环境'下状态描述文件的层次结构。如下图:

如上图所示,状态树由的根节点是master的配置文件/etc/salt/master,它通过'file_roots'配置项定义了不同环境下配置文件所存在的目录。‘环境’这个概念的主要是用于分门别类的存放不同用途的状态描述文件。例如,一个公司的服务器集群通常有不同的用途,大部分机器是用于线上环境,但是也还有一部分机器用于开发和测试。因为机器的用途不同,所以他们除了一些基础配置相同外,大部分配置是大相径庭的。Salt考虑到了这一点,他通过’环境‘将不同用途的状态描述文件隔离在不同的目录,然后通过base环境下的'top.sls'文件描述该环境下哪些minion应该处于哪种状态。base环境是默认的基础环境,它可以用于存放一些基础的状态描述文件,如每个机器都需要的ldap、ntp、监控等。其它环境的定义是可以按自己的需要自定义的,如上图,通常可以定义dev,qa和prod环境分别代表开发、测试和生产环境。

salt-master配置文件中的file_roots定义了环境,如下:

1
2
3
4
5
6
7
8
9
10
# Master file_roots configuration:
file_roots:
  base:
    - /srv/salt/base
  dev:
    - /srv/salt/dev
  qa:
    - /srv/salt/qa
  prod:
    - /srv/salt/prod

base环境下的'top.sls'文件描述该环境下哪些minion应该处于哪种状态,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
base:
  '*':
    - global
dev:
  'webserver*dev*':
    - webserver
  'db*dev*':
    - db
qa:
  'webserver*qa*':
    - webserver
  'db*qa*':
    - db
prod:
  'webserver*prod*':
    - webserver
  'db*prod*':
    - db

如上,集群中所有的minions都会使用/srv/salt/base/global.sls定义的状态;fqdn匹配'webserver*dev*'的minions的会使用/srv/salt/dev/webserver.sls所定义的状态,其它类似。Salt仍然是使用Targeting的功能来选取节点,所以选取的方式有很多种。

Salt中状态树拓扑结构的定义由salt-master配置文件中的'file_roots'和base环境下的top.sls文件组成。状态的具体定义是由存储在这些目录下的sls文件描述。

关于状态树的更多信息,请阅读:http://salt.readthedocs.org/en/latest/ref/states/top.html

状态描述文件

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
48
49
50
51
52
53
54
55
56
<Include Declaration>:
  - <Module Reference>
  - <Module Reference>
 
<Extend Declaration>:
  <ID Declaration>:
    [<overrides>]
 
 
# standard declaration
 
<ID Declaration>:
  <State Declaration>:
    - <Function>
    - <Function Arg>
    - <Function Arg>
    - <Function Arg>
    - <Name>: <name>
    - <Requisite Declaration>:
      - <Requisite Reference>
      - <Requisite Reference>
 
 
# inline function and names
 
<ID Declaration>:
  <State Declaration>.<Function>:
    - <Function Arg>
    - <Function Arg>
    - <Function Arg>
    - <Names>:
      - <name>
      - <name>
      - <name>
    - <Requisite Declaration>:
      - <Requisite Reference>
      - <Requisite Reference>
 
 
# multiple states for single id
 
<ID Declaration>:
  <State Declaration>:
    - <Function>
    - <Function Arg>
    - <Name>: <name>
    - <Requisite Declaration>:
      - <Requisite Reference>
  <State Declaration>:
    - <Function>
    - <Function Arg>
    - <Names>:
      - <name>
      - <name>
    - <Requisite Declaration>:
      - <Requisite Reference>

上表给出了一个比较完整的状态描述文件的结构,这是用yaml格式来描述的。Yaml格式和jinja2模板是Salt默认提供的状态文件描述格式,同时Salt也支持不同类型的描述文件,他们通过Render模块支持,例如xml等。在此,我们以默认的yaml格式进行介绍。

我们先看一个实际的例子,example.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
vim:          <ID Declaration>
  pkg:         <State Declaration>
    - installed    <Function>
 
salt:          <ID Declaration>
  pkg:          <State Declaration>
    - latest       <Function>
  service.running:    <State Declaration>.<Function>
    - require:            <Requisite Declaration>
      - file: /etc/salt/minion   <Requisite Reference>
      - pkg: salt           <Requisite Reference>
    - names:              <Names>
      - salt-master            <Name>
      - salt-minion            <Name>
    - watch:              <Requisite Declaration>
      - file: /etc/salt/minion    <Requisite Reference>
 
/etc/salt/minion:            <ID Declaration>
  file.managed:              <State Declaration>.<Function>
    - source: salt://salt/minion    <Function Arg>
    - user: root             <Function Arg>
    - group: root            <Function Arg>
    - mode: 644              <Function Arg>
    - require:               <Requisite Declaration>
      - pkg: salt              <Requisite Reference>

<ID Declaration>ID声明

在这个例子中首先通过<ID Declaration>定义了三个状态描述模块,他们分别是vim,salt和/etc/salt/minion。在<ID Declaration>下包含了<State Declaration><Function>等定义,这些定义具体描述了vim, salt和/etc/salt/minion这三个模块具体是由哪些状态组件组成,使用了状态组件的哪些功能和具体的参数,它们之间的依赖关系是什么。同时,如果<State Declaration>下没有定义<Name Declaration>或<Names Declaration>那么<ID Declaration>将会默认成为<State Declaration>下的Name参数。就如同下面两个状态描述是等价的,他们都定义了使用pkg这个状态组件将vim这个包处于安装状态。

1
2
3
vim:
  pkg:
    -installed

1
2
3
4
editor:
  pkg:
    - installed
    - name: vim

<ID Declaration>在整个状态树中必须是单一的,它是其它状态描述模块引用它的Key。如果在状态树中出现两个同名的<ID Declaration>,Salt只会识别第一个被加载的状态定义模块。

<Name Declaration>和<Names Declaration>声明

<Name Declaration>和<Names Declaration>都定义在<State Declaration>下,可以把它们看作是State下某个Function的参数,其中<Names Declaration>就是一个参数数组。如在salt中的service状态模块的描述中,就使用salt-mastre和salt-minion作为<Names Declaration>,定义了这两个服务处于安装状态。

这两个声明的使用可以解决一些实际中的问题,如避免ID冲突,缩短ID声明等,可参考:

http://salt.readthedocs.org/en/latest/ref/states/highstate.html#name-declaration

http://salt.readthedocs.org/en/latest/ref/states/highstate.html#names-declaration

<State Declaration>状态声明

状态声明下包含了功能<Function>、功能参数<Function Arg>、Name、Names和表示状态之间的关系的声明<Requisite Declaration>(状态之间的关系在后面一节介绍)。

其实从状态声明的数据结构,并结合上一篇文章说讲到的命令编排来看,我们可以隐约的察觉出salt的状态管理其实也是使用了由minions所提供的不同状态组件,就如同命令编排中不同的module。在状态描述文件中,通过使用<State Declaration>和<Function>指定了使用状态组件的某个函数,并将Function Arg, Name和Names传递到该函数执行。所以这也验证了Salt本质上是一个可批量执行的远程命令编排系统,它的其它扩展功能,包括状态管理也是基于这样一个系统构建。

Salt提供了这丰富的状态组件用于实现状态管理,如常见的包管理、服务管理、文件管理等,参考:http://docs.saltstack.com/ref/states/all/index.html

如本例中salt和vim模块都使用了pkg组件,并分别使用了latest和installed函数,这些我们都可以在该组件的文档中找到:

http://docs.saltstack.com/ref/states/all/salt.states.pkg.html#salt.states.pkg.installed

http://docs.saltstack.com/ref/states/all/salt.states.pkg.html#salt.states.pkg.latest

从文档的描述,我们可以知道installed函数保证了包处于安装状态,latest函数确保了包处于安装状态并且是最新的。

在知晓工作原理的前提下,我们可以很轻松的通过文档学习状态管理的使用,并且能自定义的扩展状态组件。

状态之间的关系

在Salt中,<Include Declaration>可以用于应用引用位于其它.sls文件下的<ID Declaration>,就如同c语言的inlcude语句一样。例如位于base环境中的一个sls文件:

1
2
3
4
5
6
7
8
9
10
11
12
include:
  - apache    # include /srv/salt/base/apache.sls
 
extend:
  apache:     # extend the descrpition of apache
    service:
      - watch:
        - file: mywebsite
 
mywebsite:
  file:
    - managed

这个文件首先用<Include Declaration>引用了apache这个状态文件,因为是位于base环境,所以实际引用的是/srv/salt/base/apache.sls文件。如果apache.sls文件位于/sav/salt/base/web/apache.sls,那么在include时应该指明是web.apache.

extend语句对apache的定义进行了扩展(apache.sls中已经对apache进行了定义),这个功能相当于c++中子类对父类进行扩展。

在这只要明确如果需要引用位于其它sls文件中的<ID Declaration>就必须先用include文件引用该sls文件。

除此之外,Salt还提供了7种<Requisite Declaration>,用于实现状态之间的依赖,它们分别是require, require_in, watch, watch_in, prereq, prereq_in, use。

require, require_in

require声明了本状态依赖于指定的状态,require_in声明了本状态被指定状态依赖。A require B <=> B require_in A。通过require指令,我们就可以指定一个状态收敛的顺序,如先安装vim再配置vim的配置文件。

1
2
3
4
5
6
7
8
vim:
  pkg.installed
 
/etc/vimrc:
  file.managed:
    - source: salt://edit/vimrc  # get from master's file server:/srv/salt/[env]/edit/vimrc
    - require:
      - pkg: vim

等价于

1
2
3
4
5
6
7
8
vim:
  pkg.installed:
    - require_in:
      - file: /etc/vimrc
 
/etc/vimrc:
  file.managed:
    - source: salt://edit/vimrc

watch, watch_in

watch和watch_in是require和require_in的扩展,唯一的区别是watch和watch_in会额外的调用状态组件中的mod_watch函数,如果状态组件没有提供该函数,那么它和require, require_in的行为完全一样。

如本节的第一个例子,通过include apache并扩展了对apache的定义,将service.runing的watch设置成了mywebsite。那么,mywebsite状态的改变将触发调用service的mod_watch函数,重启apache服务。

prereq, prereq_in

prereq, prereq_in同样是指明了本状态的执行依赖于指定的状态。但是与require不同的地方是,当A require B,那么状态的收敛顺序是,先B后A,如果B失败,A不会执行;当A prereq B时,系统先会用(test=True)去测试B状态是否会改变(B过程并未实际执行),如果B状态会改变,那么先执行A状态,再执行B状态,如果A执行失败,那么B就不执行了。prereq就是pre request的意思。

这两个声明通常用于分布式服务中,部署升级时先将服务从负载均衡中摘除,在进行代码升级。例如:

1
2
3
4
5
6
7
8
9
10
graceful-down:
  cmd.run:
    - name: service apache graceful
    - prereq:
      - file: site-code
 
site-code:
  file.recurse:
    - name: /opt/site_code
    - source: salt://site/code

当通过salt master代用更新了/opt/site_code下的代码文件时,salt-minion上的file组件会先对比本地的代码文件是否与master上的不一致,如果不一致说明site-code这个状态会变化,那么先执行graceful-down这个状态,apache在服务完当前的请求后会shutdown,如果前端的负载均衡器有心跳包检查机制,会自动将请求分发到其它的节点。这时在实际执行更新代码的操作,从master上的file server下载最新的site-code文件。

use

use声明可以简化配置,复用指定状态的配置。例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/etc/foo.conf:
  file.managed:
    - source: salt://foo.conf
    - template: jinja
    - mkdirs: True
    - user: apache
    - group: apache
    - mode: 755
 
/etc/bar.conf
  file.managed:
    - source: salt://bar.conf
    - use:
      - file: /etc/foo.conf

等价于

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/etc/foo.conf:
  file.managed:
    - source: salt://foo.conf
    - template: jinja
    - mkdirs: True
    - user: apache
    - group: apache
    - mode: 755
 
/etc/bar.conf
  file.managed:
    - source: salt://bar.conf
    - template: jinja
    - mkdirs: True
    - user: apache
    - group: apache
    - mode: 755

用模板动态生成的状态文件

Salt除了可以静态地描述状态文件,同时还支持动态生成的状态文件,使用者可以通过Jinja2模板并结合Grains或Pillar等功能,对状态文件进行编程,动态生成状态文件。

1
2
3
4
5
6
7
apache:
  pkg.installed:
    {% if grains['os'] == 'RedHat' %}
    - name: httpd
    {% elif grains['os'] == 'Ubuntu' %}
    - name: apache2
    {% endif %}

通过Grains提供的操作系统信息动态的指定pkg组件使用apache2或httpd安装包。

更详细内容请参考:

http://salt.readthedocs.org/en/latest/topics/tutorials/states_pt3.html

http://salt.readthedocs.org/en/latest/topics/tutorials/states_pt4.html

状态收敛的运行过程

Salt的状态管理由state模块完成,一个命令'salt '*' state.highstate'就会触发所有的minions进行状态收敛。整个过程大致如下:

  1. master通过命令'salt [Targeting] state.highstate'调用指定的minions的state模块的highstate函数;
  2. minion的state模块访问master的file server,通过top.sls的定义,file server会将minion所属环境下的状态文件和静态文件传输给minion;
  3. minion对状态文件进行编译,从highdata到lowdata,生成了具体的状态收敛顺序;
  4. minion中的state模块根据状态收敛的顺序执行该状态说指定的状态组件,如pkg, service, file等;
  5. minion中的state将执行结果返回给master;

实例:使用Vagrant和Salt配置开发环境

需求

  • 单节点
  • 安装vim并从git仓库中拉取配置文件
  • 使用ubuntu 12.04 64位操作系统
  • 整个过程全部自动化

实现步骤

  1. 安装virtualbox和vagrant
  2. 安装vagrant-salt插件,'$vagrant plugin install vagrant-salt';
  3. 参考salty-vagrant的手册,编写Vagrant配置文件;
  4. 参考本文内容编写Salt的配置文件;
  5. 运行'$vagrant up'构建开发环境;

全部文件:https://github.com/AlexYangYu/example-vagrant-salt

 
 

Salt状态管理的更多相关文章

  1. Ansible状态管理

     转载自:http://xdays.me/ansible状态管理.html 简介 就像所有服务器批量管理工具(puppet有DSL,salt有state)一样,ansible也有自己的状态管理组件 ...

  2. Linux Crontab及使用salt进行管理

    一.引言: 最近无意之间看到salt有一个cron的模块,今天就在这里介绍linux crontab以及通过salt的cron对crontab的管理. 二.Linux crontab的介绍: cron ...

  3. saltstack(五) saltstack的state状态管理

    一,YAML语法 首先先了解一下YAML,默认的SLS文件的renderer是YAML renderer.YAML是一个有很多强大特性的标记性语言.Salt使用了一个YAML的小型子集,映射非常常用的 ...

  4. Redux状态管理方法与实例

    状态管理是目前构建单页应用中不可或缺的一环,也是值得花时间学习的知识点.React官方推荐我们使用Redux来管理我们的React应用,同时也提供了Redux的文档来供我们学习,中文版地址为http: ...

  5. 表格搞定 Asp.net Web 状态管理

    最近在网上搜罗了 ASP.NET WEB 状态管理方面的一些内容,终于把这些内容整合总结了一下. 1. 希望自己通过整理,能够掌握一些,为自己投资. 2. 以便自己忘记,又要浪费时间搜罗. 3. 希望 ...

  6. [译]面向初学者的Asp.Net状态管理技术

    介绍 本文主要讲解Asp.Net应用程序中的状态管理技术(Asp.Net中有多种状态管理技术),并批判性地分析所有状态管理技术的优缺点. 背景 HTTP是无状态的协议.客户端发起一个请求,服务器响应完 ...

  7. [Asp.Net]状态管理(Session、Application、Cache)

    上篇博文介绍了在客户端状态管理的两种方式:http://www.cnblogs.com/wolf-sun/p/3329773.html.除了在客户端上保存状态外,还可以在服务器上保存状态.使用客户端的 ...

  8. [Asp.Net]状态管理(ViewState、Cookie)

    简介 HTTP协议是无状态的.从客户端到服务器的连接可以在每个请求之后关闭.但是一般需要把一些客户端信息从一个页面传送给另一个页面. 无状态的根本原因是:浏览器和服务器使用Socket通信,服务器将请 ...

  9. HttpClient_HttpClient 4.3.6 HTTP状态管理

    HTTP状态管理 最初的HTTP被设计成以状态.请求/应答为导向的协议,它被制作成是没有特殊条款的,以便在状态会话中能交换逻辑关系请求/应答.HTTP协议越来越受欢迎和被采用,越来越多的系统会在应用程 ...

随机推荐

  1. DevExpress XtraReports 入门三 创建 Master-Detail(主/从) 报表

    原文:DevExpress XtraReports 入门三 创建 Master-Detail(主/从) 报表 本文只是为了帮助初次接触或是需要DevExpress XtraReports报表的人群使用 ...

  2. three.js 来源目光(十三)Math/Ray.js

    商域无疆 (http://blog.csdn.net/omni360/) 本文遵循"署名-非商业用途-保持一致"创作公用协议 转载请保留此句:商域无疆 -  本博客专注于 敏捷开发 ...

  3. do...while(0)神奇

    1. do...while(0)消除goto语句. 通常,假设在一个函数中開始要分配一些资源.然后在中途运行过程中假设遇到错误则退出函数,当然,退出前先释放资源,我们的代码可能是这样: version ...

  4. Asp.Net实现FORM认证的一些使用技巧

    原文转发:http://www.cnblogs.com/Showshare/archive/2010/07/09/1772886.html 最近因为项目代码重构需要重新整理用户登录和权限控制的部分,现 ...

  5. 关于启动调试时,总是启动多个web端口的问题

    在一个解决方案中,经常包含多个web项目,当设置某一个web项目为起始项目后,启动调试,会发现其他的web项目的端口也会一起打开,显示在电脑的右下方,其实开启其他端口有时是没必要的,只是多占用了系统内 ...

  6. 分享一下我的部分毕设内容:基于Windows Phone平台的污染源管理应用

    原文:分享一下我的部分毕设内容:基于Windows Phone平台的污染源管理应用 毕业半年,又总结了一下之前的工作,发现很多知识不复习都忘记了.最近新闻总是报道北京的空气污染,各种雾霾,各种PM X ...

  7. 【百度地图API】如何制作一张魔兽地图!!——CS地图也可以,哈哈哈

    原文:[百度地图API]如何制作一张魔兽地图!!--CS地图也可以,哈哈哈 摘要: 你玩魔兽不?你知道如何做一张魔兽地图不?! 快来看此文吧! ---------------------------- ...

  8. Linux-常用命令1---对文件进行查看、复制、移动和分割

    基于Linux的操作系统是一种自由和开放源代码的类UNIX操作系统. Linux的几大特点决定了它的不可代替和无法超越性: (1)免费的/开源的:(2)支持多线程/多用户: (3)安全性好; (4)对 ...

  9. 浏览器扩展系列————异步可插入协议(pluggable protocol)的实现

    原文:浏览器扩展系列----异步可插入协议(pluggable protocol)的实现 IE中有很多我们比较熟悉的协议,如http,https,mailto,ftp等.当然你也可以实现自己定义的协议 ...

  10. OpenVPN多实例优化的思考过程

    1.sss 当构建组件之间的关系已经错综复杂到接近于一张全然图的时候,就要换一个思路了,或者你须要重构整个系统,或者你将又一次实现一个. 2.TAP网卡和TUN网卡 2.1.TAP的优势 1.方便组网 ...