module,grains,pillar_saltstack

http://www.sudops.com/another-tools-for-sa-of-saltstack.html

 

SaltStack是一个新的基础平台管理工具。很短的时间即可运行并使用起来, 扩展性足以支撑管理上万台服务器,数秒钟即可完成数据传递. 经常被描述为 Func加强版+Puppet精简版。

对系统工程师来说,配置管理已经向前跃进了一大步. 系统配置的自动化不仅可预测,可重复, 还具有可管理性. 配置管理工具通常使用版本控制化的配置模板来描述基础设施的目标状态。凭借版本控制化的配置,可以将环境回滚(或前滚)到前面(或后序)状态;环境配置文件的自动化管理也是持续性交付管道的必要特性。

CFEngine, Puppet和Chef(按年龄降序)是开源领域流行的配置管理工具。 我是一个Puppet的长期用户, 与自定义的配置脚本相比,它在系统自动化的组织性和可靠性方面带来了巨大的提升。(我是在2009年作出这一次飞跃,与此相比, 以前的日子简直是混乱不堪…).

虽然配置管理工具精于描述并达到想要的状态, 但并不擅长动态地查询或设置状态. 这一点在状态资源还没有被纳入配置管理时特别明显。Llinux系统管理员的传统解决办法是ssh循环登陆节点列表并执行一堆命令。这不仅容易出错, 且每一次循环都要打开新的ssh会话,效率低下。想像一下要在1000台机器上顺序执行命令!更不用说网络安全,ssh密钥和命令执行权限的问题。这当然是一种可行的办法,但缺少一种可管理的框架。

这就是命令编排工具产生的原因。这些工具旨在大量的节点上并行执行命令和实时操作。CFEngine, Puppet和Chef各自用不同的方法来解决命令编排问题。Puppet使用MCollective作为其武器,并将其集成到商业版中。

近来,我开始探索使用SaltStack来解决配置管理和命令编排这两个问题。SaltStack开始于2011年,是一个相对较新的项目,但在系统管理员和DevOps工程师中拥有越来越多的粉丝。我将在本文中探讨Salt作为前途光明的替代者,并与Puppet作比较以探索其特性。

安装

创世之初,满是空白和无序,黑暗笼罩着整个系统……然后神安装了配置管理器,于是阳光普照!唯一的麻烦是,我们还需要安装依赖……然后配置管理器本身还得被配置……并且有时事情会有那么一点丑陋。

Salt在Ubuntu和CentOS上的安装过程异常简单,我相信在有安装指南的别的系统也一样 (Arch Linux, Debian, Fedora, RedHat, CentOS, FreeBSD, Gentoo, Windows, Solaris). YMMV. 典型安装过程隐藏了不必要的细节配置,除非你需要修改他们。首先安装salt master,然后安装salt minions, 将minions指向master,安装完成。如果salt master的主机名是”salt”,都不需要将minions指向master,直接就可以运行。

然而, 如果你不是使用上面提到的发行版或操作系统, 你很可能需要卷起袖子自己手动安装一些依赖。包括Python (>= 2.6 < 3.0), ZeroMQ, pyzmq, PyCrypto, msgpack-python和YAML的Python绑定.

另一方面, Puppet在多数基础安装时只依赖Ruby和Facter, 依赖带来的麻烦显著减少. 然而,Puppet的依赖列表可以进一步增加,包括augeas-libs, dmidecode, hiera, libselinux-ruby, pciutils, ruby-augeas, ruby-irb, ruby-rdoc, rubygem-json, ruby-shadow, rubygems. 这取决于Puppet的版本和你想要使用的功能。

我喜欢Salt包安装的简单明了。For the cases mentioned it is trivial to set up and get going. 如果你想亲自安装和配置的繁过程, 跟着安装指南做即可。

If you are like me though and you prefer your provisioning and configuration all in one gift wrapped package, que Vagrant to the rescue and download this project by elasticdog on github.

配置管理

配置状态

配置管理对Puppet来说是小菜一叠,对Salt又如何呢。让我(高兴的)惊讶的是,这件事简单到令人发指。和Puppet一样,在Salt中可以描述系统的目标状态。. Salt将其称之为一个state, 配置模块是state模块。Salt的State模块文件用YAML写成,以.sls结尾。它们从功能上等同于Puppet模块的manifest文件,后者用Puppet DSL写成,以.pp结尾。

Salt在master的配置文件中指定"file roots", 类似于Puppet的"module path", 但同时包含了模块根目录和环境类型。举例来说,在Salt中我们可以分别指定development和test环境配置文件路径. 注意base环境是必须存在的。

 

 

base环境必须包含Salt的入口top文件(叫做top.sls).base定义了一个或多个环境,用正则来匹配节点,然后引用相应的Salt states. top文件与Puppet的nodes文件相似。(Puppet入口点是site文件,在Salt中不需要).

假设有一个Salt master和两个minions (由Elasticdog github提供),我想要在两个minions上安装mongodb。如果在默认的软件仓库中有mongodb包,只需要3步即可。

1, 在top.sls中指定节点。

 

 

2, 在dev/mongodb.sls中描述状态:

 

 

3, 传递状态到salt minions:

 

 

配置描述文件与Puppet非常相似。但格式差别很大。这是因为Puppet使用自己的ruby-like DSL, 而Salt使用YAML. 正是由于这点不同,造就了Salt state配置文件在视觉上的简洁性。YAML对人类可读也容易被映射到数据结构, 非常适合做配置管理中的资源描述。这不是说Puppet DSL不清晰或不结构化- it is neither - 但很难胜过YAML. YAML可以快速写成,在我的经验看,比Puppet DSL要容易生成.

注意: 配置管理社区关于声明配置的最佳方式一直存在争论。部分人青睐于利用编程语言(比如说Ruby)的灵活性。Chef是其中的代表。Puppet处于中间地段。当使用现成的功能时,Puppet DSL非常强大。但要给配置开发者更大的能力,就必须使用内部的Ruby DSL。在波谱的另一端,Salt的简单YAML状态描述非常结构化。然而,Salt也支持渲染诸如JSON, Mako, Wempy和Jinja来扩展其能力, 在将来还会支持XML,原生Python及其他。

内置的state模块

我知道Salt是比Puppet近的项目, 我完全可以预料到不会有太多可用的内置模块。我错了: Salt有大量的内置模块,包含Puppet中的大部分必要模块比如 cron, exec (Salt是cmd), file, group, host, mount, package (Salt中是pkg), service, ssh_authorized_key (Salt是ssh_auth)和user。

尽管如此, Puppet仍然具有部分优势。比如, 我非常喜欢Puppet的Augeas模块。Augeas把内容当作value树,允许你修改(而不是覆盖)一个已存在的配置文件。

虽然Salt有一个Augeas execution模块,但很不幸貌似没有Augeas的state模块。虽然这样,Salt也有一些自己特有的东西,比如针对git, hg和svn的内置state模块.

模板

Puppet具有开盒即用的模板系统。Puppet有file资源和template资源的概念,这些资源分布在模块目录结构的不同路径下。在Salt中, files和templates在同一个位置。通过为template指令指定type来区分是template还是普通文件资源, type可以是jinja, mako或wempy。好处是可以很容易为file资源增加逻辑。state文件可能看起来像下面这样:

 

 

注意最后一行, 指明被管理的文件是一个jinja模板。

配置文件可以使用jinja的语法来增加逻辑。举例来说, 假设你的应用程序配置文件中用到了主机名。再假设在Ubuntuh 只需要短主机名(hostname),在CentOS需要FQDN。这可以很容易地在模板文件myapp.conf中指定:

 

 

在CentOS节点minion1上结果文件/etc/myapp.conf将包含以下内容

 

 

变量

Salt中的全局变量不能在使用时定义。在对变量的支持方面Puppet更加直观和灵活。在Salt中, 所有的变量保存在单独的位置。这样做不够灵活,但优势是更有秩序。用Salt的话讲,变量叫做"pillars"。pillars的位置在salt master的配置文件中指定:

 

 

和state文件一样, 首先创建一个top文件,在其中可以引用相关的pillar模块。

 

 

这个top文件引用了名为packages.sls的state文件, 其中包含将要安装的软件包的版本号的变量,如下所示:

 

 

声明了两个pillar, mongodb和httpd, 然后可以在state文件中用如下方式引用:

 

 

管理系统有点像驾驶飞机。如果不小心谨慎,将会是高风险的事情。假设我是一个双翼飞机的驾驶员,将做一个危险的aerial manoeuvre, 我多半会希望能够先模拟飞行。除非我像Red Baron一样无所畏惧。无论如何,还好在执行Salt之前可以先做测试。你需要做的仅仅是将Test设置为True。

 

 

总结

在配置管理方面,Salt在Puppet面前还是能够站稳脚跟的。Salt安装非常简单,属于简单主义的开发风格, 功能丰富。总的来说,不需要过多的操作就可以完成事情。我发现的唯一问题是salt-master和minion之间的连接有时会无故断掉。搜索一番后,我发现其他人在Salt 0.10.5这个版本上也遇到了同样的问题。希望这个问题在下一个版本中得到解决。

命令编排和远程执行

MCollective

MCollective是 Puppet的命令编排解决方案。由R.I.Pienaar在PuppetLabs那帮人引起重视之前独立开发完成。MCollective使用message broker (比如ActiveMQ)通过pub-sub总线来传递消息, 可以并行通信,这比用ssh快得多。这是一可以理解特定消息并产生响应的框架。Puppet和MCollective现在可以在同一个框架下工作,同时提供完成配置管理和命令编排的功能。

先不管MCollective的优势,有两个负担能够打击你的激情。第一,MCollective只是和Puppet松散集成,至少对社区版本来讲是这样 。MCollective有单独的安装包,独立的配置文件。另外你还需要安装配置broker(比如ActiveMQ),来与MCollective一起工作. 虽然不难,但很繁琐。最后,你还不得不自己解决生产环境中通信渠道的安全问题。不幸的是,这个就有点困难。

MCollective的第二个问题是相对来讲缺少一些自带的功能。有很多现成的插件可以下载安装(https://github.com/puppetlabs/mcollective-plugins), 用Ruby写自己的插件也不是很复杂-不过想要立即使用的话,障碍比想像得要大。Nevertheless, given that the framework is solid and extensible, dabbling in Ruby plugins soon makes the real power of MCollective apparent.

Salt

另一方面,Salt生来就有命令编排的功能。最先设想的就是远程执行技术,然后才添加的配置管理管理。Salt使用轻量的ZeroMQ来处理消息。结果就是不需要单独的安装。装好Salt后,配置管理和命令编排就可以工作了。毫不惊奇,Salt state模块和execution模块的命令在语法上类似,所以很直观。再看Puppet和MCollective组合,各自使用不同的工具和语法结构,需要额外的时间去学习。

Salt远程执行功能的可用性令人印象深刻。当前的在线文档列出了超过100个不同的内置excution模块-包括augeas!(所以augeas成为state模块只是时间上的问题).

举个简单的例子,看看通用的"cmd.run"模块和指令。这在你知道想要执行的命令却又没有现成的模块可用时非常有用,- 或者你仅仅想要快速地远程执行命令。假设我想在所有节点上检查运行的内核版本号:

[root@salt salt]# salt '*' cmd.run "uname -r"
minion1.example.com: 2.6.18-274.18.1.el5
minion2.example.com: 2.6.18-274.18.1.el5
salt.example.com: 2.6.18-274.18.1.el5
或者我想看看磁盘使用情况:

salt '*' cmd.run "df -h"
顺便说一下, Salt有一个模块用来查看磁盘用量以及其他磁盘相关的查询:

salt '*' disk.usage
使用内置模块而不用cmd.run发送shell命令的好处是,模块通常返回固定结构的数据。能够以编程的方式用在自动化处理上。

有很多现成的execution模块来满足通用的管理任务,比如apt, at, cp, cron, disk, extfs, file, hosts, iptables, mount, network, pam, parted, pkg, ps, selinux, shadow, ssh, and test. 也有大量的模块用于指定的软件包和应用程序,比如apache, cassandra, djangomod, git, mongodb, mysql, nginx, nova, postgres, solr, sqlite3, 和tomcat.

甚至支持执行Puppet程序。

总结

毫无疑问,Salt远程执行比Puppet加MCollective更优雅,附带可用的功能更多。支持动态查询和大规模的服务编排。要查看完整的功能,请参考salt execution模块的文档。

附加功能

Dashboard

Puppet使用Puppet dashboard. Salt目前没有图形化的界面。我知道,我们都大爱命令行。不过,有时看到满屏幕的绿色或是点点按钮也是很惬意的。 认真的讲,dashboard是获得你所管理的节点网络state概览的好工具。Salt的路线图中没有图形界面,希望最终会出现。

Returners

Returners是minion向master返回数据时调用的模块。不将返回数据传递给salt master,而是调用Returner模块来将数据发给其他服务,通常是数据库。Salt目前支持的returner,可以连接cassandra, mongo, redis和mysql. 也可以很容易的用Python脚本为其他服务写一个returner。

Salt Syndic

Salt文档将Salt Syndic描述为"一个可以构建Salt命令拓扑的强大工具“。实际意义上,Salt Syndic可以让一个运行Syndic服务的Salt master连接到更高层的master。

假设你有多个不同的Salt环境,每个环境都有一个master。这些环境可能是特的云或是有防火墙的网络。假设你想同时控制这几个环境中的minions。你可以在想要控制的master主机上安装Salt Syndic。Salt Syndic创建了传输接口,在最顶层的master看来,就像是控制了很多的minion,但配置状态实际上是传递给了多个master。可以将其想像为军队的命令传递系统。

集成测试

有两个采用现有测试框架的项目给Puppet增加测试功能,名字是cucumber-puppet (使用 Cucumber框架)和rspec-puppet (使用RSpec).

Salt采取的做法是通过一系列的集成类提供对集成测试的支持,roadmap中提到未来会使用Unittest2和pytest做单元测试。

自动化集成测试是持续性交付管道被忽视的领域,能有一些内建的支持是非常好的。这也是以后的博文中将探讨的有趣领域

结论

我的目的是看看Salt Stack是否能做为配置管理和系统命令编排的解决方案。我的方法是与Puppet中最常用的功能作比较,以探索Salt的功能。结论是很耀眼的。Salt Stack不仅自带了很多功能,且易于安装,使用,扩展。 很明显,Salt前途一片光明。

有用的链接

Saltstack主页: http://saltstack.org
Salt下载: http://saltstack.org/download/
Salt在GitHub: https://github.com/saltstack/salt
Salt开发者博客: http://red45.wordpress.com/

原文链接:opencredo.com
authoer: Maartens Lourens. 于1月10日发表在opencredo.

本文固定链接: http://www.sudops.com/another-tools-for-sa-of-saltstack.html | 运维·速度

 

http://www.opscoder.info/move_salt_master.html

一般在非不得已的情况下,我们都不会去干迁移salt master这种事的,因为这代价还是蛮大的,但之前还真坑爹的做了一回这事儿,在这儿记录下来,供大家参考。

其实现在已经有了salt ssh这种东西,它解决了salt中是先有鸡还是先有蛋的问题,运用在maste迁移上想必是极好的,但是我salt ssh还没有用起来,什么时候有空尝试一下,好,废话不说,言归正传。

我一开始是这么做迁移的:

 

    1、搭建好新的salt master的环境,并启动;
    2、批量修改minion端的配置文件,将master指向新的master,在老的master上运行:
        salt cmd.run ” sed -i ‘s/master: old_master/master: new_master/g’ /etc/salt/minion”
         多好,只要minion端不重启,那还是和老的master保持长连接的。
    3、我们还得把老的master上的相关文件拷过来了,比如pillar什么的,我就直接把下面两个文件夹copy了:
        /srv/salt/
        /srv/pillar/
注:可能大家的地址不一样啦,看你们在配置文件中配的地址吧。
    4、批量重启minion:
        salt cmd.run "sudo /etc/init.d/salt-minion restart"

 

哈哈,转移阵地到新的master上去爽一把吧。
salt-key -A,把小弟拉过来,囧了,发现拉不过来。

才发现,在之中迁移的过程中有个很重要的操作没有执行,导致我们新的master无法正常连接到minion。

因为salt建立连接是要通过证书认证的,默认的配置是master端自动接收minion的证书,minion端存放的master相关的证书位置为:
/etc/salt/pki/minion/minion_master.pub

在该证书存在的情况下,更改master,也不会重新生成,进而导致证书不正确无法与master通信。
因此,在minion重启之前,需要先把/etc/salt/pki/minion/minion_master.pub删除掉。

好在我当时只有三十多台机器,我登上每一台机器上去执行:
“sudo rm -rf /etc/salt/pki/minion/minion_master.pub"
"sudo /etc/init.d/salt-minion restart"

其实也挺快的,我几分钟就刷完了。

 

最后给出正确的做法:
1、搭建好新的salt master的环境,并启动;
2、批量修改minion端的配置文件,将master指向新的master,在老的master上运行:
         salt cmd.run ” sed -i ‘s/master: old_master/master: new_master/g’ /etc/salt/minion”
3、老的master上的相关文件拷过来;
4、删除minion上的认证证书:
        salt cmd.run "sudo rm -rf /etc/salt/pki/minion/minion_master.pub"
5、批量重启minion:
        salt cmd.run "sudo /etc/init.d/salt-minion restart"
6、把minion accept到新的master中:
        salt-key -A




转载请注明出处:http://www.opscoder.info/move_salt_master.html

 

 

http://yoyolive.com/saltstack/2014/05/29/saltstack-base-service.html

对基础服务的管理包括配置管理系统、用户账号管理、yum配置管理、hosts文件管理、时间同步管理、DNS配置管理。

配置管理系统

配置管理系统使用模块化设计,每个服务一个模块,将多个模块组织到一起形成角色(/srv/salt/roles/)。所有模块放置到:/srv/salt下,入口配置文件为:/srv/salt/top.sls。模块使用的变量放置到:/srv/pillar,入口配置文件:/srv/pillar/top.sls。针对变量的作用域不同,将变量分为三级级,一级应用于模块(/srv/pillar/模块名),一级应用于角色(/srv/pillar/roles/),一级应用于主机节点(/srv/pillar/nodes)。具体配置在此不一一列出,具体参见salt配置文件。

入口配置/srv/salt/top.sls,直接引用各种角色:

base:  
  '*':  
    - roles.common  
  'admin.grid.mall.com':  
    - roles.admin  
  'ha.grid.mall.com':  
    - roles.ha  
  'web*.grid.mall.com':  
    - roles.web  
  'cache*.grid.mall.com':  
    - roles.cache  
  'mc*.grid.mall.com':  
    - roles.mc  
  'db*.grid.mall.com':  
    - roles.db  
  'search*.grid.mall.com':  
    - roles.search  
  'storage*'.grid.mall.com':  
    - roles.storage  

变量入口配置文件/srv/pillar/top.sls:

base:  
  '*':  
    - roles.common  
  # 引用角色级变量  
  # 模块级变量在角色级变量中引用  
  'admin.grid.mall.com':  
    - roles.admin  
  'ha.grid.mall.com':  
    - roles.ha  
  'web*.grid.mall.com':  
    - roles.web  
  'cache*.grid.mall.com':  
    - roles.cache  
  'mc*.grid.mall.com':  
    - roles.mc  
  'db*.grid.mall.com':  
    - roles.db  
  'search*.grid.mall.com':  
    - roles.search  
  'storage*'.grid.mall.com':  
    - roles.storage  
  # 引用节点级变量
  'ha1.grid.mall.com':  
    - nodes.ha1  
  'ha2.grid.mall.com':
    - nodes.ha2  
  'mc1.grid.mall.com':
    - nodes.mc1  
  'mc2.grid.mall.com':
    - nodes.mc2  
  'db1.grid.mall.com':
    - nodes.db1  
  'db2.grid.mall.com':
    - nodes.db2  

用户账号管理

用户管理模块:/srv/salt/users

此模块用到pillar,pillar和grains都可以用来获取变量,但是grains偏向于获取客户端相关信息,比如客户端硬件架构、cpu核数、操作系统版本等信息,相当于puppet的facter;pillar用于定义用户变量,通过pillar变量的传递,使salt state模块易于重用,相当于puppet的hiera。使用pillar变量之前需要执行salt '*' saltutil.refresh_pillar命令使变量生效。使用命令salt 'admin.grid.mall.com' pillar.item users获取users变量:

# salt 'admin.grid.mall.com' pillar.item users  
admin.grid.mall.com:  
    ----------  
    users:  
        ----------  
        dongliang:  
            ----------  
            fullname:  
                Shi Dongliang  
            gid:  
                1000  
            group:  
                dongliang  
            password:  
                $6$BZpX5dWZ$....... 
            shell:  
                /bin/bash  
            ssh_auth:  
                ----------  
                comment:  
                    dongliang@leju.com  
                key:  
                    AAAAB3......==  
            sudo:  
                True  
            uid:  
                1000  

获取admin.grid.mall.com上面定义的所有pillar变量:

# salt 'admin.grid.mall.com' pillar.items

添加用户:

/srv/salt/users/user.sls用于管理用户

user1定义user2定义

sudo.sls为用户添加sudo权限:

sudoers:  
  file.managed:  
    - name: /etc/sudoers  

/srv/salt/users/user.sls读取/srv/pillar/users/init.sls中的users变量。

users:  
  dongliang:  # 定义用户名  
    group: dongliang  # 用户所在组  
    uid: 1000  # 用户uid  
    gid: 1000  # 用户gid  
    fullname: Shi Dongliang  
    password:   $6$BZpX5dWZ$......  # 密码,注意是hash后的密码  
    shell: /bin/bash  # 用户shell  
    sudo: true  # 是否给sudo权限  
    ssh_auth:  # 无密码登录,可选项  
      key: AAAAB3......==  
      comment: dongliang@mall.com 

在salt-master上执行下面命令使配置生效

# salt '' saltutil.refresh_pillar
# salt '
' state.highstate

yum配置管理

yum配置管理:/srv/salt/base/repo.sls
配置文件:/srv/salt/base/files/mall.repo # 此配置文件可以通过salt协议下发到客户端

/srv/salt/base/repo.sls定义,管理mall.repo文件,当文件改变后执行yum clean all清理缓存,是配置生效。

/etc/yum.repos.d/mall.repo:  
  file.managed:  
    - source: salt://base/files/mall.repo  
    - user: root  
    - group: root  
    - mode: 644  
    - order: 1  
  cmd.wait:  
    - name: yum clean all  
    - watch:  
       - file: /etc/yum.repos.d/mall.repo  

hosts文件管理

hosts文件管理:/srv/salt/base/hosts.sls

/srv/salt/base/hosts.sls 定义了每个主机名和IP的对应关系。如下:

admin.grid.mall.com:  
  host.present:  
    - ip: 172.16.100.81  
    - order: 1  
    - names:  
      - admin.grid.mall.com  

时间同步管理

时间同步作为一个cron,定义文件为:/srv/salt/base/crons.sls

# 引用ntp模块  
include:  
  - ntp  

'/usr/sbin/ntpdate 1.cn.pool.ntp.org 1.asia.pool.ntp.org':  
  cron.present:  
    - user: root  
    - minute: 0  
    - hour: 2  

ntp模块:ntp/init.sls

# 安装ntpdate软件包  
    ntpdate:  
      pkg.installed:  
        - name: ntpdate  

DNS配置管理

配置DNS服务器定义在resolv.sls,控制/etc/resolv.conf配置文件:

/etc/resolv.conf:  
  file.managed:  
    - source: salt://base/files/resolv.conf  
    - user: root  
    - group: root  
    - mode: 644  
    - template: jinja  




http://www.wudiweb.com/tech/topics/355131

引言:一个”非专职运维人员“的烦恼

加入到某证券公司的IT部门,尽管所在的部门挂了一个“研发部”的名字,但是我发现有大概40%的时间是在做运维工作。

这来自两种情况:
1. 自主开发的应用,需要持续的改进,不断的更新、发布、部署、调整配置,这不是运维部门喜欢的状态。
2. 软件商提供的“产品”无法满足运维部门的要求:无法通过简单的 Q&A 文档保证系统的正常运行,经常需要有一定技术能力的人员解决系统运行过程中各种稀奇古怪的问题。

这种情况下只能自己做一个“非专职运维人员”,需要频繁的登录各种服务器,执行一些命令来查看状态或者更改配置(包括配置文件的变更和软件包的安装部署)。很多操作都是不断的重复,日复一日,让人厌烦。

”重复的工作应该交给程序去做“,所以我自己写过一些脚本。为了避免将脚本上传到几十台服务器并且不时进行更改,我使用Fabric来进行服务器的批量操作。

尽管避免了”批量的人工操作“,但我还是在进行”人工的批量操作“。远远没有实现自动管理。将有限的生命解放出来,投入到更有意义的编码工作是一个奔四程序员应有的追求,所以我又睁大红肿的眼睛,迷茫的搜索这个世界。

我发现了Puppet,Chef和CFEngine,但是并不满意。直到我发现了Salt,我的眼前一亮:这正是我所需要的东西。

如果说Salt有什么独特之处打动了我,那就是:

简单:可能是源于python的简约精神,Salt的安装配置和使用简单到了令人发指的地步。任何稍有经验的linux使用者可以在10分钟之内搭建一个测试环境并跑通一个例子(相比之下,puppet可能需要30--60分钟)。
高性能:Salt使用大名鼎鼎的ZeroMQ作为通讯协议,性能极高。可以在数秒钟之内完成数据的传递
可伸缩:基于ZeroMQ通信,具备很强的扩展性;可以进行分级管理,能够管理分布在广域网的上万台服务器。

尽管twitter、豆瓣、oracle、等著名网站的运维团队都在使用puppet,但是我相信,他们切换到salt只是一个时间问题。毕竟不是所有的人都喜欢操纵傀儡(puppet),但是谁又能离开盐(salt)呢?

关于Salt和Puppet的对比,可以参考这里,或者看看中文版

Salt快速入门

Salt的体系结构中将节点区分为: master, minion, syndic。

1. master: 老大,管理端
2. minion: 马仔,被管理端
3. syndic: 头目,对于老大来说是马仔,对于马仔来说是老大

在入门阶段,先不考虑syndic。

1. 安装配置

如果将操作系统区分为:
*NIX
Linux
Solaris
HP Unix
FreeBSD
OS X
windows

理论上来说,Salt可以安装在任何*NIX系统上,包括master和minion。除了源代码之外, 还可以通过Salt提供的安装脚本,或者PyPI进行安装。

对于Linux,尤其是企业环境中常用的RHEL,CentOS,Ubuntu,可以通过包管理器非常容易的安装master 和/或 minion。 比如: yum(需要先配置EPEL), apt(需要增加http://debian.madduck.net/repo/库),yaourt,ports。

Mac OS X 先使用HomeBrew解决依赖包:brew install swig zmq,然后用PyPI安装:pip install salt。

对于windows,只能安装minion(windows只适合做马仔)。从官方网站下载合适的安装包。安装过程中可以指定master地址和本机名称。 安装后需要自己启动Salt服务。配置文件在C:\salt\conf\minion。

具体的各操作系统下的安装可以参考官方文档。这里为了简单,只考虑常用的RHEL/CentOS 和 windows。 在下面的例子中,使用一台RHEL/CentOS作为master, 另外一台RHEL/CentOS和一台windows 2003 Server作为 minion。

2. 安装管理端(master)

  1. # 安装EPEL,注意选择合适的版本
  2. rpm -ivh http://mirrors.sohu.com/fedora-epel/6/x86_64/epel-release-6-8.noarch.rpm
  3. yum update
  4. # 安装master
  5. yum install salt-master
  6. # 修改配置
  7. vim /etc/salt/master
  8. # 最基本的设定服务端监听的IP(比如使用VIP做master的高可用时):
  9. # interface: 服务端监听IP
  10. # 其他配置参考[官方文档](http://docs.saltstack.com/ref/configuration/master.html)
  11. # 启动服务(以下命令等效)
  12. salt-master -d
  13. /etc/init.d/salt-master start
  14. service salt-master start

3. 安装被管理端(minion)

  1. # 安装EPEL,注意选择合适的版本
  2. rpm -ivh http://mirrors.sohu.com/fedora-epel/6/x86_64/epel-release-6-8.noarch.rpm
  3. yum update
  4. # 安装minion
  5. yum install salt-minion
  6. # 修改配置
  7. vim /etc/salt/minion
  8. # 最基本的设定是指定master地址,以及本机标识符:
  9. # master: master的主机名或IP地址
  10. # id: 本机标识符
  11. # 其他配置参考[官方文档](http://docs.saltstack.com/ref/configuration/minion.html)
  12. # 启动服务(以下命令等效)
  13. salt-minion -d
  14. /etc/init.d/salt-minion start
  15. service salt-minion start

4. 接受minion的托管请求

minion向master投诚后,还需要master接受才行。这个过程叫做“授信”。

Salt底层使用公钥-私钥证书来保证通信信道的安全。具体的机制可以参考ZeroMQ的相关内容。Salt已经屏蔽了底层的细节,只需要使用封装好的命令:
  1. # 在master上运行
  2. # 查看所有minion
  3. salt-key -L
  4. Accepted Keys:
  5. windows
  6. bond_app_server_main
  7. mac_os_vm
  8. salt-master
  9. Unaccepted Keys:
  10. minion1
  11. minion2
  12. Rejected Keys:
  13.  
  14. #其中Unaccepted Keys是未许可的minion。可以使用下面的命令通过认证:
  15. salt-key -a minion1

5. 测试

安装配置好之后,首先要测试一下联通性:salt '*' test.ping。salt会列出每个认证过的minion的联通状态(true 或 false)。

再举一些例子:
  1. # 查询主机运行了多长时间
  2. sudo salt '*' cmd.run "uptime"
  3.  
  4.  
  5. # 批量重启服务
  6. salt '*' cmd.run "service httpd restart"
  7.  
  8. # 让多台机器一起,使用Apache Bench进行压力测试
  9. salt '*' cmd.run "ab -n 10 -c 2 http://www.google.com/"
注意,默认情况下master和minion之间使用以下端口进行通信:
1. 4505(publish_port): salt的消息发布系统
2. 4506(ret_port):salt客户端与服务端通信的端口

网络的设置需要保证这些端口可以访问。

Salt的强大功能

上面的例子都是用Salt进行批量操作。但是Salt的功能不仅如此。

认真分析一下我的“非专职运维工作”的内容,发现可以分为以下三个方面:
1. 变更操作:根据需要对节点中某个资源的某种状态进行调整,并检验变更的结果
2. 配置管理:让上述行为变得“可管理”,支持“有关人士”对上述行为的标记、控制、识别、报告、跟踪和归档甚至审批和审计
3. 状态监控:随时掌握状态,发现异常。尽量在系统用户发现问题之前解决麻烦

Salt对上述三个方面提供了完美的支持,事实上,Salt提供的功能比我需要的还要多。下图是Salt的主要功能:

轻松使用SaltStack管理成千上万台服务器(入门教程)- 强大功能

如果想对Salt的功能和使用有一个初步的了解,最好参考官方文档:Salt Stack Walkthrough

1. 批量操作(targeting)

再回顾一下上文中的例子:
  1. # 测试连通性
  2. salt '*' test.ping
  3.  
  4. # 查询主机运行了多长时间
  5. sudo salt '*' cmd.run "uptime"
  6.  
  7.  
  8. # 批量重启服务
  9. salt '*' cmd.run "service httpd restart"
  10.  
  11. # 让多台机器一起,使用Apache Bench进行压力测试
  12. salt '*' cmd.run "ab -n 10 -c 2 http://www.google.com/"
上面的例子都是对多个节点进行批量操作:使用通配符"'*'"对所有注册的节点进行操作。Salt支持多种方式对节点id(minion id)进行匹配。包括:

默认:通配符(globbing))
* E:正则表达式(Regular Expression)
* L:列表
* N: 分组(group)
* C:复合匹配
先看一下通配符、正则表达式和列表的例子:
  1. # 通配符是最常用的匹配方式。Salt使用[linux风格的通配符](http://docs.python.org/2/library/fnmatch.html)
  2. salt '*' test.ping
  3. salt '*.example.net' test.ping
  4. salt '*.example.*' test.ping
  5. salt 'web?.example.net' test.ping
  6. salt 'web[1-5]' test.ping
  7. salt 'web-[x-z]' test.ping
  8. # 正则表达式可以适应更复杂的情况。使用[python的re模块](http://docs.python.org/2/library/re.html#module-re)进行匹配
  9. salt -E 'web1-(prod|devel)' test.ping
  10. # 最直接的方式是自己指定多个minion,即列表
  11. salt -L 'web1,web2,web3' test.ping
复合匹配(Compound matchers)有点复杂,后续会在其他文章中专门介绍。

2. 节点分组(nodegroups)

好吧,批量操作确实很爽。但是每次都输入匹配规则有点麻烦,对于复杂的匹配规则更是如此。 salt的 nodegroups功能可以将常用的匹配规则保存下来(称之为minion的分组)。批量操作是,只需要使用L标记指定要操作的group名字即可。 groups定义在master的配置文件/etc/salt/master中。

group 的定义可以使用各种匹配规则,比如:
  1. group1: 'L@foo.domain.com, bar.domain.com,baz.domain.com or bl*.domain.com'
  2. group2: 'G@os:Debian and foo.domain.com'

3. 命令执行(execution)

Salt生来就有命令编排的功能。据说,Salt最先实现的是远程执行技术,然后才添加的配置管理功能。Salt使用ZeroMQ来处理命令执行的请求和响应消息,安装配置简单,并且性能非常高。

Salt即可以批量执行命令,也可以单机执行。通常单机执行用于测试:
1. 单机(立即)执行。 使用salt-call命令单机执行操作
2. 批量(立即)执行。最常用的操作。使用salt命令,对匹配的minion节点执行操作

Salt可以执行的命令也可以分为两种:
1. 系统命令,使用cmd.run执行
2. Salt模块,将常用的命令/批处理封装到内置的Salt模块(module),使用模块名.功能名的方式执行。

比如:

 

  1. # 执行系统命令
  2. salt '*' cmd.run 'hostname'
  3. # 执行Salt模块
  4. salt '*' disk.usage
使用Salt模块的好处是能够做到一致。比如同样是查看磁盘使用情况,salt '*' cmd.run "df -h"只能用于NIX节点,而salt '*' disk.usage对NIX和Windows都适用,并且采用相同结构返回数据,便于批量处理。

Salt已经内置了大量的模块,这些模块涵盖了日常管理任务的主要任务,包括:
1. 通用的管理任务,比如apt, at, cp, cron, disk, extfs, file, grains, hosts, iptables, mount, network, pam, parted, pkg, ps, selinux, shadow, ssh, test等
2. 针对特定软件的任务,比如apache, cassandra, djangomod, git, mongodb, mysql, nginx, nova, postgres, solr, sqlite3, 和tomcat

而且,自己开发Salt模块也非常简单,很容易将实际管理操作中的一些经验通过自定义的模块固化下来,并方便分享。

在开发和调试模块的时候,可以使用test=True参数进行模拟执行(Dry run)。比如:
  1. salt 'minion1.example.com' state.highstate -v test=True

4. 节点信息(grains)

grains是Salt内置的一个非常有用的模块。在用salt进行管理客户端的时候或者写state的时候都可以引用grains的变量。

grains的基本使用举例如下:
  1. # 查看grains分类
  2. salt '*' grains.ls
  3.  
  4. # 查看grains所有信息
  5. salt '*' grains.items
  6. # 查看grains某个信息
  7. salt '*' grains.item osrelease

5. 配置管理(state)

配置管理是Salt中非常重要的内容之一。Salt通过内置的state模块支持配置管理所需的功能。关于这部分内容,官方文档有很详细的描述,可以参考 part 1part 2和 part 3

Salt中可以定义节点的目标状态,称之为state。state对应配置管理中的配置,可以对其进行标识、变更控制、变更识别、状态报告、跟踪和归档以及审计等一些的管理行为。

状态描述
Salt使用SLS文件(SaLt State file)描述状态。SLS使用YAML格式进行数据序列化,因此简单明了,可读性也很高。

基本描述(yaml)
下边是一个简单的SLS文件例子:
  1. apache:
  2. pkg:
  3. - installed
  4. service:
  5. - running
  6. - require:
  7. - pkg: apache

该文件描述一个ID为apache的配置状态:
1. 软件包(pkg)已经安装
2. 服务应该处于运行中
3. 服务的运行依赖于apache软件包的安装

state文件中的所有YAML变量名来自Salt的state模块。
Salt内置了大量的state模块,比如cron, cmd, file, group, host, mount, pkg, service, ssh_auth,user等。 详细清单参考这里
还可以开发自己的state模块。

扩展描述(jinja)
state可以使用jinja模板引擎进行扩展,其语法可以参考这里

下面是一个更复杂的例子:
  1. vim:
  2. pkg:
  3. { % if grains['os_family'] == 'RedHat' % }
  4. - name: vim-enhanced
  5. { % elif grains['os'] == 'Debian' % }
  6. - name: vim-nox
  7. { % elif grains['os'] == 'Ubuntu' % }
  8. - name: vim-nox
  9. { % endif % }
  10. - installed
    
该state增加了判断逻辑:如果是redhard系列的就安装 vim-enhanced,如果系统是Debian或者Ubuntu就安装vim-nox。

逻辑关系
state之间可以有逻辑关系。常见的关系举例如下:

1. require:依赖某个state,在运行此state前,先运行依赖的state,依赖可以有多个
  1. httpd:
  2. pkg:
  3. - installed
  4. file.managed:
  5. - name: /etc/httpd/conf/httpd.conf
  6. - source: salt://httpd/httpd.conf
  7. - require:
  8. - pkg: httpd

watch:在某个state变化时运行此模块
  1. redis:
  2. pkg:
  3. - latest
  4. file.managed:
  5. - source: salt://redis/redis.conf
  6. - name: /etc/redis.conf
  7. - require:
  8. - pkg: redis
  9. service.running:
  10. - enable: True
  11. - watch:
  12. - file: /etc/redis.conf
  13. - pkg: redis

watch除具备require功能外,还增了关注状态的功能

3. order:优先级比require和watch低,有order指定的state比没有order指定的优先级高
  1. vim:
  2. pkg.installed:
  3. - order: 1

想让某个state最后一个运行,可以用last

保存状态
状态描述文件(SLS)要保存在master节点中,并通过指令分发到minion节点。

1. 路径设置
Salt master的配置文件(/etc/salt/master)中可以通过file_roots参数指定状态文件的保存路径。可以为不同的环境(如开发环境、UAT环境、生产环境、灾备环境等)分别指定路径,如下所示:
  1. file_roots:
  2. base:
  3. - /srv/salt/
  4. dev:
  5. - /srv/salt/dev/services
  6. - /srv/salt/dev/states
  7. prod:
  8. - /srv/salt/prod/services
  9. - /srv/salt/prod/states

其中,base环境是必须的。

2. 入口文件
file_roots中必须指定“base”环境的路径,因为该路径中存在Salt state的入口文件: top.sls。

Top文件建立配置环境、节点和状态配置之间的映射关系。比如一个简单的top.sls文件:
  1. base:
  2. '*':
  3. - servers
  4. dev:
  5. '*nodb*':
  6. - mongodb

该文件指定了: - 所有节点使用base环境的servers配置 - nodb节点使用dev环境的mongodb配置

结合第一部分的file_roots配置,该top配置意味存在以下的配置文件:
  1. /srv/salt/servers.sls
  2. /srv/salt/dev/mongodb.sls

注:这里也可以使用文件夹/srv/salt/servers/和/srv/salt/dev/mongodb/,在文件夹中放置一组状态文件和配置文件,便于建立复杂的状态配置。

top.sls中的可配置内容非常丰富,具体内容可以参考官方文档

状态生效(State Enforcement)
master上对状态进行定义,最终这些状态要传递到minion节点上。在本节的例子中,如果定义好了状态文件/srv/salt/dev/mongodb.sls:
  1. mongodb:
  2. pkg:
  3. - installed

可以使用命令salt "minion1" state.highstate -v使得所有针对"minion1"的state生效;

在执行状态之前先进行测试是个好主意,需要指定参数test=True。比如,salt "minion1" state.highstate -v test=True。

关于state模块的更多用法,可以参考state模块说明,或官方文档

更多
Salt的state模块的功能不仅如此,还可以使用模板和变量,以及定义状态的定时自动生效。

6. 小结

本文介绍Salt的主要功能和基本使用,包括minion节点的管理,批量操作,以及非常重要的配置管理。 掌握了这些内容,可以使用Salt极大提高运维的效率(事实上,Salt对于开发阶段也能提供很大的帮助,开发和运维的界限正在逐渐模糊)。

后续会介绍一些使用案例以及Salt的高级功能。

Salt state实例解析

在Salt的官方教程中,以apache和sshd的state配置作为例子。掌握这两个例子,就能够触类旁通,处理日常工作中大部分的配置管理问题。 本文对这两个例子进行详细的分析和注释。

1. 目录结构

文档 中的例子包含了多个文件。这些文件之间互相引用和关联。目录结构及文件清单如下:
  • apache/init.sls
  • apache/httpd.conf
  • ssh/init.sls
  • ssh/server.sls
  • ssh/banner
  • ssh/ssh_config
  • ssh/sshd_config
  • ssh/custom-server.sls
两个配置分别放在了apache和ssh文件夹。一个Salt状态可以使用单个的SLS文件,或者使用一个文件夹。后者更加灵活方便。

2. apache/init.sls

  1. apache:
  2. pkg:
  3. - installed
  4. service:
  5. - running
  6. - watch:
  7. - pkg: apache
  8. - file: /etc/httpd/conf/httpd.conf
  9. - user: apache
  10. user.present:
  11. - uid: 87
  12. - gid: 87
  13. - home: /var/www/html
  14. - shell: /bin/nologin
  15. - require:
  16. - group: apache
  17. group.present:
  18. - gid: 87
  19. - require:
  20. - pkg: apache
  21. /etc/httpd/conf/httpd.conf:
  22. file.managed:
  23. - source: salt://apache/httpd.conf
  24. - user: root
  25. - group: root
  26. - mode: 644
  27. - template: jinja
  28. - context:
  29. custom_var: "override"
  30. - defaults:
  31. custom_var: "default value"
  32. other_var: 123
说明:
1. sls文件使用YAML格式定义,最外面的层级定义配置项。
2. 一个sls文件中可以有多个配置项,配置项的ID可以起任意的名字。本例中包含ID为apache和/etc/httpd/conf/httpd.conf两个配置项。
3. 配置项内是一系列的状态声明。所有的状态项来自Salt状态模块。即可以使用Salt内置的状态模块,也可以编写自定义的状态模块
4. 状态声明内部指定状态函数的调用。状态函数是每个Salt状态模块中定义的函数。
5. apache配置项
1) pkg模块,使用操作系统的包管理器(如yum, apt-get)安装软件包
salt.states.pkg.installed函数, 验证软件包是否安装以及是否为指定的版本
2) service模块管理服务/守护进程(daemon)的启动或停止
    salt.states.service.running函数检查服务是否已经启动
    service模块定义了salt.states.service.mod_watch函数,可以使用watch要素监控其他的模块是否满足。这里监控以下情况:
        apache软件包(pkg)是否已安装
        /etc/httpd/conf/httpd.conf文件(file)是否存在
        apache用户(user)是否存在
    user.present是简写形式,直接调用user模块的present函数检查是否存在如下属性的apache用户:
        uid=87
        gid=87
        home目录为/var/www/html
        登录脚本为/bin/nologin
        检查依赖项:apache用户组
    group.present是简写形式,直接调用group模块的present函数检查是否存在如下属性的apache用户组:
        gid=87
        检查依赖项:apache软件包
6. /etc/httpd/conf/httpd.conf配置项
file.managed是简写形式,直接调用file模块的managed方法根据需要从master获取文件并可能会通过模板系统(templating system)进行渲染。文件要满足如下要求:
  • 使用master上面的apache/httpd.conf文件
  • user=root
  • group=root
  • mode=644
  • 使用jinja模板渲染
  • 上下文变量:
  • custom_var="override"
  • 默认值:
  • custom_var="default value"
  • other_var=123

3. ssh/init.sls

  1. openssh-client:
  2. pkg.installed
  3. /etc/ssh/ssh_config:
  4. file.managed:
  5. - user: root
  6. - group: root
  7. - mode: 644
  8. - source: salt://ssh/ssh_config
  9. - require:
  10. - pkg: openssh-client

4. ssh/server.sls

  1. include:
  2. - ssh
  3. openssh-server:
  4. pkg.installed
  5.  
  6. sshd:
  7. service.running:
  8. - require:
  9. - pkg: openssh-client
  10. - pkg: openssh-server
  11. - file: /etc/ssh/banner
  12. - file: /etc/ssh/sshd_config
  13.  
  14. /etc/ssh/sshd_config:
  15. file.managed:
  16. - user: root
  17. - group: root
  18. - mode: 644
  19. - source: salt://ssh/sshd_config
  20. - require:
  21. - pkg: openssh-server
  22.  
  23. /etc/ssh/banner:
  24. file:
  25. - managed
  26. - user: root
  27. - group: root
  28. - mode: 644
  29. - source: salt://ssh/banner
  30. - require:
  31. - pkg: openssh-server
说明:
1. include语句将别的state添加到当前文件中,使得state可以跨文件引用。
使用include相当于把被引用的内容文件添加到自身,可以require、watch或extend被引用的SLS中定义的内容。
这里引用了sshstate。
2. openssh-server配置项
3. sshd
4. /etc/ssh/sshd_config配置项
5. /etc/ssh/banner配置项

5. ssh/custom-server.sls

  1. include:
  2. - ssh.server
  3.  
  4. extend:
  5. /etc/ssh/banner:
  6. file:
  7. - source: salt://ssh/custom-banner
说明:
1. 引用sshstate的server配置项
2. extend可以复用已有的state,在原来的基础上进行扩展,增加新的配置或修改已有的配置。
    将/etc/ssh/banner配置项的文件修改为salt://ssh/custom-banner
 
 
 
 
http://www.kerncai.com/tech/sa/2014/01/14/set-linux-saltsquid/

之前的几篇记录了salt的安装、配置、以及各个模块的使用,今天主要基于salt的grains和pillar自动化部署squid缓存服务。

动手之前先确定下当前需求:

  1. 我们有两个机房,两个机房的ip地址是不同的,一个是10.10.开头,另外一个是10.20.开头;
  2. 10.10.开头的机房主要用来缓存js、css等,另外一个机房的squid机器主要用来缓存图片,这两个的配置文件肯定是不同的
  3. 缓存图片服务的squid机器硬盘大小不同,也就是说要做的cache大小肯定也是不同的
  4. 机器的内存并不是统一大小

整理如下:

1.首先要通过salt自动安装squid服务
 2.要自己编写grains模块收集机器的内存和硬盘大小
 3.要使用pillar确认机器的ip地址是以什么开头的,以此来确认是用来缓存的具体对象
 4.整理具体配置分发到不同服务的squid配置文件内

一、先整理squid的安装包

自己整理好的squid-2.7的rpm包,通过yum的方式来安装 
编写state.sls文件 
在根目录下/srv/salt下进行,vim squid.sls

squid:
  pkg:
    - name: ajk-squid #我自己打的rpm包
    - installed
  user.present:    #检测用户,如果没有就创建 squid用户,设置为nologin状态
  - home: { { pillar['squid_home_dir'] }}
  - shell: /sbin/nologin
  - require:
    - group: squid
  group.present:   #用户组squid 和用户对应
    - name: squid
    - require:
      - pkg: ajk-squid
  service.running:  #这里保持squid服务是正常运行的状态
    - enable: True
    - reload: True
    - require:
      - file: /etc/init.d/squid      #squid的启动脚本,也是打包在安装包内的,检测下面的watch内的服务,有变化就执行
    - watch:
      - file: { { pillar['squid_conf_dir'] }}/squid.conf
      { { pillar['squid_conf_dir'] }}/squid.conf:

 file.managed:
    - source: salt://files/squid/squid.conf # 定义salt内的squid.conf配置文件
    - user: root
    - mode: 644
    - template: jinja   #使用jinja模板,这里是为了配置文件内使用pillar
    - require:
      - pkg: ajk-squid  #依赖关系

{ { pillar[squid_home_dir] }} 这里在pillar内定义好的,我是为了美观方便;之前填写下面的目录也是可以的

squid_home_dir: /usr/local/squid-2.7
squid_conf_dir: /usr/local/squid-2.7/etc

目前,squid服务的state.sls模块就已经写好了

二、收集服务器端的硬件信息

还是要使用python脚本,在_grains下面编写脚本,编写脚本前确认下配置;我的需求是squid的内存设置为总内存的45%,我squid的硬盘会有三块,挂载为目录cache1、cache2、cache3 。每块盘取90%,如果90%之后大于65G,直接取值65,少于65的话,直接使用90%的值。 
脚本如下:

vim squid.py

# -*- coding: utf-8 -*-

'''
Module for squid disk information by python2.7.3
'''


import commands
import os

def cache():
    '''
    Return the cache usage information for volumes mounted on this minion
    '''
    grains={}
    m = commands.getoutput("free -g|awk '$0~/Mem/ {print$2+1}'")
    grains['cache_mem_size']=int(int(m)*(0.45))

    file = commands.getoutput("df -Th |awk '{print$7}'")
    cache = 'cache'

    if cache in file:

        a = commands.getoutput("df -Th |grep cache |awk 'NR==1 {print$3}' |sed 's/G//g'")
        b = int(int(a)*(0.9))
        if b > = 65:
            grains['cache_disk_size'] = 65*1024
        else:
            grains['cache_disk_size'] = int(b*1024)
    else:
        grains['cache_disk_size'] = 'The cache of partition does not exist'

    return grains

我的squid机器在salt上面定义了一个组: 
root@salt _grains # cat /etc/salt/master.d/nodegroups.conf

nodegroups:
  squid_20: 'cdn20-*'

‘然后,加载编写的模块,命令如下 :

salt -N squid_20 saltutil.sync_all

查询编写的模块取值,根据disk信息取值:

root@salt _grains # salt -N 'squid_20' grains.item cache_disk_size
cdn20-005:
  cache_disk_size: 43008
cdn20-001:
  cache_disk_size: 66560

查询内存信息取值:

root@salt _grains # salt -N 'squid_20' grains.item cache_mem_size
cdn20-005:
  cache_mem_size: 7
cdn20-001:
  cache_mem_size: 14
 

三、编写squid.conf的配置文件

根据上文的目录定义,路径在/srv/salt/files/squid下 
vim squid.conf

{ % if grains['ip_interfaces'].get('eth0')[0].startswith('10.20') %} 
...........省略具体配置
## MEMORY CACHE OPTIONS
cache_mem { { grains['cache_mem_size'] }} GB #内存的大小
## DISK CACHE OPTIONS
cache_dir aufs /cache1 { { grains['cache_disk_size'] }} 16 256 #cache的大小
cache_dir aufs /cache2 { { grains['cache_disk_size'] }} 16 256
cache_dir aufs /cache3 { { grains['cache_disk_size'] }} 16 256
visible_hostname{ { grains['host'] }} #机器名
{ % else %} (#去掉)
  缓存js等的配置文件,此处省略
{ % endif %}(#去掉)

这里只是说明下salt需要配置的东西,至于squid具体的配置文件,这里就不多说了 
当然,上述的判断可以在pillar里面做完而不用在配置文件的时候做判断,只不过我感觉那样要多一层逻辑,就直接判断了 ··· 其实是我比较懒····

这样,一个squid的基本安装配置基本就成功了,可以找机器进行测试 
后续,添加机器的话,可以进行直接部署了

 

 

http://www.tuicool.com/articles/m6NjeqR

今天在查找salt中pillar嵌套pillar的方法时,无意之间发现了pillar除了可以直接使用文件(sls)外,也同时支持多种后端的数据存储方式。例如:mysql, mongodb, ldap, json, cobbler甚至是puppet。这无疑为开发中的接口提供了极大的便利。

详细的支持列表可见:http://docs.saltstack.com/en/latest/ref/pillar/all/index.html#all-salt-pillars。

严格意义上来说,这篇博文并非完全原创,英文原文请参考:http://www.tmartin.io/articles/2014/salt-pillar-mongodb/。

下面就来说说详细的配置方式,假定你已经有了一个部署好的salt环境,并且正确配置了salt master和salt minion,并且完成认证,主机名为salt-master.salt.com,这里我们使用Ubuntu 12.04 64bit作为演示环境。

安装MongoDB和Python MongoDB

apt-get install mongodb python-pymongo python-pymongo-ext

确保你能连接到MongoDB

# mongo
MongoDB shell version: 2.2.3
connecting to: test
>

创建MongoDB数据库和存放Pillar的Collection

创建数据库pillar

use pillar
在数据库中插入pillar数据
db.pillar.insert({
    _id: 'salt-master.salt.com',
    mongo_pillar: {
        key1: "value1",
        key2: "value2",
    }})
注意:这里的_id必须要和你的minion节点的主机名一致,并且 无法使用通配符,也就是一个节点都有自己一套独立的pillar,这一点和文件中定义pillar有很大的不同 。mongo_pillar部分中是定义的是pillar中的内容,也就是我们可以直接引用的部分。

配置Salt Master

下一步就是告诉Salt Master,我们在MongoDB中存放了pillar数据,需要劳您大驾,移步MongoDB读取数据。修改:

/etc/salt/master
添加
mongo.db: "pillar"
mongo.host: "localhost"
ext_pillar:
    - mongo: {}
注意:如果需要使用不同于标准安装接口,请使用mongo.port,如果需要配置用户名和密码,请使用mongo.user和mongo.password。其他参数定义,请详见:http://docs.saltstack.com/en/latest/ref/pillar/all/salt.pillar.mongo.html#module-documentation。

测试

salt salt-master.salt.com pillar.item mongo_pillar
返回
salt-master.salt.com:
  ----------
  mongo_pillar:
    ----------
    key1:
      value1
    key2:
      value2
如果想在sls中直接使用
{{ salt['pillar.get']('mongo_pillar:key1') }}

总结

pillar应该是salt中一个比较灵活的配置选项,个人理解pillar的作用就像puppet中init定义的初始化的参数的默认值,每次部署时,只需要更改pillar的文件就可以啦。但是随着代码的增长(主要用于部署OpenStack),发现pillar的管理越来越难,pillar本身对如何组织结构并没有严格的限制,而且嵌套(extend)功能暂时还不能很完美的支持(https://github.com/saltstack/salt/issues/3991),这也给pillar的管理提高了复杂度。

 

http://blog.opmacloud.com/2014/06/%E4%BD%BF%E7%94%A8saltstack%E7%AE%A1%E7%90%86%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%E3%80%81%E9%83%A8%E7%BD%B2nginx%E3%80%81zabbix/

使用saltstack管理配置文件、部署nginx、zabbix

看下saltstack的目录结构

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
[root@manager srv]# pwd
/srv
[root@manager srv]# tree 
.
├── pillar
│   ├── nginx
│   │   └── vhost.sls
│   └── top.sls
└── salt
    ├── base
    │   ├── base.sls
    │   ├── hosts
    │   └── limits.conf
    ├── _grains
    ├── nginx
    │   ├── conf.sls
    │   ├── files
    │   │   ├── nginx
    │   │   ├── nginx_ajp_module-master.zip
    │   │   ├── nginx.conf
    │   │   ├── nginx_log_cut.sh
    │   │   ├── tengine-2.0.2.tar.gz
    │   │   └── vhost
    │   │       ├── lens.networkbench.com.conf
    │   │       └── newlens-api.networkbench.com.conf
    │   ├── install.sls
    │   └── vhost.sls
    ├── ssh
    │   ├── client.sls
    │   ├── server.sls
    │   ├── ssh_config
    │   └── sshd_config
    ├── top.sls
    └── zabbix
        ├── conf_d.sls
        ├── conf.sls
        ├── files
        │   ├── zabbix-2.2.1.tar.gz
        │   ├── zabbix_agentd
        │   ├── zabbix_agentd.conf
        │   └── zabbix_agentd.conf.d
        │       ├── io.conf
        │       └── iostat.conf
        └── install.sls
 
12 directories, 28 files

从top文件逐个说明

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[root@manager salt]# cat top.sls 
base:
  '*':
    - base.base
    - ssh.client
    - ssh.server
    - zabbix.install
    - zabbix.conf
    - zabbix.conf_d
 
  'lens1,lens2':
    - match: list
    - nginx.install
    - nginx.conf
    - nginx.vhost

base.sls主要是一些基本软件包的安装和一些系统配置文件的集中管理,sshclient和sshserver是对openssh配置文件集中管理。

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
[root@manager salt]# cat base/base.sls 
vim-enhanced:
  pkg:
    - name: vim-enhanced
    - installed
unzip:
  pkg:
    - name: unzip
    - installed
 
/etc/hosts:
  file.managed:
    - source: salt://base/hosts
    - user: root
    - group: root 
    - mode: 644 
    - backup: minion
 
/etc/security/limits.conf:
  file.managed:
    - source: salt://base/limits.conf
    - user: root
    - group: root 
    - mode: 644 
    - backup: minion

下面看下zabbix的安装,这里采用的是编译安装

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
[root@manager salt]# cat zabbix/install.sls 
zabbix_source:
  file.managed:
    - name: /var/tmp/zabbix-2.2.1.tar.gz
    - unless: test -e /var/tmp/zabbix-2.2.1.tar.gz
    - source: salt://zabbix/files/zabbix-2.2.1.tar.gz
 
extract_zabbix:
  cmd.run:
    - cwd: /var/tmp
    - names:
      - tar xvf zabbix-2.2.1.tar.gz
    - unless: test -d /var/tmp/zabbix-2.2.1
    - require:
      - file: zabbix_source
 
zabbix_user:
  user.present:
    - name: zabbix
    - uid: 1501
    - createhome: False
    - gid_from_name: True
    - shell: /sbin/nologin
 
zabbix_pkg:
  pkg.installed:
    - pkgs:
      - gcc
 
zabbix_compile:
    cmd.run:
      - cwd: /var/tmp/zabbix-2.2.1
      - names:
        - ./configure --prefix=/opt/zabbix --enable-agent; make -j4; make install
      - require:
        - cmd: extract_zabbix
        - pkg: zabbix_pkg
      - unless: test -d /opt/zabbix
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
[root@manager salt]# cat zabbix/conf.sls 
zabbix_log_dir:
  cmd.run:
    - names:
      - mkdir /opt/zabbix/log
    - require:
      - cmd: zabbix_compile
    - unless: test -d /opt/zabbix/log
 
zabbix_conf:
  file.managed:
    - name: /opt/zabbix/etc/zabbix_agentd.conf
    - source: salt://zabbix/files/zabbix_agentd.conf
    - template: jinja
 
zabbix_log:
  file.managed:
    - name: /opt/zabbix/log/zabbix_agentd.log
    - user: zabbix
    - group: zabbix
    - mode: 644
 
zabbix_service:
  file.managed:
    - name: /etc/init.d/zabbix_agentd
    - user: root
    - mode: 755
    - source: salt://zabbix/files/zabbix_agentd
  cmd.run:
    - names:
      - /sbin/chkconfig zabbix_agentd on
    - unless: /sbin/chkconfig --list zabbix_agentd
  service.running:
    - name: zabbix_agentd
    - enable: True
    - watch:
      - file: /opt/zabbix/etc/zabbix_agentd.conf
      - file: /opt/zabbix/etc/zabbix_agentd.conf.d/*.conf

conf_d.sls存放的是zabbix_agentd.conf.d目录下的内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[root@manager salt]# cat zabbix/conf_d.sls 
zabbix_agentd.conf.d_io:
  file.managed:
    - name: /opt/zabbix/etc/zabbix_agentd.conf.d/io.conf
    - source: salt://zabbix/files/zabbix_agentd.conf.d/io.conf
    - watch_in:
      service: zabbix
 
zabbix_agentd.conf.d_iostat:
  file.managed:
    - name: /opt/zabbix/etc/zabbix_agentd.conf.d/iostat.conf
    - source: salt://zabbix/files/zabbix_agentd.conf.d/iostat.conf
    - watch_in:
      service: zabbix

下面是nginx

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
[root@manager salt]# cat nginx/install.sls 
nginx_source:
  file.managed:
    - name: /var/tmp/tengine-2.0.2.tar.gz
    - unless: test -e /var/tmp/tengine-2.0.2.tar.gz
    - source: salt://nginx/files/tengine-2.0.2.tar.gz
 
ajp_source:
  file.managed:
    - name: /var/tmp/nginx_ajp_module-master.zip
    - unless: test -e /var/tmp/nginx_ajp_module-master.zip
    - source: salt://nginx/files/nginx_ajp_module-master.zip
 
extract_nginx:
  cmd.run:
    - cwd: /var/tmp
    - names:
      - tar xvf tengine-2.0.2.tar.gz
      - unzip nginx_ajp_module-master.zip
    - unless: test -d /var/tmp/tengine-2.0.2
    - unless: test -d /var/tmp/nginx_ajp_module-master
    - require:
      - file: nginx_source
      - file: ajp_source
 
nginx_user:
  user.present:
    - name: nginx
    - uid: 1500
    - createhome: False
    - gid_from_name: True
    - shell: /sbin/nologin
 
nginx_pkg:
  pkg.installed:
    - pkgs:
      - gcc
      - openssl-devel
      - pcre-devel
      - zlib-devel
      - unzip
 
nginx_compile:
    cmd.run:
      - cwd: /var/tmp/tengine-2.0.2
      - names:
        - ./configure --prefix=/opt/nginx --user=nginx --group=nginx --with-http_upstream_check_module --add-module=/var/tmp/nginx_ajp_module-master/;make -j4;mak install
      - require:
        - cmd: extract_nginx
        - pkg: nginx_pkg
      - unless: test -d /opt/nginx

nginx的配置文件和脚本管理

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
[root@manager salt]# cat nginx/conf.sls 
{% set nginx_user = 'nginx' %}
 
nginx_conf:
  file.managed:
    - name: /opt/nginx/conf/nginx.conf
    - source: salt://nginx/files/nginx.conf
    - template: jinja
    - defaults:
      nginx_user: {{ nginx_user }}
 
nginx_vhost_dir:
  cmd.run:
    - names:
      - mkdir /opt/nginx/conf/vhost
    - require:
      - cmd: nginx_compile
    - unless: test -d /opt/nginx/conf/vhost
 
nginx_service:
  file.managed:
    - name: /etc/init.d/nginx
    - user: root
    - mode: 755
    - source: salt://nginx/files/nginx
  cmd.run:
    - names:
      - /sbin/chkconfig nginx on
    - unless: /sbin/chkconfig --list nginx
  service.running:
    - name: nginx
    - enable: True
    - reload: True
    - watch:
      - file: /opt/nginx/conf/nginx.conf
      - file: /opt/nginx/conf/vhost/*.conf
 
nginx_log_cut:
  file.managed:
    - name: /opt/nginx/sbin/nginx_log_cut.sh
    - user: root
    - mode: 755
    - source: salt://nginx/files/nginx_log_cut.sh
  cron.present:
    - name: /opt/nginx/sbin/nginx_log_cut.sh
    - user: root
    - minite: 10
    - hour: 0
    - require:
      - file: nginx_log_cut

nginx conf的模板

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
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
[root@manager salt]# cat nginx/files/nginx.conf 
user {{ nginx_user }};
worker_processes  auto;
worker_cpu_affinity auto;
 
worker_rlimit_core 768m;
worker_rlimit_nofile 65536;
working_directory /opt/nginx/logs;
 
error_log logs/error.log;
 
pid logs/nginx.pid;
 
events {
    worker_connections 65535;
    use epoll;
}
 
http {
    include       mime.types;
    default_type text/plain;
 
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for" $request_time '
                      '"$host" "$upstream_addr" "$upstream_status" "$upstream_response_time"';
 
    log_format  main1 '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for" $request_time '
                      '"$host" "$upstream_addr" "$upstream_status" "$upstream_response_time" '
                      '$ssl_protocol $ssl_cipher';
 
 
    access_log  off;
 
    sendfile        on;
    tcp_nopush     on;
    client_max_body_size 20M;
    client_body_buffer_size 32k;
    client_header_timeout 25;
    max_ranges 10;
    send_timeout 15;
    keepalive_timeout 0;
    server_name_in_redirect off;
    server_tokens off;
 
    gzip on;
    gzip_buffers 32 4k;
    gzip_comp_level 9;
    gzip_disable "msie6";
    gzip_http_version 1.0;
    gzip_min_length 800;
    gzip_proxied any;
    gzip_types text/css application/x-javascript text/plain application/json;
    gzip_vary on;
 
    proxy_buffers 64 4k;
    proxy_connect_timeout 3s;
    proxy_hide_header ETag;
    proxy_http_version 1.1;
    proxy_intercept_errors on;
    proxy_max_temp_file_size 0;
    proxy_next_upstream error timeout http_502 http_503 http_504 http_500;
    proxy_read_timeout 5s;
    proxy_send_timeout 8s;
    proxy_set_header Connection Keep-Alive;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
 
    index index.html index.htm;
 
    include vhost/*.conf;
}

nginx vhost的管理
首先是pillar的配置

1
2
3
4
5
6
7
8
9
10
[root@manager srv]# cat pillar/nginx/vhost.sls 
vhost:
  {% if 'lens' in grains['id'] %}
  - name: newlens-api.networkbench.com.conf
    target: /opt/nginx/conf/vhost/newlens-api.networkbench.com.conf
    source: salt://nginx/files/vhost/newlens-api.networkbench.com.conf
  - name: lens
    target: /opt/nginx/conf/vhost/lens.networkbench.com.conf
    source: salt://nginx/files/vhost/lens.networkbench.com.conf
  {% endif %}

然后是vhost.sls

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[root@manager srv]# cat salt/nginx/vhost.sls 
include:
  - nginx.install
 
{% for vhostname in pillar['vhost'] %}
 
{{vhostname['name']}}:
  file.managed:
    - name: {{vhostname['target']}}
    - source: {{vhostname['source']}}
    - template: jinja
    - watch_in:
      service: nginx 
 
{% endfor %}

本条目发布于2014年6月9日。属于saltstack分类,被贴了 saltstack 标签。

 

 

 

http://www.opstool.com/article/293

实时管理

cmd.run的方式

执行命令

sudo salt '*' cmd.run 'uptime'

系统模块

系统自建的模块 参考salt文档 http://docs.saltstack.com/en/latest/ref/modules/all/index.html
例如查看minion的磁盘使用率,使用disk模块的usage函数

sudo salt '*' disk.usage

使用sys.doc模块查询salt模块的相关使用方法。sys.doc 相当于系统的man,可以查询salt模块的在线doc

sudo salt '*'  sys.doc disk

自定义模块

自定义模块的目录/srv/salt/_modules/,自定义模块路径一般为/srv/salt/_modules/custom.py 。 示例:

$cat /srv/salt/_modules/custom.py
def test():
  return 'i am test'

手动同步模块到minion

sudo salt '*' saltutil.sync_modules

执行模块

sudo salt '*' custom.test

Targetting

简单方式的匹配:Shell Style & Perl 正则匹配

模式 含义
* 匹配所有minion
web1 匹配web1
web* 匹配web开头的minion
web? 匹配web开头4个字符ID的minion
web[1-5] 匹配web1到web5
web[1,3] 匹配web1和web3
web1-(prod|devel) 匹配web1-prod和web1-devel

列表匹配

sudo salt -L 'web1,web2' test.ping

Grains匹配

sudo salt -G 'virtual:physical'  test.ping  #匹配所有物理机
sudo salt -G 'virtual:phy*'  test.ping  #grains匹配方式中同样可以使用 Shell Style & Perl正则方式

Pillar匹配

sudo salt -I 'master:ipv6:False' test.ping

SLS文件中的匹配方式

'virtual:physical':
     match: grain

States

states用于实现对minion进行状态管理,官方参考文档 http://docs.saltstack.com/ref/states/all/index.html
states 定义路径/src/salt(在/etc/salt/master中的file_roots变量定义),states文件使用YAML格式定义
states文件的后缀是sls(Salt State),sls文件编写需要注意在:之后要保留一个空格,否则会导致解析错误

手动执行state的方式,以修改admin账号的bashrc为例

准备/src/salt/bashrc.sls,内容如下

/home/admin/.bashrc:
  file.managed:
      - source: salt://files/bashrc
      - user: admin
      - group: admin
      - mode: 644

准备好用于分发的bash文件,salt://files/bashrc 对应/srv/salt/files/bashrc
使bash.sls生效

sudo salt '*' state.sls 'bashrc'

Highstate的方式。其实是使用top.sls作为state的入口文件

/src/salt/top.sls文件如下,top.sls引用bashrc.sls

base:
    '*':
        - bashrc

手动执行highstate生效

sudo salt '*' state.highstate

使用schedule 让minion自动执行highstate

定义 /srv/pillar/top.sls

 base:
    '*':
        - schedule

定义 /srv/pillar/schedule.sls (30分钟为单位)

schedule:
    highstate:
        function: state.highstate
            minutes: 30

Pillar

官方文档 http://docs.saltstack.com/topics/tutorials/pillar.html
pillar数据定义路径/srv/pillar, 入口文件:/srv/pillar/top.sls
查看pillar信息

sudo salt '*' pillar.data

Grains

官方文档 http://docs.saltstack.com/topics/targeting/grains.html
查看grains分类

sudo salt '*' grains.ls

查看grains所有信息

sudo salt '*' grains.items 

查看grains某个信息

sudo salt '*' grains.item osrelease 

自定义grains

grains自定义目录/srv/salt/_grains/,自定义路径/srv/salt/_grains/grans_test.py,示例:

def grans_test():
  grains = {}
  grains['grans_test'] = 'this is a grans test!'
  return grains
if __name__ == '__main__':
  print grans_test()

同步grains

sudo salt '*' saltutil.sync_grains

查看机器grains信息

sudo salt '*' grains.item grans_test

Job管理

Salt实时管理的任务都是作为Job来执行

查看正在执行的Job

sudo salt-run jobs.active

查看Job列表(包括执行过的)

sudo salt-run jobs.list_jobs

查看指定Job的状态

sudo salt-run jobs.lookup_jid 20140408112045976162

Minion状态管理

查看minion的状态up or down

sudo salt-run manage.status  #查看所有状态
sudo salt-run manage.up        #只看up的
sudo salt-run manage.down  #只看down

查看minion的版本,该命令会提示哪些minion的版本需要升级

sudo salt-run manage.versions

参考文档

 

http://www.ttlsa.com/saltstack/saltstack-pillar-grains-action-shencan-06/

前面已经讲了5章关于saltstack 的一些基本应用与基本功能(基本而已 还有很多东西我也没弄) 但是目前就这些基本的功能就能满足我们线上的业务了 下面我整理了下关于我们全网统一squid配置文件的一个案例 我顺便记录下 以便下次接着扩展

先说下原始需求

1.我们全网的squid配置文件 配置比较乱 有视频 下载 web 3种业务的配置

2.我们全网的设备 磁盘大小 磁盘块数 也不同

3.我们某些节点还有特殊配置

目前就是针对这3个需求 统一一个squid主配置文件的模板 (jinja模板)

先讲下我的思路 (我的思路可能不是最好的 但是我能保证我的配置是能用的)

1.先收集全网所以squid 配置文件 对比 分析 挑选出 其中的共同之处 (squid 性能配置一般是一样的) 然后定义存储到pillar里面

2.然后对比 那些有区别的地方 (统计一下 有多少种配置) 然后 讲每种配置 都存储到pillar 里面

3.然后编写grains 去 采集设备自身的信息 (磁盘数 服务业务等等) 然后根据自身的grains 信息 自动调用上面定义的pillar 生成文件

OK 思路就是这样 不知道 你们看懂没 总结一句话吧 1. 把不变的东西 存到pillar 里面 2. 不确定的东西 用grains 去采集 3.根据采集的值 调用不同的pillar

现在我开始讲案例吧

先说下我们全网的squid配置文件的不同之处

1. 视频 下载 web 的核心配置不一样 (我们是通过api去确定这台设备改服务什么)这个是主导方向

2.有12*1T 12*2T 的设备 ( 直接定义2种pillar )

3.还有某些自定义的配置 (预留一个自定义的pillar)

下面贴下我编写的grains python脚本吧(自定义这个一起讲过 看前面的文章去)

cat _grains/fc8.py

grains

脚本的意思 这里不用多讲了吧 还是那句话 python 牛掰了 想怎么弄 就怎么弄 按照官方源码的格式弄就行

这里说下这个脚本的用途吧 去采集3个值

1. 磁盘的块数

2.每块盘的大小

3.这台设备的应用(公司api已经有绑定)

同步下 这里不说了 saltutil.sync_grains 你懂的 验证这个也不多说了

自定义grains 就弄完了 因为我python 还没入门 说实话 刚才的脚本 我也是凑出来的 实在搞不定的就是直接用python 调用shell

然后去编写pillar值吧 这个是静态的 很简单 (例子 我前面的博客也有介绍)

我直接上配置吧

我的pillar结构就是这样的 下面我会每个挑个例子说下

grains

cache.sls 这个里面定义 squid 的cache_dir配置 (跟盘大小 跟盘数量有关 你懂的)

sc.sls 这个里面定义所以squid配置文件里面共同的配置 你懂的

core.sls 这个里面定义 核心配置(跟 服务业务有关 视频 下载 web)

optimize.sls 这个是一些调优配置 (服务业务有关 视频 下载 web)

diy.sls 这个你懂的 留个一些 特殊配置用的

ok 下面 开始讲 没个sls的 定义吧 (前面也讲过 我这里指截图一部分 )

cache.sls 的部分配置

截图为 web 业务的2种配置 下载跟视频的 也一样 挨着定义就行 这里不截图

grains

grains

看看优化配置吧 (也是根据 web 视频 下载 3大业务来分的) 下面的截图是web的

grains

其他的 也都差不多 记住我的方向是 根据业务来分的 就行 其他的配置 格式 也都一样 只是 东西不同(squid配置文件的一些东西)

OK pillar 也差不多讲完了 现在去弄弄 jinjia模板吧

我直接贴我的目标吧

grains

这个就不讲了

核心在下面

grains

判断很简单 你懂的 记住调用pillar值格式就行 我介绍一个吧

{{ pillar[‘CPISWEB’][’12_1T’] }} 就这个吧

学过python的 这个应该能看懂吧 CPISWEB 是cache.sls 里面定义的一个 针对web的 12_1T 是web的cache_dir配置 简单吧

OK 先写到这里 抽烟去了。。。。。。。

 

转自:http://www.shencan.net/index.php/2013/07/10/saltstack%E5%85%AD-pillar-grains-%E5%AE%9E%E9%99%85%E6%BC%94%E7%BB%83/

 

 

 http://blog.sina.com.cn/s/blog_c509f4d90102v53t.html

虚拟模块

模块名

描述

aliases

管理aliases file信息

alternatives

salt.modules.alternatives

apache

管理apace模块

apt

APT(Advanced Packaging Tool)支持

archive

压缩(archive)支持

at

at支持

augeas_cfg

通过augeas管理配置文件

bluez

管理Bluetooth(使用Bluez)

brew

Mac OS X的Homebrew支持

butterkvm

指定butter云组件路由

cassandra

Cassandra NoSQL数据库模块

cmdmod

A module for shelling out

config

返回配置信息

cp

minion端salt-cp支持

cron

cron支持

daemontools

daemontools服务模块

data

管理minion本地持久化的数据结构

debconfmod

Debconf支持

debian_service

Debian系列系统服务支持

disk

管理磁盘信息

djangomod

管理django站点

dnsmasq

管理dnqmasq模块

dnsutil

dns通用管理工具

dpkg

用于支持DEB 分发版本的包管理

ebuild

另外一个包管理

eix

eix 支持

event

Fire events on the minion, events can be fired up to the master

extfs

管理ex2/3/4文件系统]]

file

管理minion的文件信息,设置或读取文件属组、权限等

fressbsdjail

管理FreeBSD jail环境

freebsdmod

管理FreeBSD 内核

freebsdpkg

FreeBSD package管理支持

freebsdservice

管理FreeBSD服务

freebsd_sysctl

FreeBSD sysctl管理支持

gem

管理ruby gem

gentoolkitmod

Gentoolkit支持

gentoo_service

管理gentoo服务

git

git SCM支持

glance

Module for handling openstack glance calls.

grains

grains数据控制

groupadd

管理Linux和OpenBSD组

grub_legacy

GRUB Legacy支持

guestfs

通过libguestfs管理虚拟机镜像

hg

Mercurial SCM支持

hosts

管理hosts文件

img

虚拟机镜像管理

iptables

iptables支持

keyboard

posix-like系统键盘管理模块

key

minion key信息支持

keystone

openstack keystone调用管理

kmod

Linux内核管理模块

kvm_hyper

Provide the hyper module for kvm hypervisors

launchctl

Mac OSX launchd/launchctl管理支持

layman

Layman支持

ldapmod

ldap管理支持

linux_acl

Linux文件访问控制支持

lvm

Linux LVM2支持

linux_sysctl

Linux sysctl管理支持

locale

posix-like系统locale支持

locate

locate工具管理

logrotate

logrotate管理支持

makeconf

Support for modifying make.conf under Gentoo

mdadm

使用mdadm工具管理RAID arrary

mongodb

mongodb管理支持

monit

monit模块

moosefs

moosefs管理支持

mount

管理UNIX mount及fstab文件

muniu

Run munin plugins/checks from salt and format the output as data

mysql

mysql管理支持

network

收集和管理网络信息

nfs3

NFS3管理模块

nginx

nginx管理

nova

openstack nova调用管理

npm

Manage and query NPM packages

nzbget

nzbget支持

openbsdpkg

OpenBSD包管理

openbsdservice

OpenBSD服务管理

osxdesktop

Mac OS X implementations of various commands in the "desktop" interface

pacman

Arch pacman管理

pam

pam管理

parted

posix-like系统分区管理parted支持

pecl

PHP pecl扩展支持

pillar

minion pillar数据管理

pip

系统python或virtualenv pip管理

pkgng

pkgng支持

pkg_resource

Resources needed by pkg providers

pkgutil

Solaris Pkgutil支持

postgres

Postgres数据库管理支持

poudriere

poudriere支持

ps

A salt interface to psutil, a system and process library

publish

Publish a command from a minion to a target

puppet

puppet管理支持

pw_group

FreeBSD组管理

pw_user

FreeBSD用户管理

qemu_img

qemu镜像命令管理

qemu_nbd

qemu命令管理

quotaposix-like系统quota管理

rabbitmq

rabbitmq管理

reg

Windows注册表管理

ret

Module to integrate with the returner system and retrieve data sent to a salt

rh_ip

RHEL/Fedora网络管理

rh_service

类RHEL服务管理

rpm

rpm支持

rvm

Manage ruby installations and gemsets with RVM, the Ruby Version Manager

s3

Amazon S3支持

saltutil

The Saltutil module is used to manage the state of the salt minion itself

selinux

selinux调用管理

service

服务管理

shadow

管理shadow文件

smf

Solaris 10和11服务管理模块

solaris_group

Solaris组管理

solarispkg

Solaris包管理

solaris_shadow

Solaris shadow文件管理

solaris_user

Solaris用户管理

solr

solr模块支持

sqlite3

SQLite3支持

ssh

管理ssh客户端

state

管理minion state

status

返回minion各种状态

supervisord

Provide the service module for supervisord

svn

Subversion SCM

sysbench

sysbench支持

sysmod

he sys module provides information about the available functions on the minion

systemd

systemd服务管理

system

支持关机、重启等

test

Module for running arbitrary tests

timezone

posix-like系统timezone管理

tls

SSL/TLS模块

tomcat

tomcat支持

upstart

Module for the management of upstart systems

virt

libvirt管理支持

virtualenv

创建python virtualenv环境

win_disk

收集Windows磁盘信息

win_file

管理Windows minion文件信息

win_groupadd

管理Windows组

win_network

管理Windows网络信息

win_pkg

Windows包管理

win_service

Windows服务管理

win_shadow

Windows shadow管理

win_status

返回Windows minion各种信息

win_useradd

Windows用户管理

yumpkg5

YUM支持

yumpkg

YUM支持

zpool

ZFS支持

zypper

OpenSUSE zypper包管理支持

 

 

 http://my.oschina.net/u/877567/blog/186288

编写模块

简述

以ubuntu为例 salt 全部模块文件置于如下目录中:

/usr/share/pyshared/salt/

编写一个自定义的模块

在已定义的 file_roots 中,创建一个 _modules/ 目录,我们要扩展的外部模块就编写在这个目录下,(具体位置参见配置文件: /etc/salt/master)

描述一下这个模块的功能:检查 /etc/hostname /etc/resolv.conf 这两个文件的 attr 属性

/srv/salt/_modules/getattr.py

import os
import popen2

def run():
        cmd = "lsattr /etc/hostname /etc/resolv.conf"
        child=os.popen(cmd)
        data = child.read()
        return data

将模块分发到目标机器

salt '*' saltutil.sync_modules

命令执行完毕后,可以看到getattr.py被分发到minions主机的如下位置

/var/cache/salt/master/roots/hash/base/_modules/getattr.py.hash.md5
/var/cache/salt/minion/files/base/_modules/getattr.py
/var/cache/salt/minion/extmods/modules/getattr.py

执行自己编写的模块

salt '*' getattr.run

命令执行成功后返回信息如下:

salt-master:
    -------------e- /etc/hostname
    -------------e- /etc/resolv.conf

参考

A guide on how to write Salt modules

http://arlen.blog.51cto.com/7175583/1424216

SaltStack 通过模块来实现管理,具备丰富的模块功能,命令形式也比较自由,这里通过罗列几个有用的命令来作为入门的学习实验。

 

sys.doc : 类似linux的man命令,可以显示minion支持的模块的详细操作说明

1
2
3
4
5
6
7
8
9
10
# 这里查询  status.all_status 模块函数的使用方法
[root@yw_home monitor]# salt 192.168.0.100  sys.doc status.all_status
status.all_status:
 
    Return a composite of all status data and info for this minion.
    Warning: There is a LOT here!
 
    CLI Example:
 
        salt '*' status.all_status

 


 

status 模块是系统状态的常用信息模块,可以利用这个模块查看系统的信息

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
# 负载信息
[root@yw_home salt]# salt '192.168.0.100' status.loadavg
192.168.0.100:
    ----------
    1-min:
        0.0
    15-min:
        0.0
    5-min:
        0.0
 
# cpu信息
[root@yw_home salt]# salt '192.168.0.100' status.cpuinfo     
 
# 磁盘信息
[root@yw_home salt]# salt '192.168.0.100' status.diskstats
         
# 内存信息
[root@yw_home salt]# salt '192.168.0.100' status.meminfo    
 
# 类似w命令的返回信息
[root@yw_home salt]# salt '192.168.0.100' status.w
192.168.0.100:
    ----------
    - idle:
        10:02
    - jcpu:
        0.00s
    - login:
        183.63.100.85
    - pcpu:
        0.62s
    tty:
        pts/0
    - user:
        root
    - what:
        0.44s /usr/bin/python

 


 

test 模块

1
2
3
[root@yw_home salt]#salt '192.168.0.100' test.ping 
192.168.0.100:
    True

备注: 想更多的了解test模块,可以查看 salt 192.168.0.100 sys.doc test

 


 

cmd 模块是常用的执行远程命令模块,具有强大的功能

1
2
3
4
5
6
# cmd.run 执行一个远程shell命令
[root@yw_home salt]#salt '192.168.0.100' cmd.run 'ls -l'
 
# cmd.script 在远程minion执行一个master上的脚本,命令会从master下载脚本到minion上并执行
# 路径为file_root参数指定的路径为 salt:// 路径
[root@yw_home salt]#salt '192.168.0.100' cmd.script salt://scripts/runme.sh

 

备注: 想更多的了解cmd模块,可以查看 salt 192.168.0.100 sys.doc cmd

 


 

state 模块是salt state的管理模块,可以通过state模块简单的对minion操作sls状态

1
2
3
4
5
6
7
8
# 更新指定minons的所有sls状态
[root@yw_home salt]#salt '192.168.0.100' state.highstate
 
# 查看当前运行的sls状态
[root@yw_home salt]#salt '192.168.0.100' state.running
 
# 动态指定一个sls状态
[root@yw_home salt]#salt '192.168.0.100' state.single pkg.installed name=vim

备注: 想更多的了解cmd模块,可以查看 salt 192.168.0.100 sys.doc state

 


 

saltutil 模块 saltstack的一些辅助操作命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
saltutil.is_running:
 
    判断一个函数是否正在使用。
 
    例如:
 
        salt '*' saltutil.is_running state.highstate
     
 
saltutil.kill_job:
 
    强制关闭一个job进程
 
    例如:
 
        salt '*' saltutil.kill_job <job id>

 

备注: 想更多的了解saltUtil模块,可以查看 salt 192.168.0.100 sys.doc saltutil

 


 

上面列出的仅是saltstack的一小部分模块,saltstack有超多模块来辅助进行服务器的管理,更多信息可以参考官网下载的doc文件的最后不少章节,都是讲关于模块函数的。

本文出自 “纳米龙” 博客,请务必保留此出处http://arlen.blog.51cto.com/7175583/1424216

 

 

http://runforever.github.io/blog/2014-07-11-saltstack%E8%87%AA%E5%AE%9A%E4%B9%89%E6%A8%A1%E5%9D%97.html

SaltStack自定义模块

 

来由

公司项目以前使用的是fabric将代码部署到云平台,现在迁移到本地的服务器,
再使用fabric显然有点不合适,然而使用SaltStack的state来描述发版本的过 
程又略显不灵活,所以决定自己编写一个SaltStack的模块来实现版本发布的需求,
下面给出编写自定义模块的方法。

版本发布流程

  1. 使用git pull最新的master代码。
  2. 使用脚本替换一些变量。
  3. 一些其他的操作
  4. 重启supervisor开启的uwsgi服务。

如何编写SaltStack自定义模块

编写SaltStack自定义模块超级简单,前提是需要你会一些Python编程,具体如下: 

步骤

  1. 首先需要在master机器的file_roots 下建一个_modules文件夹,里面放.py 文件,也就是自定义模块。
    • file_roots 在/etc/salt/master 里可以设置,默认是/srv/salt/,即你需要在这个目录下新建文件夹_modules
  2. 在_modules里新建自定义模块,然后编写相应的代码。
    • 比如模块名是foo,在里面定义了方法bar。
  3. 写完代码后,使用命令 salt ‘*’ saltutil.sync_all 将自定义模块同步到各个minion上。
    • 也可以使用 salt ‘*’ saltutil.sync_modules 将自定义模块同步到minion上
  4. 运行自定也模块,使用命令 salt ‘*’ foo.bar

实例

目录结构:

srv
\-- salt
   \-- _modules
       \-- foo.py
   \-- prod
   ...

自定义模块代码:

# coding: utf-8

def bar():
    CMD_RUN = __salt__['cmd.run']
    cmd = "ls /etc/init"
    return CMD_RUN(cmd)

# 解释
# 自定义模块会加载__salt__变量,这个dict变量里包含所有的salt function
# 上面的cmd.run就是salt的命令运行函数
# __salt__变量必须在自定义的模块里使用,也就是必须在自定一的方法中使用,
# 如上面的bar方法,不能将__salt__变量放到全局变量中使用,否则会报__salt__变量为定义

注意事项

  1. 如果要使用__salt__变量,必须要在自定义的方法中使用,不能在全局变量中使用。
  2. 如果运行命令报错了,如报 foo.bar is not avaliable,请到minion机器上去查看具体的日志。
    • 报上述错误并不是模块没有同步到minion上,而是你编写的模块运行有问题。
    • minion的日志记录在/var/log/salt/minion中,可以去这里查看具体错误。

最后的思考

  1. 编写SaltStack自定义模块很简单、方便。
  2. 实现自定义模块的过程中,可以发扬NIH(Not invent here)的思想。
    • 可以充分利用__salt__变量里的salt自带函数来实现你想要的功能。

 

 

http://lixcto.blog.51cto.com/4834175/1429759

模块是个啥呢?其实就是个文件。

salt模块其实分为两类,一类模块,叫execution modules,这一类模块是在命令行上面执行的

来个内置执行模块的链接地址:

http://docs.saltstack.cn/ref/modules/all/index.html#all-salt-modules

还有一类模块,叫state modules,这一类模块是在state里面使用的

也来个内置state模块的链接:

http://docs.saltstack.cn/ref/states/all/index.html

先说执行模块是怎么写的吧。

执行模块,默认的路径在/srv/salt/_modules下

 

 

__salt__是个字典,是个啥字典呢,这个玩意,是属于salt全局的一个字典,只要我们定义的模块被minion加载后,就可以用__salt__了。

注意:这个__salt__字典,不是在我们模块里面自己定义的,而是salt全局的,我们写模块的时候直接拿来用就OK了

OK,知道__salt__是个啥之后,那个这东西里面都装了些什么玩意呢?

其实,__salt__这个字典里面装的minion上面所有的modules。__salt__的key是一个个的模块名称,value则是模块里面的一个个函数。

好,下面咱们看个例子,看看内建模块是怎么调用的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
这个foo.py是楼主自定义的一个模块,很简单,传一个参数进去,然后返回一段话
root@salt-master:~# cat /srv/salt/_modules/foo.py 
def foo(name):
    return  "I am %s" % name
     
这个cheng.py也是楼主定义的一个模块,目的是通过__salt__调用我们上面定义的那个foo模块中的
foo函数
root@salt-master:~# cat /srv/salt/_modules/cheng.py 
def cheng(name):
  return __salt__['foo.foo'](name)
 
OK,咱们同步一下模块
root@salt-master:~# salt  '*'    saltutil.sync_modules
salt-minion:
    - modules.cheng
    - modules.foo
     
好,看一下结果!
root@salt-master:~# salt  '*'    cheng.cheng lisisi
salt-minion:
    I am lisisi
root@salt-master:~#

通过这个例子,大家差不多该知道怎么调用__salt__里面的模块函数了吧。

好,咱们总结一下

使用格式:__salt__['模块.函数']('函数参数')

 

OK,下一个话题,来看看自定义的模块,怎样使用grains,pillar,以及编写文档,还有自定义输出格式。

看这个例子。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
root@salt-master:~# cat -n /srv/salt/_modules/lisisi.py 
     1  '''
     2  :maintainer:    LiXiangcheng <626659817@qq.com>
     3  :maturity:      new
     4  :depends:       
     5  :platform:      all
     6  '''
     7  __outputter__ = {
     8                  'lisisi''json'
     9                  }
    10  def lisisi(args):
    11      '''
    12      A function just one example
    13      CLI Example:
    14          salt '*' lisisi.lisisi args
    15
    16      '''
    17      grain = __grains__['chengge']
    18      pillar = __pillar__['group']
    19      result = __salt__['cmd.run'](args)
    20      result = "%s,%s,%s" % (grain,pillar,result)
    21      return  result
root@salt-master:~#

下面解释一下,1到6行都看得明白,是一些基本信息。

7到9行,是指定输出格式,__outputter__这个东西也是个字典,这个字典会绑定salt中的一个方法,当你以    函数名:输出格式   这种形式加入__outputter__这个字典后,salt就会帮你把你指定的函数,按照指定的格式打印返回值。

好了,那输出格式有哪些个呢?看下面

'grains','yaml','json','pprint','raw','highstate','quiet','key','txt','no_return','nested','virt_query'

看到了没,这么多。一般咱们用默认的就OK了,大多数的输出格式都不好看其实。楼主这里用json输出格式测试一下。

再看一下11~16行,这个东西是干啥的呢?这个东西,是把你这个函数的用法加到sys.doc里面的。

再看一下17行。这个用到grains,咋用的呢,也是通过salt默认的一个字典__grains__,你想去哪个grain的时候,这么用就ok了,__grains__['Id'] 

18行,这个用到了pillar,咋用的呢?和grains一个样,__pillar__['Id']

下面的几行就不说了。

OK,来看一下结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
好同步一下模块
root@salt-master:~# salt  '*'    saltutil.sync_modules
salt-minion:
    - modules.lisisi
     
看一下doc,看看这个函数是咋用的?
root@salt-master:~# salt '*'  -d lisisi.lisisi 
lisisi.lisisi:
 
    A function just one example
    CLI Example:
        salt '*' lisisi.lisisi args
 
     
OK,可以执行了,传个命令进行
root@salt-master:~# salt '*' lisisi.lisisi  "ls /tmp" 
{
    "salt-minion""1002,lixc,lixc1"
}
root@salt-master:~#

 

OK,关于执行模块,楼主看了官方文档,还有这么个功能,__virtual__, 这东西叫虚拟模块 

这功能楼主一看,尼玛,这东西好像和C++里面的多态虚函数,差不多。

这东西咋用的呢?官网上的例子是pkg这个模块,安装软件,有很多平台啊,有debian用的apt-get,centos用的是yum,用这个函数就可以来自动的判断。。。

楼主举个小例子吧。

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
先看一下,楼主的这个模块是咋定义的?
root@salt-master:~# cat /srv/salt/_modules/foo.py 
__virtualname__ = 'sisi'
def __virtual__():
    if __grains__['chengge'] == 1002:
        return True
    return __virtualname__
def foo(name):
    return  "I am %s" % name
 
再看一下,chengge这个grains的value是啥,和楼主那个模块里都是1002,说明__virtual__这个函数会
返回True
root@salt-master:~# salt '*' grains.item chengge
salt-minion:
  chengge: 1002
   
同步一下模块
root@salt-master:~# salt  '*'   saltutil.sync_modules
salt-minion:
    - modules.foo
     
好,执行这个模块,正常打印了吧。
root@salt-master:~# salt  '*'   foo.foo lisisi
salt-minion:
    I am lisisi
     
接着,咱们把1002随便改为1003吧,这时候1003这个值和chengge这个grain的value是不一致的,这时候
__virtual__这个函数返回__virtualname__,也就是'sisi'
root@salt-master:~# sed -i 's#1002#1003#g' /srv/salt/_modules/foo.py
 
查看一下,修改成功了没 
root@salt-master:~# grep 1003 /srv/salt/_modules/foo.py 
    if __grains__['chengge'] == 1003:
     
OK,修改之后,再同步一下模块
root@salt-master:~# salt  '*'   saltutil.sync_modules                
salt-minion:
    - modules.foo
     
再执行一下模块,看到了没,模块不可用了。
root@salt-master:~# salt  '*'   foo.foo lisisi                                    
salt-minion:
    'foo.foo' is not available.
     
再这么访问一下,看到了神奇的地方了没
root@salt-master:/srv/salt/_modules# salt '*'  sisi.foo   lixc
salt-minion:
    I am lixc

哈哈,大伙应该知道这东西大概怎么用了吧。其实__virtual__这东西,返回一个string的时候,模块就可用,当它返回False的时候。模块就不可用了。。。

如果__virtual__这个函数,返会__virtualname__,那么我们的模块的名字就会被改名,修改的名字就是__vitualname__对于的值。

我们可以根据__virtual__这个函数,来控制,自定义模块的使用场景。。。

哈哈,还有一个东西忘记提了,怎么同步模块呢,上面已经写了一种方法,楼主总结下吧。以下三种方法都可以同步模块

salt '*' state.highstate

salt '*' saltutil.sync_all

salt '*' saltutil.sync_modules

 

exection modules官方上还介绍了一个装饰器的功能。。楼主还没看懂。自定义state modules,楼主也没有看到呢,楼主先研究研究再写吧。

 

 

本文出自 “小城运维” 博客,请务必保留此出处http://lixcto.blog.51cto.com/4834175/1429759

 

 

http://www.fireinfo.cn/content-11-134-1.html

参考:http://docs.saltstack.com/en/latest/ref/modules/all/salt.modules.cp.html#module-salt.modules.cp

 

 

 

cp.cache_[file,files] 将salt://中文件复制到minions/var/cache/salt/files中

 

cp.cache_dir 将salt://中文件夹复制到minions/var/cache/salt/files中

 

cp.get_file 将salt://中文件复制到minions指定文件夹中

 

cp.get_dir 将salt://中文件夹复制到minions指定文件夹中

 

salt '*' cp.get_file salt://files/b /tmp/b

 

salt '*' cp.get_url salt://path/to/template /minion/dest 从网址中下载文件

 

salt '*' cp.get_template salt://path/to/template /minion/dest配置文件的下发,和cp.get_file类似(个人感觉)

 

salt '*' cp.hash_file salt://files/a 返回文件a的hash值

 

salt '*' cp.is_cached salt://files/a 判断a文件是否在minion的cache中

 

salt '*' cp.list_master  列出salt://files/目录下的所有文件

 

salt '*' cp.list_master_dirs 列出salt://下的所有文件夹

 

salt   '*'  cp.push /etc/fstab 从minion中下载文件

 

salt  ‘*’cp.push_dir 从minion中下载文件夹

 

http://blog.liuts.com/post/240/

  Saltstack是一个具备puppet与func功能为一身的集中化管理平台,saltstack基于python实现,功能十分强大,各模块融合度及复用性极高,官方极力推荐作为云计算平台的基础架构。轻松维护成千上万台服务器不是问题,现分享作者基于saltstack实现一个集中化的配置管理平台,以Nginx配置例子展开,涉及salt的grains、grains_module、pillar、States、jinja(template)等,本文适合有salt基础的同学阅读。
一、设备环境说明
    有两组web业务服务器,组名分别为web1group与web2group,设备硬件配置、web根目录存在异常,见下图:
    点击在新窗口中浏览此图片

二、master配置说明
    1、关键配置定义:

  1. nodegroups:  
  2.    web1group: 'L@SN2012-07-010,SN2012-07-011,SN2012-07-012'  
  3.    web2group: 'L@SN2013-08-021,SN2013-08-022'  
  4.   
  5. file_roots:  
  6.   base:  
  7.     - /srv/salt  
  8.   
  9. pillar_roots:  
  10.   base:  
  11.     - /srv/pillar  


    2、定义的文件树结构(具体文件后续说明)
点击在新窗口中浏览此图片

三、自定义grains_module
1)#vi /srv/salt/_grains/nginx_config.py

  1. import os,sys,commands  
  2.   
  3. def NginxGrains():  
  4.     ''' 
  5.         return Nginx config grains value 
  6.     '''  
  7.     grains = {}  
  8.     max_open_file=65536  
  9.     #Worker_info={'cpus2':'01 10','cpus4':'1000 0100 0010 0001','cpus8':'10000000 01000000 00100000 00010000 00001000 00000100 00000010 00000001'}  
  10.     try:  
  11.         getulimit=commands.getstatusoutput('source /etc/profile;ulimit -n')  
  12.     except Exception,e:  
  13.         pass  
  14.     if getulimit[0]==0:  
  15.         max_open_file=int(getulimit[1])  
  16.     grains['max_open_file'] = max_open_file  
  17.     return grains  


2)同步grains模块
salt '*' saltutil.sync_all

3)刷新模块(让minion编译模块)
salt '*' sys.reload_modules

4)验证max_open_file key的value
[root@SN2013-08-020 _grains]# salt '*' grains.item max_open_file              
SN2013-08-022:
  max_open_file: 1024
SN2013-08-021:
  max_open_file: 1024
SN2012-07-011:
  max_open_file: 1024
SN2012-07-012:
  max_open_file: 1024
SN2012-07-010:
  max_open_file: 1024

四、配置pillar
    本例使用分组规则定义pillar,即不同分组引用各自的sls属性
1)定义入口top.sls
#vi /srv/pillar/top.sls

  1. base:  
  2.   web1group:  
  3.     - match: nodegroup  
  4.     - web1server  
  5.   web2group:  
  6.     - match: nodegroup  
  7.     - web2server  


2)定义私有配置,本例只配置web_root的数据,当然可以根据不同需求进行定制,格式为python的字典形式,即"key:value"。
#vi /srv/pillar/web1server.sls 

  1. nginx:  
  2.     root: /www  


#vi /srv/pillar/web2server.sls 

  1. nginx:  
  2.     root: /data  


3)验证配置结果:
#salt 'SN2013-08-021' pillar.data nginx
SN2013-08-021:
    ----------
    root:
        /data

#salt 'SN2012-07-010' pillar.data nginx 
SN2012-07-010:
    ----------
    root:
        /www

五、配置States
1)定义入口top.sls
#vi /srv/salt/top.sls

  1. base:  
  2.   '*':  
  3.     - nginx   


2)定义nginx配置及重启服务SLS,其中salt://nginx/nginx.conf为配置模板文件位置。
#vi /srv/salt/nginx.sls

  1. nginx:  
  2.   pkg:  
  3.    - installed  
  4.   file.managed:  
  5.    - source: salt://nginx/nginx.conf  
  6.    - name: /etc/nginx/nginx.conf  
  7.    - user: root  
  8.    - group: root  
  9.    - mode: 644  
  10.    - template: jinja  
  11.   
  12.   service.running:  
  13.    - enable: True  
  14.    - reload: True  
  15.    - watch:  
  16.      - file: /etc/nginx/nginx.conf  
  17.      - pkg: nginx  


3)Nginx配置文件(引用jinja模板)
功能点:
1、worker_processes参数采用grains['num_cpus'] 上报值(与设备CPU核数一致);
2、worker_cpu_affinity分配多核CPU根据当前设备核数进行匹配,分别为2\4\8\其它核;
3、worker_rlimit_nofile参数与grains['max_open_file'] 获取的系统ulimit -n一致;
4、worker_connections 参数理论上为grains['max_open_file'];
5、 root参数为定制的pillar['nginx']['root']值。
#vi /srv/salt/nginx/nginx.conf

  1. # For more information on configuration, see:  
  2. user              nginx;  
  3. worker_processes  {{ grains['num_cpus'] }};  
  4. {% if grains['num_cpus'] == 2 %}  
  5. worker_cpu_affinity 01 10;  
  6. {% elif grains['num_cpus'] == 4 %}  
  7. worker_cpu_affinity 1000 0100 0010 0001;  
  8. {% elif grains['num_cpus'] >= 8 %}  
  9. worker_cpu_affinity 00000001 00000010 00000100 00001000 00010000 00100000 01000000 10000000;  
  10. {% else %}  
  11. worker_cpu_affinity 1000 0100 0010 0001;  
  12. {% endif %}  
  13. worker_rlimit_nofile {{ grains['max_open_file'] }};  
  14.   
  15. error_log  /var/log/nginx/error.log;  
  16. #error_log  /var/log/nginx/error.log  notice;  
  17. #error_log  /var/log/nginx/error.log  info;  
  18.   
  19. pid        /var/run/nginx.pid;  
  20.   
  21. events {  
  22.     worker_connections  {{ grains['max_open_file'] }};  
  23. }  
  24.   
  25.   
  26. http {  
  27.     include       /etc/nginx/mime.types;  
  28.     default_type  application/octet-stream;  
  29.   
  30.     log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '  
  31.                       '$status $body_bytes_sent "$http_referer" '  
  32.                       '"$http_user_agent" "$http_x_forwarded_for"';  
  33.   
  34.     access_log  /var/log/nginx/access.log  main;  
  35.   
  36.     sendfile        on;  
  37.     #tcp_nopush     on;  
  38.   
  39.     #keepalive_timeout  0;  
  40.     keepalive_timeout  65;  
  41.   
  42.     #gzip  on;  
  43.       
  44.     # Load config files from the /etc/nginx/conf.d directory  
  45.     # The default server is in conf.d/default.conf  
  46.     #include /etc/nginx/conf.d/*.conf;  
  47.     server {  
  48.         listen       80 default_server;  
  49.         server_name  _;  
  50.   
  51.         #charset koi8-r;  
  52.   
  53.         #access_log  logs/host.access.log  main;  
  54.   
  55.         location / {  
  56.             root   {{ pillar['nginx']['root'] }};  
  57.             index  index.html index.htm;  
  58.         }  
  59.   
  60.         error_page  404              /404.html;  
  61.         location = /404.html {  
  62.             root   /usr/share/nginx/html;  
  63.         }  
  64.   
  65.         # redirect server error pages to the static page /50x.html  
  66.         #  
  67.         error_page   500 502 503 504  /50x.html;  
  68.         location = /50x.html {  
  69.             root   /usr/share/nginx/html;  
  70.         }  
  71.   
  72.     }  
  73.   
  74. }  


4)同步配置
#salt '*' state.highstate
点击在新窗口中浏览此图片
(由于非第一次运行,看不到配置文件比对的信息)

5)验证结果:
1、登录root@SN2013-08-021
#vi /etc/nginx/nginx.conf
点击在新窗口中浏览此图片


点击在新窗口中浏览此图片

2、登录root@SN2012-07-010
#vi /etc/nginx/nginx.conf
点击在新窗口中浏览此图片


点击在新窗口中浏览此图片

 

 

 http://www.xiyang-liu.com/2014/12/saltstack-file-server-module/

原文链接:http://www.ituring.com.cn/article/41632

Salt States

参考链接: 原文Salt File Server, 官网文档cp模块

在配置管理系统中,从中心服务器想客户端推送文件是很基本的需求。SaltStack使用内建的ZeroMQ服务器做为文件服务器。 文件服务器主要用来在state系统中推送文件到客户端,也可以用于其他文件的传输。

cp模块

客户端对文件服务器的操作都在cp模块中。Salt State系统,Salt-cp都用到了cp模块。

环境

因为文件服务器是为Salt state系统服务,所以也支持环境的概念。master的配置文件中定义各环境的路径,文件的路径基于指定环境的根目录(参见下面的例子)。

常见用法

get_file

cp.get_file用来从master下载文件到客户端,语法如下:

# salt '*' cp.get_file salt://vimrc /etc/vimrc

其中vimrc在master上的实际路径要看环境中定义的根目录,假设在master中有如下定义:

file_roots:
  base:
    - /srv/salt/

那么vimrc的实际路径就是/srv/salt/vimrc,这样做的好处是,可以满足state系统中环境的概念。

源路径和目标路径中都可以使用模板,如下:

# salt '*' cp.get_file "salt://{{grains.os}}/vimrc" /etc/vimrc template=jinja

这个例子中,将下载与客户端操作系统名字相同的目录下的文件。

对于大文件,cp.get_file支持gzip压缩,在参数中指定gzip的压缩级别,如下:

# salt '*' cp.get_file salt://vimrc /etc/vimrc gzip=5

其中,1代表作小压缩,9代表最大压缩。

cp.get_file默认不在客户端上建立目录,如果客户端上没有这个目录了,文件拷贝将失败,可以指定makedirs=True来创建目录:

# salt '*' cp.get_file salt://vimrc /etc/vim/vimrc makedirs=True

在这个例子中,如果“/etc/vim不存在,将会建立此目录。

get_dir

cp.get_dir可以从master下载整个目录,语法如下:

# salt '*' cp.get_dir salt://etc/apache2 /etc

cp.get_dir也支持模板和压缩:

# salt '*' cp.get_dir salt://etc/{{pillar.webserver}} /etc gzip=5 template=jinja

get_url

cp.get_url可以从一个URL地址下载文件,URL可以是msater上的路径(salt://),也可以是http网址。

salt '*' cp.get_url salt://my/file /tmp/mine
salt '*' cp.get_url http://www.slashdot.org /tmp/index.html

get_template

cp.get_template可以在文件下载之前用模板引擎处理。

salt '*' cp.get_template salt://path/to/template /minion/dest

push

cp.push可以从客户端传文件到master上,处于很明显的安全考虑,默认没有启用此功能,如果你需要的话可以参考文档,很方便的开启。

 

 

http://linux48.com/archives/307

在server端编写模块

salt默认的根目录在/srv/salt中,没有这个目录需要建立一个

mkdir -p /srv/salt/

编写安装nginx模块

“最高同步”需要执行的top规则

#cat /srv/salt/top.sls 

base:
'*':               #通过正则去匹配所有minion
    - nginx          #这里都是我自己写的state.sls模块名 这里可以无视 后面会提到

my_app:             #通过分组名去进行匹配 必须要定义match:nodegroup
    - match: nodegroup
    - nginx

'os:Redhat':        #通过grains模块去匹配,必须要定义match:grain
    - match: grain
    - nginx

nginx安装规则

#cat /srv/salt/nginx.sls 

nginx:
  pkg:               #定义使用(pkg state module)
    - installed      #安装nginx(yum安装)
  service.running:   #保持服务是启动状态
    - enable: True
    - reload: True
    - require:
      - file: /etc/init.d/nginx
    - watch:                 #检测下面两个配置文件,有变动,立马执行上述/etc/init.d/nginx 命令reload操作
      - file: /etc/nginx/nginx.conf
      - file: /etc/nginx/fastcgi.conf
      - pkg: nginx
/etc/nginx/nginx.conf:       #绝对路径
  file.managed:
    - source: salt://files/nginx/nginx.conf  #nginx.conf配置文件在salt上面的位置
    - user: root
    - mode: 644
    - template: jinja   #salt使用jinja模块
    - require:
      - pkg: nginx

/etc/nginx/fastcgi.conf:
 file.managed:
   - source: salt://files/nginx/fastcgi.conf 
   - user: root
   - mode: 644
   - require:
     - pkg: nginx

/etc/init.d/nginx:
 file.managed:
   - source: salt://files/nginx/nginx
   - user: root
    - mode: 777
    - require:
     - pkg: nginx

在当前目录下面(salt的主目录)创建files/nginx/nginx.conf、files/nginx/fastcgi.conf文件

mkdir -p /srv/salt/files/nginx/

fastcgi.conf 配置文件

cat fastcgi.conf 

#test1111111111111111111

fastcgi_param  SCRIPT_FILENAME    $document_root$fastcgi_script_name;
fastcgi_param  QUERY_STRING       $query_string;
fastcgi_param  REQUEST_METHOD     $request_method;
fastcgi_param  CONTENT_TYPE       $content_type;
fastcgi_param  CONTENT_LENGTH     $content_length;

fastcgi_param  SCRIPT_NAME        $fastcgi_script_name;
fastcgi_param  REQUEST_URI        $request_uri;
fastcgi_param  DOCUMENT_URI       $document_uri;
fastcgi_param  DOCUMENT_ROOT      $document_root;
fastcgi_param  SERVER_PROTOCOL    $server_protocol;

fastcgi_param  GATEWAY_INTERFACE  CGI/1.1;
fastcgi_param  SERVER_SOFTWARE    nginx/$nginx_version;

fastcgi_param  REMOTE_ADDR        $remote_addr;
fastcgi_param  REMOTE_PORT        $remote_port;
fastcgi_param  SERVER_ADDR        $server_addr;
fastcgi_param  SERVER_PORT        $server_port;
fastcgi_param  SERVER_NAME        $server_name;

# PHP only, required if PHP was built with --enable-force-cgi-redirect
fastcgi_param  REDIRECT_STATUS    200;

nginx.conf配置文件

cat nginx.conf

# For more information on configuration, see:
#   * Official English Documentation: http://nginx.org/en/docs/
#   * Official Russian Documentation: http://nginx.org/ru/docs/
# test111111111111111111111
user              nginx;
worker_processes  1;

error_log  /var/log/nginx/error.log;
#error_log  /var/log/nginx/error.log  notice;
#error_log  /var/log/nginx/error.log  info;

pid        /var/run/nginx.pid;


events {
    worker_connections  1024;
}


http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                    '$status $body_bytes_sent "$http_referer" '
                    '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    #keepalive_timeout  0;
    keepalive_timeout  65;

    #gzip  on;

    # Load config files from the /etc/nginx/conf.d directory
    # The default server is in conf.d/default.conf
    include /etc/nginx/conf.d/*.conf;

}

nginx启动脚本

cat nginx

#!/bin/sh
#
# nginx - this script starts and stops the nginx daemon
#
# chkconfig:   - 85 15
# description:  Nginx is an HTTP(S) server, HTTP(S) reverse \
#               proxy and IMAP/POP3 proxy server
# processname: nginx
# config:      /etc/nginx/nginx.conf
# config:      /etc/sysconfig/nginx
# pidfile:     /var/run/nginx.pid

# Source function library.
. /etc/rc.d/init.d/functions

# Source networking configuration.
. /etc/sysconfig/network

# Check that networking is up.
[ "$NETWORKING" = "no" ] && exit 0

nginx="/usr/sbin/nginx"
prog=$(basename $nginx)

sysconfig="/etc/sysconfig/$prog"
lockfile="/var/lock/subsys/nginx"
pidfile="/var/run/${prog}.pid"

NGINX_CONF_FILE="/etc/nginx/nginx.conf"

[ -f $sysconfig ] && . $sysconfig


start() {
    [ -x $nginx ] || exit 5
    [ -f $NGINX_CONF_FILE ] || exit 6
    echo -n $"Starting $prog: "
    daemon $nginx -c $NGINX_CONF_FILE
    retval=$?
    echo
    [ $retval -eq 0 ] && touch $lockfile
    return $retval
}

stop() {
    echo -n $"Stopping $prog: "
    killproc -p $pidfile $prog
    retval=$?
    echo
    [ $retval -eq 0 ] && rm -f $lockfile
    return $retval
}

restart() {
    configtest_q || return 6
    stop
    start
}

reload() {
    configtest_q || return 6
    echo -n $"Reloading $prog: "
    killproc -p $pidfile $prog -HUP
    echo
}

configtest() {
    $nginx -t -c $NGINX_CONF_FILE
}

configtest_q() {
    $nginx -t -q -c $NGINX_CONF_FILE
}

rh_status() {
    status $prog
}

rh_status_q() {
    rh_status >/dev/null 2>&1
}

# Upgrade the binary with no downtime.
upgrade() {
    local oldbin_pidfile="${pidfile}.oldbin"

    configtest_q || return 6
    echo -n $"Upgrading $prog: "
    killproc -p $pidfile $prog -USR2
    retval=$?
    sleep 1
    if [[ -f ${oldbin_pidfile} && -f ${pidfile} ]];  then
        killproc -p $oldbin_pidfile $prog -QUIT
        success $"$prog online upgrade"
        echo 
        return 0
    else
        failure $"$prog online upgrade"
        echo
        return 1
    fi
}

# Tell nginx to reopen logs
reopen_logs() {
    configtest_q || return 6
    echo -n $"Reopening $prog logs: "
    killproc -p $pidfile $prog -USR1
    retval=$?
    echo
    return $retval
}

case "$1" in
    start)
        rh_status_q && exit 0
        $1
        ;;
    stop)
        rh_status_q || exit 0
        $1
        ;;
    restart|configtest|reopen_logs)
        $1
        ;;
    force-reload|upgrade) 
        rh_status_q || exit 7
        upgrade
        ;;
    reload)
        rh_status_q || exit 7
        $1
        ;;
    status|status_q)
        rh_$1
        ;;
    condrestart|try-restart)
        rh_status_q || exit 7
        restart
            ;;
    *)
        echo $"Usage: $0 {start|stop|reload|configtest|status|force-reload|upgrade|restart|reopen_logs}"
        exit 2
esac

还可以多加几个配置文件,此处只列出重要的

在server端执行安装过程

# salt '*' state.sls nginx   

test-minion:
----------
      ID: nginx
Function: pkg.installed
  Result: True
 Comment: The following packages were installed/updated: nginx.
 Changes:   
          ----------
          nginx:
              ----------
              new:
                  1.0.15-5.el6
              old:

----------
      ID: /etc/init.d/nginx
Function: file.managed
  Result: True
 Comment: File /etc/init.d/nginx updated
 Changes:   
          ----------
          diff:
              ---  
              +++  
              @@ -137,7 +137,7 @@
                   condrestart|try-restart)
                       rh_status_q || exit 7
                       restart
              -         ;;
              +            ;;
                   *)
                       echo $"Usage: $0 {start|stop|reload|configtest|status|force-reload|upgrade|restart|reopen_logs}"
                       exit 2

          mode:
              0777
----------
      ID: /etc/nginx/nginx.conf
Function: file.managed
  Result: True
 Comment: File /etc/nginx/nginx.conf updated
 Changes:   
          ----------
          diff:
              ---  
              +++  
              @@ -1,7 +1,7 @@
               # For more information on configuration, see:
               #   * Official English Documentation: http://nginx.org/en/docs/
               #   * Official Russian Documentation: http://nginx.org/ru/docs/
              -
              +# test111111111111111111111
               user              nginx;
               worker_processes  1;

              @@ -34,7 +34,7 @@
                   keepalive_timeout  65;

                   #gzip  on;
              -    
              +
                   # Load config files from the /etc/nginx/conf.d directory
                   # The default server is in conf.d/default.conf
                   include /etc/nginx/conf.d/*.conf;

----------
      ID: /etc/nginx/fastcgi.conf
Function: file.managed
  Result: True
 Comment: File /etc/nginx/fastcgi.conf updated
 Changes:   
          ----------
          diff:
              ---  
              +++  
              @@ -1,3 +1,4 @@
              +#test1111111111111111111

               fastcgi_param  SCRIPT_FILENAME    $document_root$fastcgi_script_name;
               fastcgi_param  QUERY_STRING       $query_string;

----------
      ID: nginx
Function: service.running
  Result: True
 Comment: Service nginx has been enabled, and is running
 Changes:   
          ----------
          nginx:
              True

Summary
------------
Succeeded: 5
Failed:    0
------------
Total:     5

还有别的规则也可以全量执行

#salt '*' state.highstate

到此就可以大批量的为服务器安装nginx了,当然这只是初探saltstack,后续还有更详细的功能。

 

 

http://www.2cto.com/os/201401/270398.html

本文从sal命令行命令执行的角度,剖析一下saltstack的运行过程。代码分析过程结合运行日志进行解析。

命令执行过程

在终端输入salt '*' cmd.run ls命令

#salt "*" cmd.run ls
cloudstack-agent_4.2.0_all.deb
cloudstack-common_4.2.0_all.deb
zmq

我们看一下salt master的输出日志

2014-01-03 14:28:36,087 [master.py] [_handle_clear] [640] [master] [-1221166336] [MainThread] [salt.master ][INFO ] Clear payload received with command publish
2014-01-03 14:28:36,497 [master.py] [publish] [2520] [master] [-1221166336] [MainThread] [salt.master ][INFO ] User root Published command cmd.run with jid 20140103142836087085
2014-01-03 14:28:36,499 [master.py] [publish] [2530] [master] [-1221166336] [MainThread] [salt.master ][DEBUG ] Published command details {'tgt_type': 'glob', 'jid': '20140103142836087085', 'tgt': 'stack', 'ret': '', 'user': 'root', 'arg': ['ls'], 'fun': 'cmd.run'}
2014-01-03 14:28:38,617 [master.py] [_handle_aes] [664] [master] [-1221166336] [MainThread] [salt.master ][INFO ] AES payload received with command _return
2014-01-03 14:28:38,622 [master.py] [_return] [1236] [master] [-1221166336] [MainThread] [salt.master ][INFO ] Got return from stack for job 20140103142836087085
2014-01-03 14:28:39,201 [master.py] [_handle_clear] [640] [master] [-1221166336] [MainThread] [salt.master ][INFO ] Clear payload received with command _auth
2014-01-03 14:28:39,203 [verify.py] [check_max_open_files] [392] [verify] [-1221166336] [MainThread] [salt.utils.verify][DEBUG ] This salt-master instance has accepted 1 minion keys.
2014-01-03 14:28:39,205 [master.py] [_auth] [1795] [master] [-1221166336] [MainThread] [salt.master ][INFO ] Authentication request from stack
2014-01-03 14:28:39,208 [master.py] [_auth] [1922] [master] [-1221166336] [MainThread] [salt.master ][INFO ] Authentication accepted from stack
2014-01-03 14:28:40,371 [master.py] [_handle_aes] [664] [master] [-1221166336] [MainThread] [salt.master ][INFO ] AES payload received with command _return
2014-01-03 14:28:40,374 [master.py] [_return] [1236] [master] [-1221166336] [MainThread] [salt.master ][INFO ] Got return from stack for job 20140103142836087085

看一下客户端minion的运行日志

2014-01-03 14:28:36,522 [minion.py] [_handle_aes] [612] [minion] [-1221879040] [MainThread] [salt.minion ][INFO ] User root Executing command cmd.run with jid 20140103142836087085
2014-01-03 14:28:36,527 [minion.py] [_handle_aes] [618] [minion] [-1221879040] [MainThread] [salt.minion ][DEBUG ] Command details {'tgt_type': 'glob', 'jid': '20140103142836087085', 'tgt': 'stack', 'ret': '', 'user': 'root', 'arg': ['ls'], 'fun': 'cmd.run'}
2014-01-03 14:28:37,790 [minion.py] [parse_args_and_kwargs] [165] [minion] [-1221879040] [MainThread] [salt.minion ][DEBUG ] Parsed args: ['ls']
2014-01-03 14:28:37,842 [minion.py] [parse_args_and_kwargs] [166] [minion] [-1221879040] [MainThread] [salt.minion ][DEBUG ] Parsed kwargs: {'__pub_user': 'root', '__pub_arg': ['ls'], '__pub_fun': 'cmd.run', '__pub_jid': '20140103142836087085', '__pub_tgt': 'stack', '__pub_tgt_type': 'glob', '__pub_ret': ''}
2014-01-03 14:28:37,913 [cmdmod.py] [_run] [283] [cmdmod] [-1221879040] [MainThread] [salt.loaded.int.module.cmdmod][INFO ] Executing command 'ls' in directory '/root'
2014-01-03 14:28:38,607 [cmdmod.py] [run] [501] [cmdmod] [-1221879040] [MainThread] [salt.loaded.int.module.cmdmod][DEBUG ] output: cloudstack-agent_4.2.0_all.deb
cloudstack-common_4.2.0_all.deb
zmq
2014-01-03 14:28:38,610 [minion.py] [_return_pub] [828] [minion] [-1221879040] [MainThread] [salt.minion ][INFO ] Returning information for job: 20140103142836087085

执行过程解析

1. Salt stack的Master与Minion之间通过ZeroMq进行消息传递,使用了ZeroMq的发布-订阅模式,连接方式包括tcp,ipc

2. salt命令,将cmd.run ls命令从salt.client.LocalClient.cmd_cli发布到master,获取一个Jodid,根据jobid获取命令执行结果。

3. master接收到命令后,将要执行的命令发送给客户端minion。

4. minion从消息总线上接收到要处理的命令,交给minion._handle_aes处理

5. minion._handle_aes发起一个本地线程调用cmdmod执行ls命令。线程执行完ls后,调用minion._return_pub方法,将执行结果通过消息总线返回给master

6. master接收到客户端返回的结果,调用master._handle_aes方法,将结果写的文件中

7. salt.client.LocalClient.cmd_cli通过轮询获取Job执行结果,将结果输出到终端。

心得:

1. Salt master和minion之间通过zeromq进行通信,传递消息。阅读salt源码,需要了解zeromq的使用方法

2. salt都使用了zeromq的pub-sub模式,req-rep模式

3. salt 使用了tcp,ipc的通信模式

 

http://blog.cunss.com/?p=282

官方文档:
 
 
默认情况下,发送给salt minion的命令执行结果将返回给salt master.

Saltstack Returner的接口允许将结果发送给任意系统

 

和pillar、modules一样,returners需要在master端创建目录

 

 

[root@test81 _returners]# pwd
/srv/salt/_returners

将返回结果写到本地:
[root@test81 _returners]# cat local_return.py
#coding:utf-8
def __virtual__():
   '''调用时的名字'''
   return "local_return"
def returner(ret):
    f=open('/var/log/salt/local_returner.log','a+')
    f.write(str(ret)[1:-1]+'\n')
    f.close()

 

同步到各minion

 

[root@test81 _returners]# salt '*' saltutil.sync_returners
192.168.2.100:
    - returners.local_return
test82.salt.cn:
    - returners.local_return
test83.salt.cn:
    - returners.local_return
192.168.2.84:
    - returners.local_return

 

 

运行:
#–return 后面跟的参数是returners里面指定__virtual__这个方法返回

 

[root@test81 _returners]# salt '192.168.2.84' cmd.run 'who ' --return local_return   
192.168.2.84:
    root pts/0 Feb 19 13:08 (192.168.2.100)

 

 

在minions端查看:
[root@test84 salt]# tail /var/log/salt/local_returner.log

 

[root@test84 salt]# tail /var/log/salt/local_returner.log
'jid': '20140219142855265028', 'return': ' 14:28:56 up 8 days, 21:56, 1 user, load average: 0.56, 0.21, 0.13', 'retcode': 0, 'success': True, 'fun': 'cmd.run', 'id': '192.168.2.84'
'jid': '20140219143706008256', 'return': ' 14:37:06 up 8 days, 22:04, 1 user, load average: 0.14, 0.12, 0.09', 'retcode': 0, 'success': True, 'fun': 'cmd.run', 'id': '192.168.2.84'
'jid': '20140219144258880492', 'return': 'root pts/0 Feb 19 13:08 (192.168.2.100)', 'retcode': 0, 'success': True, 'fun': 'cmd.run', 'id': '192.168.2.84'

已经成功写入到文件

 

 

 

 

下面我们来看下将返回值写到mysql的实现,官方的例子https://github.com/saltstack/salt/blob/develop/salt/returners/mysql.py

 

1、创建salt存放数据库,使用如下sql

 

 CREATE DATABASE `salt`
      DEFAULT CHARACTER SET utf8
      DEFAULT COLLATE utf8_general_ci;
    USE `salt`;
    --
    -- Table structure for table `jids`
    --
    DROP TABLE IF EXISTS `jids`;
    CREATE TABLE `jids` (
      `jid` varchar(255) NOT NULL,
      `load` mediumtext NOT NULL,
      UNIQUE KEY `jid` (`jid`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    --
    -- Table structure for table `salt_returns`
    --
    DROP TABLE IF EXISTS `salt_returns`;
    CREATE TABLE `salt_returns` (
      `fun` varchar(50) NOT NULL,
      `jid` varchar(255) NOT NULL,
      `return` mediumtext NOT NULL,
      `id` varchar(255) NOT NULL,
      `success` varchar(10) NOT NULL,
      `full_ret` mediumtext NOT NULL,
      KEY `id` (`id`),
      KEY `jid` (`jid`),
      KEY `fun` (`fun`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

 

 

 

创建访问数据库用户
 
GRANT ALL PRIVILEGES ON salt.* to ‘salt’@'%’ identified by ‘salt’;
 
 
在master端创建mysql returner脚本

 

[root@test81 _returners]# cat mysql_return.py
from contextlib import contextmanager
import sys
import json
import logging
try:
    import MySQLdb
    HAS_MYSQL = True
except ImportError:
    HAS_MYSQL = False
log = logging.getLogger(__name__)
def __virtual__():
    if not HAS_MYSQL:
        return False
    return 'mysql'
def _get_options():
    '''
    Returns options used for the MySQL connection.
    '''
    defaults = {'host': '192.168.2.100',
                'user': 'salt',
                'pass': 'salt',
                'db': 'salt',
                'port': 3306}
    _options = {}
    for attr in defaults:
        _attr = __salt__['config.option']('mysql.{0}'.format(attr))
        if not _attr:
            log.debug('Using default for MySQL {0}'.format(attr))
            _options[attr] = defaults[attr]
            continue
        _options[attr] = _attr
    return _options
@contextmanager
def _get_serv(commit=False):
    '''
    Return a mysql cursor
    '''
    _options = _get_options()
    conn = MySQLdb.connect(host=_options['host'], user=_options['user'], passwd=_options['pass'], db=_options['db'], port=_options['port'])
    cursor = conn.cursor()
    try:
        yield cursor
    except MySQLdb.DatabaseError as err:
        error, = err.args
        sys.stderr.write(error.message)
        cursor.execute("ROLLBACK")
        raise err
    else:
        if commit:
            cursor.execute("COMMIT")
        else:
            cursor.execute("ROLLBACK")
    finally:
        conn.close()
def returner(ret):
    '''
    Return data to a mysql server
    '''
    with _get_serv(commit=True) as cur:
        sql = '''INSERT INTO `salt_returns`
                (`fun`, `jid`, `return`, `id`, `success`, `full_ret` )
                VALUES (%s, %s, %s, %s, %s, %s)'''
        cur.execute(sql, (ret['fun'], ret['jid'],
                            str(ret['return']), ret['id'],
                            ret['success'], json.dumps(ret)))

 

 

同步mysql  returners到minions

 

 

[root@test81 _returners]# salt '*' saltutil.sync_returners
192.168.2.100:
    - returners.mysql_return
test83.salt.cn:
    - returners.mysql_return
test82.salt.cn:
    - returners.mysql_return
192.168.2.84:
    - returners.mysql_return
执行
#192.168.2.100(minions) 上面需要安装Mysql-python模块

 

 

 

[root@test81 _returners]# salt '192.168.2.100' cmd.run 'uptime' --return mysql
192.168.2.100:
     15:19:11 up 6:13, 6 users, load average: 0.84, 0.87, 0.89

 

查看mysql:

 

mysql> select * from salt_returns;
+---------+----------------------+---------------------------------------------------------------+---------------+---------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| fun | jid | return | id | success | full_ret |
+---------+----------------------+---------------------------------------------------------------+---------------+---------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| cmd.run | 20140219151909502559 | 15:19:11 up 6:13, 6 users, load average: 0.84, 0.87, 0.89 | 192.168.2.100 | 1 | {"jid": "20140219151909502559", "return": " 15:19:11 up 6:13, 6 users, load average: 0.84, 0.87, 0.89", "retcode": 0, "success": true, "fun": "cmd.run", "id": "192.168.2.100"} |
+---------+----------------------+---------------------------------------------------------------+---------------+---------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

 

OK,Very Good!已经成功将返回结果写入mysql

总结:使用saltstack的returners再加上自定义modules,只要写一个监控主机的状态的模块,加上salt自带很多获取主机信息的模块,再把模块的返回结果入数据库,这样就可以轻松实现分布式的监控。

 

 

 

##################################################################################

 http://www.ahlinux.com/mainte/9915.html

之前写过一片博文介绍了saltstack的安装配置,由于最近忙着办理离职,就没有更新了,对不起自己,说好的要坚持下去的。这篇博文准备记录一 下saltstack作为文件服务器,从master向minions分发文件的功能。我们知道,类似于hadoop、hbase、zookeeper这 些与分布式系统相关的组件在安装配置的时候,往往是一个节点上修改好配置文件后,然后用scp远程拷贝到其他节点上去,如果你有10个节点的话,那么同一 条远程拷贝的命令需要执行多次,显然不是一个好办法。那么问题来了,自动化运维之远程分发文件到底哪家强?哈哈,自然是神器saltstack啦!我们需 要借助saltstack来实现从master端向minions推送文件的需求。

Saltstack内置了一个简单的文件服务器用于master分发文件给minions,这个文件服务器是基于zeroMQ消息队列实现的,客户端对文件服务器的操作全部封装在了cp这个模块中。

首先看环境:

hadoop0.updb.com    192.168.0.100    OS:CentOS 6.5        Role:master

uadoop2.updb.com    192.168.0.202    OS:CentOS 6.5        Role:minion

uadoop3.updb.com    192.168.0.203    OS:CentOS 6.5        Role:minion

在开始saltstack的配置管理之前,要首先指定saltstack所有状态文件的根目录,在master上做如下操作

## 首先修改master的配置文件,指定根目录,注意缩进全部使用两个空格来代替Tab(python规范)
[root@hadoop0 ~]# vi /etc/salt/master 
file_roots:
  base:
    - /srv/salt
  dev:
    - /srv/salt/dev     
## 确定指定的目录是否存在,如果不存在,需要手动来创建目录
[root@hadoop0 ~]# ls /srv/salt/ -ld
drwxr-xr-x 2 root root 4096 Nov  6 23:54 /srv/salt/
[root@hadoop0 ~]# ls /srv/salt/dev/ -ld
drwxr-xr-x 2 root root 4096 Nov  7 00:36 /srv/salt/dev/
## 重启master服务
[root@hadoop0 ~]# /etc/init.d/salt-master  restart 
Stopping salt-master daemon:                               [  OK  ]
Starting salt-master daemon:                               [  OK  ]

首先介绍cp.get_file,用来从master端下载文件到minion的指定目录下,如下

## 在master上创建测试用的文件
[root@hadoop0 ~]# echo 'this is test file with module of cp.get_file!' > /opt/getfile.txt
## 拷贝测试文件到master配置的根目录下
[root@hadoop0 ~]# cp /opt/getfile.txt /srv/salt/
## 在master执行文件的分发
[root@hadoop0 ~]# salt 'uadoop2' cp.get_file salt://getfile.txt /opt/getfile.txt 
uadoop2:
    /opt/getfile.txt
## 分发成功,在minion上查看文件是否已经发送到uadoop2上了
[root@uadoop2 ~]# cat  /opt/getfile.txt 
this is test file with module of cp.get_file!

使用cp.get_file进行文件的分发时时也可以指定是否对分发的文件进行压缩,如下

## 使用gzip的方式进行压缩,数字越大,压缩率就越高,9代表最大的压缩率
[root@hadoop0 ~]# salt 'uadoop2' cp.get_file salt://getfile.txt /opt/getfile.txt gzip=9
uadoop2:
    /opt/getfile.txt
## 分发成功,在minion上查看文件是否已经发送到uadoop2上了    
[root@uadoop2 ~]# cat  /opt/getfile.txt 
this is test file with module of cp.get_file!

当minion上的目标目录不存在时,可以使用makedirs参数来创建目标目录,如下

[root@hadoop0 ~]# salt 'uadoop2' cp.get_file salt://getfile.txt /opt/test/getfile.txt makedirs=True
uadoop2:
    /opt/test/getfile.txt
## 分发成功,在minion上查看文件是否已经发送到uadoop2上了  
[root@uadoop2 ~]# cat /opt/test/getfile.txt 
this is test file with module of cp.get_file!

在开始下一个示例之前,先介绍一下grains,这个接口的作用是在minion端的minion服务启动时,调用这个接口,收集minion 端的信息,这些信息数据可以在salt的其他模块中直接使用,需要注意的是,这个接口只在minion端的minion服务启动时被调用一次,所以收集的 数据是静态的,不会改变的,除非你重启了minion端的服务,关于这点,官方文档是这样说明的:

    Grains Static bits of information that a minion collects about the system when the minion first starts.
The grains interface is made available to Salt modules and components so that the right salt minion commands are
automatically available on the right systems.
    It is important to remember that grains are bits of information loaded when the salt minion starts, so this information
is static. This means that the information in grains is unchanging, therefore the nature of the data is static. So grains
information are things like the running kernel, or the operating system.
## 使用grains.ls列出可以在其他模块中直接使用的grains
[root@hadoop0 ~]# salt 'uadoop2' grains.ls
uadoop2:
  - biosreleasedate
  - biosversion
  - cpu_flags
  - cpu_model
  - cpuarch
  - defaultencoding
  - defaultlanguage
  - domain
  - fqdn
  - fqdn_ip4
  - fqdn_ip6
  - gpus
  - host
  - hwaddr_interfaces
  ..............

## 使用grains.items模块列出所有可用grains的具体数据
[root@hadoop0 ~]# salt 'uadoop2' grains.items
uadoop2:
  biosreleasedate: 07/31/2013
  biosversion: 6.00
  cpu_flags: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts mmx fxsr sse sse2 ss syscall nx rdtscp lm constant_tsc arch_perfmon pebs bts xtopology tsc_reliable nonstop_tsc aperfmperf unfair_spinlock pni pclmulqdq ssse3 cx16 pcid sse4_1 sse4_2 x2apic popcnt aes xsave avx hypervisor lahf_lm ida arat epb xsaveopt pln pts dts
  cpu_model: Intel(R) Core(TM) i7-2630QM CPU @ 2.00GHz
  cpuarch: x86_64
  defaultencoding: UTF8
  defaultlanguage: en_US
  domain: prolexic.com
  fqdn: unknown.prolexic.com
  fqdn_ip4:
    72.52.4.120
  fqdn_ip6:
  gpus:
    {'model': 'SVGA II Adapter', 'vendor': 'unknown'}
  host: unknown
  hwaddr_interfaces: {'lo': '00:00:00:00:00:00', 'eth0': '00:0c:29:b7:1d:85'}
  id: uadoop2
  ip_interfaces: {'lo': ['127.0.0.1'], 'eth0': ['192.168.0.202']}
  ipv4:
    127.0.0.1
    192.168.0.202
  ipv6:
    ::1
    fe80::20c:29ff:feb7:1d85
  kernel: Linux
  kernelrelease: 2.6.32-431.el6.x86_64
  ..............  

## ping测试grains中os的值为CentOS的主机通信是否正常
[root@hadoop0 ~]# salt -G 'os:CentOS' test.ping
uadoop2:
  True		

## 查看uadoop2主机的ip地址,注意这里不是items噢,而是item
[root@hadoop0 ~]# salt 'uadoop2' grains.item ipv4
uadoop2:
  ipv4:
    127.0.0.1
    192.168.0.202

好了,在介绍了grains接口之后,接下来看下在cp模块中如何简单的使用grains的数据呢

## 首先在状态配置文件的根目录下创建一个CentOS目录,然后将位于根目录下的getfile.txt测试文件
mv到CentOS目录下
[root@hadoop0 ~]# mkdir  /srv/salt/CentOS/
[root@hadoop0 ~]# mv  /srv/salt/getfile.txt /srv/salt/CentOS/
## 然后执行文件分发的命令,注意这里要使用salt内置模版jinja才能分发成功
[root@hadoop0 ~]# salt 'uadoop2' cp.get_file "salt://{{grains.os}}/getfile.txt" /opt/getfile.txt template=jinja
uadoop2:
    /opt/getfile.txt

接着介绍cp.get_dir,get_dir与get_file的用法十分相似,用来将整个目录分发到minions

## 创建测试目录
[root@hadoop0 ~]# mkdir /srv/salt/test_dir
## 创建测试文件
[root@hadoop0 ~]# echo 'hello a !' > /srv/salt/test_dir/a.txt
[root@hadoop0 ~]# echo 'hello b !' > /srv/salt/test_dir/b.txt 
## 执行目录文件的分发,并使用压缩传输
[root@hadoop0 ~]# salt 'uadoop2' cp.get_dir salt://test_dir /opt/ gzip=9 
uadoop2:
  - /opt//test_dir/a.txt
  - /opt//test_dir/b.txt

## 分发成功,验证
[root@uadoop2 ~]# ls /opt/test_dir/   
a.txt  b.txt
[root@uadoop2 ~]# cat /opt/test_dir/a.txt 
hello a !
[root@uadoop2 ~]# cat /opt/test_dir/b.txt  
hello b !

在往下介绍之前,首先介绍一下salt的pillar接口,pillar是salt中比较重要的组件,跟grains有些相似,但是 pillar相比于grains更加灵活,而且是动态的,数据可以随时更新,只要你愿意的话。而grains只在minion启动时采集一次数据,关于 pillar官网描述如下,简单翻译一下,但不保证翻译的到位,意思是说pillar是salt实现部署功能的最重要的组件,能够为minions生成非 常灵活的数据,这些数据可以被salt的其他的组件所使用。

    The pillar interface inside of Salt is one of the most important components of a Salt 
deployment. Pillar is the interface used to generate arbitrary data for specific minions. 
The data generated in pillar is made available to almost every component of Salt.

pillar的基本用法

## 使用pillar之前要在master中配置pillar的工作目录,将下面三行的注释打开
[root@hadoop0 ~]# vi /etc/salt/master
pillar_roots:
  base:
  - /srv/pillar
## 重启master服务 
[root@hadoop0 ~]# /etc/init.d/salt-master restart 
Stopping salt-master daemon:							   [  OK  ]
Starting salt-master daemon:							   [  OK  ]
## 创建所需目录
[root@hadoop0 ~]# mkdir  /srv/pillar/
## 该目录用来测试使用
[root@hadoop0 ~]# mkdir  /srv/pillar/user
## 首先在/srv/pillar目录中要有一个入口文件top.sls
[root@hadoop0 pillar]# vi top.sls 
base:
  'uadoop2':
  - data		 ## 为uadoop2定义了一个属性数据,引用了跟top.sls同目录下的data.sls
  
  'uadoop3':
  - webserver	## 为uadoop3定义了一个属性数据,引用了跟top.sls同目录下的web.sls

  '*':
  - user		 ## 为所有节点定义了一个属性数据,引用了/srv/pillar/user/init.sls
           ## 这里指定的是一个目录,salt会自动在top.sls文件中的引用目录中寻找状态文件
           ## 因此会找到位于user目录中的init.sls文件
        
## 编写在top.sls文件中引用的状态文件
[root@hadoop0 pillar]# vi data.sls
data: some data
[root@hadoop0 pillar]# vi webserver.sls 
webserver: test_dir
[root@hadoop0 pillar]# vi user/init.sls 
users:
  kora: 1000
  kadefor: 1100
  foway: 1200

## 接着将master上定义的属性同步到对应的minion上去
[root@hadoop0 pillar]# salt '*' pillar.items
uadoop3:
  ----------
  master:
    ----------
    auth_mode:
      1
    auto_accept:
      False
  .............省略N行..............
    worker_threads:
      5
  webserver:
    test_dir
  users:
    ----------
    foway:
      1200
    kadefor:
      1100
    kora:
      1000
uadoop2:
  ----------
  data:
    some data
  master:
    ----------
    auth_mode:
      1
  .............省略N行..............	   
    worker_threads:
      5
  users:
    ----------
    foway:
      1200
    kadefor:
      1100
    kora:
      1000

## 在master上远程获取刚刚定义的属性
[root@hadoop0 pillar]# salt 'uadoop2' pillar.item data
uadoop2:
  ----------
  data:
    some data
[root@hadoop0 pillar]# salt 'uadoop3' pillar.item webserver
uadoop3:
  ----------
  webserver:
    test_dir  
[root@hadoop0 pillar]# salt '*' pillar.item users
uadoop2:
  ----------
  users:
    ----------
    foway:
      1200
    kadefor:
      1100
    kora:
      1000
uadoop3:
  ----------
  users:
    ----------
    foway:
      1200
    kadefor:
      1100
    kora:
      1000
## 可以看到刚刚为不同的minion定义的属性已经同步到了各个minion上,从这个测试可以看出,使用pillar
## 我们可以为不同的minion或者不同的minion组定义不同的属性,极其灵活。

好了,在介绍了pillar接口之后,接下来看下在cp模块中如何简单的使用pillar定义的属性数据呢

## 我们可以利用之前定义的属性来匹配不同的minion
[root@hadoop0 pillar]# salt -I 'users:kora:1000' test.ping
uadoop2:
  True
uadoop3:
  True
[root@hadoop0 pillar]# salt -I 'data:*some*' test.ping	  
uadoop2:
  True
[root@hadoop0 pillar]# salt -I 'webserver:test_dir' test.ping	 
uadoop3:
  True

## 匹配uadoop3,然后在master上远程分发文件到uadoop3上去
[root@hadoop0 pillar]# salt -I 'webserver:test_dir' cp.get_dir "salt://{{pillar.webserver}}" /opt/ gzip=9 template=jinja	
uadoop3:
  - /opt//test_dir/a.txt
  - /opt//test_dir/b.txt

从远程执行的结果来看文件已经分发成功,上面的例子就演示了pillar接口定义的属性在cp模块中的简单使用,我们可以通过pillar为不同minion指定的属性及其值来匹配对应的minion,非常的灵活。

好了,关于salt文件服务器就介绍到这里。虽然我也只是简单的体验了一下,但是依旧被salt作为文件服务器的强大功能所震精。有了salt 的文件分发功能后,真的是鸟枪换炮。当然不需要使用好多条scp命令,只需要写好配置文件,分好组,一条命令过去,完成所有节点的文件分发。

 

 

 

 http://www.geedoo.info/salt-use-notes.html

Grains使用

节点信息(grains)

# 查看grains分类
salt ‘*’ grains.ls

# 查看grains所有信息
salt ‘*’ grains.items

# 查看grains某个信息
salt ‘*’ grains.item osrelease

自定义Grains

自定义grains  就是想客户端汇报你想要的数据到服务器,这个可以通过2个方法实现 第一个是在服务器端 往客户端推(可以过滤指定客户端) 第二个就是直接在客户端配置文件里面编辑。下面说第二种方法:

新建grains配置文件:

vim /etc/salt/minion.d/grains_test.conf  填写一些数据;

grains:
  Wen: 1
  Liu: 2
  List:
    - a
    - b
    - c

好了重启miinon服务,在master上查看
salt "Master.Hadoop" grains.items

[root@Master ~]# salt "Master.Hadoop" grains.items 
Master.Hadoop:
  List:
      a
      b
      c
  Liu: 2
  Wen: 1

想法:利用这个特性,做个数据收集系统。通过程序去修改客户端配置文件的属性。缺点:要重启minion

Pillar使用

pillar 是在master服务器上定义的  默认安装没有这个文件夹 自己新建一个就行,目录要和/etc/salt/master中的pillar_roots一致

mkdir /srv/pillar/ && touch  /srv/pillar/top.sls

base:
  '*':
    - sc

不多说,这里配置和含义和state差不多

新建sc.sls,填入相应的数据:

[root@Master pillar]# cat sc.sls 
a: 1
b: 2
c: )))))))))))))))))

OK 配置完后 我们查看下吧 有没有生效

在服务器端运行 salt ‘*′ pillar.data

从结果中可以看到相应的值。

总结:其实pillar和state很类似,不同的是state描述的是状态,pillar描述的是kv的变量。

参考:http://www.shencan.net/index.php/2013/05/24/saltstack-%E4%BA%8C-grains%E5%92%8Cpillar/

Salt cp命令使用

大集群下文件分发如果使用scp来做的话,呵呵,累死不偿命啊!

今天教大家尝试使用salt-cp功能来实现文件分发。

我想做的事情:由于我的hadoop集群有很多项目,都是安装cdh4的rpm包,因此有很多项目的配置文件是分开的,但是又集中在/etc下。我想每次修改完配置可以使用一个命令直接分发修改的目录(或文件)到个节点。以前是使用scp,但是集群大了,没法干了。

解决方法:

让salt文件服务器管理/etc目录,修改配置/etc/salt/master

file_roots:
   base:
     - /srv/salt/
     - /etc
   dev:
     - /srv/salt/dev/services
     - /srv/salt/dev/states

只是在base下添加了/etc目录作为salt文件服务器的另一个文件目录。

重启salt-master。

参看目录是否存在,存在则说明配置成功:
salt '*' cp.list_master_dirs

查看master上的文件:
salt '*' cp.list_master

分发文件:
salt '*' cp.get_file salt://path/to/file /minion/dest

分发目录:
salt '*' cp.get_dir salt://path/to/dir/ /minion/dest

例子:
salt '*' cp.get_dir salt://impala/ /etc/

总结:好了,是不是很方便啊?如果可以的话直接配置成根目录,那就可以管理系统所有文件 / 目录了

参考:salt.modules.cp

定时任务(cron)

查看某用户的定时任务,如 root用户:
salt '*' cron.list_tab root
同上,查看的是文本形式
salt '*' cron.raw_cron root
移除某用户的定时任务:
salt '*' cron.rm_job root /usr/local/weekly
设置某用户的定时任务:
salt '*' cron.set_job root '*' '*' '*' '*' 1 /usr/local/weekly
例如:

salt "*" cron.set_job root 0 1 '*' '*' '*' '/usr/sbin/ntpdate cn.pool.ntp.org'
注意: * 要加引号,最后一个参数也要加引号,不然会当成两个参数

http://ju.outofmemory.cn/entry/60807

 

http://my.oschina.net/u/877567/blog/213047

 

目录[-]

grains

minion基本信息的管理

基本使用:

salt '*' grains.ls  查看grains分类
salt '*' grains.items 查看grains所有信息
salt '*' grains.item osrelease 查看grains某个信息

自定义grains信息

Grains 信息可以在 minion 配置文件 /etc/salt/minion 中静态定义,自定义的 grains 可以将 Core grains 定义的信息覆盖,示例如下:

grains:
  roles:
    - webserver
    - memcache
  deployment: datacenter4
  cabinet: 13
  cab_u: 14-15

如果不希望将配置信息定义在 /etc/salt/minion 可以将配置信息写入 /etc/salt/grains,示例如下:

roles:
  - webserver
  - memcache
deployment: datacenter4
cabinet: 13
cab_u: 14-15

重启 salt-minion 服务后,在 salt 'host' grains.items 可以查看自定义的信息是否生效,下面有几种自定义grains的方式,如果这些定义方式同时存在,则遵守如下由低到高的优先级:

  1. Core grains.
  2. Custom grains in /etc/salt/grains.
  3. Custom grains in /etc/salt/minion.
  4. Custom grain modules in _grains directory, synced to minions.

Each successive evaluation overrides the previous ones, so any grains defined in /etc/salt/grains that have the 
same name as a core grain will override that core grain. Similarly, /etc/salt/minion overrides both core grains 
and grains set in /etc/salt/grains, and custom grain modules will override any grains of the same name

salt '*' grains.item osrelease
  minoin1:
    osrelease: 6.2

在用salt进行管理客户端的时候或者写state的时候都可以引用grains的变量

文档:http://docs.saltstack.com/topics/targeting/grains.html

pillar

salt敏感信息的管理,只有匹配到的节点才能看到和使用

salt '*' pillar.items

文档:http://docs.saltstack.com/topics/tutorials/pillar.html

开启敏感信息配置管理 Pillar settings

编辑 /etc/salt/master 文件

pillar_roots:
  base:
    - /srv/pillar

mkdir -p /srv/pillar

默认:pillar数据定义文件存储路径:/srv/pillar

入口文件:/srv/pillar/top.sls

base:
  "targeting":
    - pillar            #名字为pillar.sls的文件来存放对匹配到的minion的变量

$pillar.sls

#基本:

$key: $value
#对应state引用方式: {{ pillar['$key'] }} 

#复杂:
users:
  thatch: 1000
  shouse: 1001
  utahdave: 1002
  redbeard: 1003   
#state引用方式:
#{% for user, uid in pillar.get('users', {}).items() %}
#  {{user}}:
#    user.present:
#      - uid: {{uid}}
#{% endfor %}

查看节点的pillar数据:

salt 'client2' pillar.data

同步pillar:

salt '*' saltutil.refresh_pillar

附:这里我们可以看到,pallar中也可以使用jinja

文档:http://docs.saltstack.com/topics/tutorials/pillar.html

 

 

 

http://www.mageyoyo.com/?p=455

rains 这个跟puppet的facter功能一样。主要负责采集客户端一些基本信息, 这个也完全可以自定义,可以在客户端自定义,然后自动汇报上来;也可以从服务器端定义然后推下去,采集完后,再汇报上来;pillar 跟grains 比较的话 他的灵活性强点,怎么定义就这么定义,然后取值就行

 

QQ截图20140912094852
QQ截图20140912095443
然后可以通过

 

 

查看单项值
QQ截图20140912095718
使用grains添加自动以items
第一种方法: minion端:
修改/etc/salt/minion打开default_include: minion.d/.conf, 在/etc/salt/minion.d/目录中添加需要增加的items,文件类型与配置项.conf对应

 

 

重启minion端 service salt-minion restart
在master端查看item添加的属性
QQ截图20140912100711

第二种方法:
mkdir -p /srv/salt/_grains
在master端添加_grains文件夹编写grains文件,需要返回一个字典

 

 

推送_grains模块

 

 

重新加载模块,刷新grains静态数据

 

 

20140913194309
表示自定义grains定义成功

pillar

Pillar 是 Salt 非常重要的一个组件,它用于给特定的 minion 定义任何你需要的数据, 这些数据可以被 Salt 的其他组件使用。Salt 在 0.9.8 版本中引入了 Pillar。Pillar 在解析完成 后,是一个嵌套的 dict 结构;最上层的 key 是 minion ID,其 value 是该 minion 所拥有的 Pillar 数据;每一个 value 也都是 key/value。这里可以看出 Pillar 的一个特点,Pillar 数据是与特定 minion 关联的,也就是说每一个minion 都只能看到自己的数据, 所以 Pillar 可以用来传递敏感数据 (在 Salt 的设计中, Pillar 使用独立的加密 session,也是为了保证敏感数据的安全性) 。 Pillar 可以用在哪些地方?

敏感数据
例如 ssh key,加密证书等,由于 Pillar 使用独立的加密 session,可以确保这些敏感数据不被其他 minion 看到。

变量
可以在 Pillar 中处理平台差异性,比如针对不同的操作系统设置软件包的名字,然后在State 中引用。

其他任何数据
可以在 Pillar 中添加任何需要用到的数据。比如定义用户和 UID 的对应关系,mnion 的角色等。

用在 Targetting 中
Pillar 可以用来选择 minion,使用-I 选项
默认情况下,master 配置文件中的所有数据都添加到 Pillar 中,且对所有 minion 可用。如果要禁用这一默认值,可以在 master 配置文件中添加如下数据,重启服务后生效,关于Pillar的配置见 /etc/salt/master

 

 

 

 

然后执行 salt ‘test82.salt.cn’ pillar.data 命令查看

 

 

出现刚刚添加的字段,成功。

 

 

 

http://arlen.blog.51cto.com/7175583/1424444

什么是Grains

    Grains是服务器的一系列粒子信息,也就是服务器的一系列物理,软件环境信息。在执行salt的sls时候可以根据Grains信息的不同对服务器进行匹配分组,例如可以根据系统是centos服务器跟系统是redhat环境的安装不同的软件包。

 

Grains是什么样子

下面是一台Dell R420的粒子信息

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
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
[root@yw_home ~]# salt 192.168.0.100 grains.items
192.168.0.100:
  biosreleasedate: 03/11/2013
  biosversion: 1.5.2
  cpu_flags: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon pebs bts rep_good xtopology nonstop_tsc aperfmperf pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 cx16 xtpr pdcm pcid dca sse4_1 sse4_2 x2apic popcnt tsc_deadline_timer aes xsave avx lahf_lm ida arat xsaveopt pln pts dts tpr_shadow vnmi flexpriority ept vpid
  cpu_model: Intel(R) Xeon(R) CPU E5-2420 0 @ 1.90GHz
  cpuarch: x86_64
  defaultencoding: UTF8
  defaultlanguage: en_US
  domain: localdomain
  external_ip: 192.168.0.100
  fqdn: localhost.localdomain
  fqdn_ip4:
      127.0.0.1
  fqdn_ip6:
      ::1
  gpus:
      {'model''G200eR2''vendor''unknown'}
  host: localhost
  hwaddr_interfaces: {'lo''00:00:00:00:00:00''em1''保密隐去''em2''保密隐去'}
  id: 192.168.0.100
  ip_interfaces: {'lo': ['127.0.0.1'], 'em1': ['192.168.0.100'], 'em2': []}
  ipv4:
      127.0.0.1
      192.168.0.100
  ipv6:
      ::1
      fe80::92b1:1cff:fe50:d4ac
  kernel: Linux
  kernelrelease: 2.6.32-431.el6.x86_64
  localhost: 192.168.0.100
  manufacturer: Dell Inc.
  master: 192.168.0.100
  mem_total: 64377
  nodename: 192.168.0.100
  num_cpus: 24
  num_gpus: 1
  os: CentOS
  os_family: RedHat
  osarch: x86_64
  oscodename: Final
  osfinger: CentOS-6
  osfullname: CentOS
  osmajorrelease:
      6
      5
  osrelease: 6.5
  path: /sbin:/usr/sbin:/bin:/usr/bin
  productname: PowerEdge R420
  psps -efH
  pythonpath:
      /usr/bin
      /usr/lib64/python26.zip
      /usr/lib64/python2.6
      /usr/lib64/python2.6/plat-linux2
      /usr/lib64/python2.6/lib-tk
      /usr/lib64/python2.6/lib-old
      /usr/lib64/python2.6/lib-dynload
      /usr/lib64/python2.6/site-packages
      /usr/lib64/python2.6/site-packages/gtk-2.0
      /usr/lib/python2.6/site-packages
      /usr/lib/python2.6/site-packages/setuptools-0.6c11-py2.6.egg-info
  pythonversion: 2.6.6.final.0
  saltpath: /usr/lib/python2.6/site-packages/salt
  saltversion: 2014.1.0
  saltversioninfo:
      2014
      1
      0
  serialnumber: 保密隐去
  server_id: 保密隐去
  shell: /bin/sh
  virtual: physical

 

从上面的信息可以看出,grains其实是一系列的服务器信息,从信息里可以看到服务器是一台dell r420型号的物理机器,系统是centos6.5,cpu是E5-2420 24核。通常我们进行采购都是一批次的产品,所以使用grains可以轻易的进行批量管理。当然,也可以通过自定义grains来分组管理我们的服务器。

 

 

怎么运用Grains

 

第一种,命令行中使用,salt 命令中使用grains

1
2
3
4
5
6
7
8
9
#对系统是CentOS的服务器进行ping测试操作
#os:CentOS ; 就是对应上面grains.items显示出来的os值是CentOs的对象进行匹配 
salt -G 'os:CentOS' test.ping
 
#对cpu架构是x86_64的服务器显示CPU的个数
salt -G 'cpuarch:x86_64' grains.item num_cpus
 
#对字典值的对象进行匹配
salt -G 'ip_interfaces:em1:192.168.0.*'

 

第二种,在SLS中使用grains

1
2
3
4
5
# 在top.sls中使用grais
 
'os:CentOS':
    - match: grain
    - webserver

 

上面是在top.sls中定义对系统是CentOs的服务器执行webserver.sls定义的状态信息.

 

 

进阶,自定义Grains

 

Grains的四种存在形式

1
2
3
4
Core grains.
在 /etc/salt/grains 自定义grains。
在 /etc/salt/minion 自定义grains。
在 _grains 目录自定义grain,同步到minions。

 

自定义的grains编写格式参考上面grains.items显示出来的格式

  • 直接值对应 

1
os:CentOS
  • 字典格式

1
ip_interfaces: {'lo': ['127.0.0.1'], 'em1': ['192.168.0.100'], 'em2': []}
  • 分多行值的列表格式

1
2
3
osmajorrelease:
      6
      5

 

  • Core Grains : 是salt定义好的grains,后面三种自定义的grains,如果名称跟Core grains定义的一样,将会覆盖掉Core grains定义的值.

 

  • /etc/salt/grains  : 单独的grains来放置自定义的grains可以更加好的独立***。 

1
2
3
4
5
6
roles:
  - webserver
  - memcache
deployment: datacenter4
cabinet: 13
cab_u: 14-15

 

* 上面的内容定义了四个grain。 roles是一个列表,还有deployment,cabinet,cab_u三个值

*  需要重启minion才能生效

 

  • /etc/salt/minion : 这个的定义跟在/etc/salt/grains中的定义一样,只不过要多个grains的声明

1
2
3
4
5
6
7
grains : 
  roles:
    - webserver
    - memcache
  deployment: datacenter4
  cabinet: 13
  cab_u: 14-15

 

*  需要重启minion才能生效

 

  • _grains 目录自定义grain : 

假设使用默认的master 的file_roots配置路径 /srv/salt ,那么_grains的位置是/srv/salt/_grains 

1
2
3
4
5
6
7
8
9
# mkdir /srv/salt/_grains
# vim /srv/salt/_grains/my_grain.py
## 添加下面内容
    def my_grains():
        grains = {'roles' : ['phpserver','webserver']}
        return grains
         
# salt '192.168.0.100' saltutil.sync_grains
# salt '192.168.0.100' grains.item roles

 

这里是通过定以一个grains模块注入给minion一个roles信息。

如果查询grains.items roles无法查出相关信息,可以重启下master,再重新测试

 

下面给给出一个Core grains定义的一个例子,使用了比较复杂的方式来定义grains,更多的信息点击这里

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
saltutil.sync_grainsdef _windows_cpudata():
    '''
    Return some CPU information on Windows minions
    '''
    # Provides:
    # num_cpus
    # cpu_model
    grains = {}
    if 'NUMBER_OF_PROCESSORS' in os.environ:
        # Cast to int so that the logic isn't broken when used as a
        # conditional in templating. Also follows _linux_cpudata()
        try:
            grains['num_cpus'] = int(os.environ['NUMBER_OF_PROCESSORS'])
        except ValueError:
            grains['num_cpus'] = 1
    grains['cpu_model'] = platform.processor()
    return grains

 

  • 分发自定义的grains到客户端

1
2
3
4
### 下面的三个操作均会将自定义的grains分发到192.168.0.100上
#salt '192.168.0.100' state.highstate
#salt '192.168.0.100' saltutil.sync_all
#salt '192.168.0.100' saltutil.sync_grains

 

 

 

本文出自 “纳米龙” 博客,请务必保留此出处http://arlen.blog.51cto.com/7175583/1424444

 

 

 

=============================================================================

 

http://www.ituring.com.cn/article/41737

Targeting

Targeting

通过客户端的hostname,系统信息,预定义的分组或复合条件来选择执行命令或配置状态的目标机器。

比如说命令salt web1 apache.signal restart只会重启web1上的apache服务。

在State系统也类似,以下的top file只让客户端web1执行webserver.sls

base:
  'web1':
    - webserver

Salt目前有5种方式来选择目标机器,灵活而强大。

  • 匹配minion id
    • 使用shell通配符
    • 正则(Perl风格)
    • minion列表
  • Grains
    • 可用的Grains
    • 在客户端配置文件中定义Grains
    • 编写Grains
  • 节点分组
  • 复合匹配
  • 批量执行

匹配minion id

minion id

客户端(minion)的唯一标志符。默认值是主机的FQDN,也可以在配置文件中修改。

每一个客户端都需要唯一标志符。minion第一次启动时选择FQDN作为标志符。默认值可以在minion配置文件中用id来覆盖。

Tip

minion idminion keys

minion id  minion 公/私钥对的名字,如果修改了 minion id master 需要重新接受新的key,否则 minion 不能通过 master 的认证。操作和添加新的 minion 一样。

shell通配符 Globbing

Salt默认使用shell风格通配符('*','?','[]')来匹配minion id。在State系统中的top file也一样。

Note

使用 salt 命令时必须将'*'放在单引号中,或是用'\'转义,不然 shell 会在 salt 之前扩展'*'。

匹配所有客户端:

salt '*' test.ping

匹配所有example.net域或者example域的客户端:

salt '*.example.net' test.ping
salt '*.example.*' test.ping

匹配example.net域中的webN客户端(web1.example.net, web2.example.net … webN.example.net):

salt 'web?.example.net' test.ping

匹配web1web5

salt 'web[1-5]' test.ping

匹配web-xweb-yweb-z

salt 'web-[x-z]' test.ping

正则表达式 Regular Expressions

Salt可以使用Perl风格的正则表达式来匹配minion id,使用选项-E

匹配web1-prodweb1-devel

salt -E 'web1-(prod|devel)' test.ping

Statetop file,需要将匹配方式作为第一个选项。以下例子在和上面相同的客户端上执行webserver中的内容。

base:
  'web1-(prod|devel)':
  - match: pcre
  - webserver

minion列表 Lists

最基本的,可以列出每一个minion id来指定多个目标机器,使用选项'-L'。

salt -L 'web1,web2,web3' test.ping

使用 Grains

Grains

minion启动时收集的关于系统的静态信息。

需要注意的是,grainsminion启动时加载的,在运行过程中不会发生变化,所以是静态数据。grains中包含诸如运行的内核版本,操作系统等信息。

grains示例

匹配所有系统是CentOS的客户端:

salt -G 'os:CentOS' test.ping

匹配所有64位CPU的机器,并返回CPU核心数:

salt -G 'cpuarch:x86_64' grains.item num_cpus

有哪些可用的grains?

grains在客户端上运行,收集客户端的信息,所有不同的客户端可以有不同的grains。使用grains.ls模块列出目标机器上所有可用的grains的名字。

salt '*' grains.ls

grains.item列出所有grains的名字及内容。

salt '*' grains.items

在客户端配置文件中定义grains

内置的grains不一定满足需求,可以在minion的配置文件中静态定义grains

grains:
  roles:
    - webserver
    - memcache
  deployment: datacenter4
  cabinet: 13
  cab_u: 14-15

重启minion服务后,grains.ls就可以列出roles等自定义的grainsgrains数据不仅可以用salt命令查询,还可以在state系统和Targeting中用来匹配目标机器。

编写Grains

minion配置文件中定义的grains是静态的,不能够动态的在minion上生成。可以用Python非常方便的写动态的grainsminion启动时,会执行grains包所带的模块及自定义grains模块中的公开函数,返回的结果就是grainsgrains模块中的函数必须返回一个dict,其中keygrains的名字,value是值。

Note

这里的动态 grains 是指 minion 启动时动态生成,事先并不知道内容,在启动后,这些值依然是不变的。

很明显,自定义的grains并不是直接放在minion上,而是放在master配置文件中定义的file_roots下的_grains目录中。执行state.highstatesaltutil.sync_grainssaltutil.sync_all时,会将_grains中的文件分发到客户端上。

假定file_roots/srv/salt,增加自定义grain的操作如下:

# mkdir /srv/salt/_grains
# vim /srv/salt/_grains/custom_grain.py
    def custom_grains():
        ''' 
            only a test grain.
            you could use any Python code to generate the grains list dynamicly.
        '''
        grains = {'role' : 'LB'}
        return grains
# salt '*' saltutil.sync_grains
# salt '*' grains.item role

由于是作为模块导入,custom_grain.py中不需要#!/usr/bin/env python行,也不需要有执行权限。

节点组 Node Groups

Node group

masternodegroups用复合条件定义的一组minion。 复合匹配在下面的内容有详细介绍。

nodegroups配置示例:

nodegroups:
  group1: 'L@foo.domain.com,bar.domain.com,baz.domain.com or bl*.domain.com'
  group2: 'G@os:Debian and foo.domain.com'

使用-N选项:

salt -N group1 test.ping

top file中用- match: nodegroup来指定使用节点组匹配。

base:
  group1:
    - match: nodegroup
    - webserver

复合匹配 Compound matchers

Compound matcher

用布尔操作符连接的多个目标条件。

复合匹配可以用前面讨论的几种方式实现更精确的匹配。复合匹配默认使用Globbing,要使用其他匹配方式的话,需要加上类型前缀字母,现在实现的字母详细列表,请参考文档

复合匹配中也可以使用andornot操作符,比如说,下面的命令匹配主机名以webserv开始且运行Debian系统的minion,还匹配主机名满足正则web-dc1-srv.*minion

salt -C 'webserv* and G@os:Debian or E@web-dc1-srv.*' test.ping

本例中,G表示用shell通配符匹配grainsE表示用正则匹配minion id。 这个例子在top file中如下:

base:
  'webserv* and G@os:Debian or E@web-dc1-srv.*':
    - match: compound
    - webserver

注意not不能用于第一个条件,需要用如下命令:

salt -C '* and not G@kernel:Darwin' test.ping

批量执行 Batch Size

在指定数量或百分比的机器上执行命令。

salt \* -b 10 test.ping

salt -G 'os:RedHat' --batch-size 25% apache.signal restart

第一条命令在所有的客户端上执行test.ping,但同一时间只有10台机器运行此命令,当有minion返回执行结果是,再让下一个minion执行。 第二条命令在系统是RedHat的客户端中重启apache服务,但同一时间只有25%的机器执行重启,直到所有目标机器执行完成。

Batch Size并不减少总的数量,只是限制同时执行任务的机器数量。这非常有用,比如,在负载均衡web集群中,可以只用一条命令分批的重启web服务。

 

 

 

 

 

https://github.com/kerncai/saltstack/blob/master/salt%E7%9A%84grains%E4%BD%BF%E7%94%A8%E4%BB%A5%E5%8F%8Acmd.run.md

 

 

grains.items主要用来收集minion端的信息,方便进行信息采集,后续的piller使用,根据硬件信息自动匹配配置文件等。

基本用法

grains.ls

salt '*' grains.ls 显示所有minion的item

grains.items

salt '*' grains.items 显示所有minion的item值

grains.item

salt '*' grains.item os 显示os的相关信息。如下 :
root@salt ~ # salt 'sa10-003' grains.item os
sa10-003:
  os: RedHat

如果想同时获取多个item,可以在后面接空格后,直接相关item,如下:

root@salt ~ # salt 'sa10-003' grains.item os osrelease oscodename
sa10-003:
  os: RedHat
  oscodename: Tikanga
  osrelease: 5.8

自定义grains: 首先,现在salt的根目录下(/srv/salt)建一个目录_grains

mkdir /srv/salt/_grains
cd /srv/salt/_grains

假设我要取minion端内存的信息 事例如下: vim mem.py

# -*- coding: utf-8 -*-

'''
Module for squid disk information by python
'''
import commands
import os

def cache():
    '''
    Return the memory usage information for volumes mounted on this minion
    '''
    grains={}
    m = commands.getoutput("free -g|awk '$0~/Mem/ {print$2+1}'")
    grains['mem_test']=int(m)

    return grains

同步到minion端

root@salt _grains # salt 'sa10-003' saltutil.sync_all 
sa10-003:
    ----------
    grains:
        - grains.mem #已经同步过来了
    modules:
    outputters:
    renderers:
    returners:
    states:

如果需要更改模块,更改完成后,可以使用下面命令重载:

salt sa10-003 sys.reload_modules

验证下之前的自定义grains:

root@salt _grains # salt sa10-003 grains.item mem_test
sa10-003:
  mem_test: 2

sa10-003的内存信息:

[root@sa10-003 salt]# free -m
             total       used       free     shared    buffers     cached
Mem:          2012       1766        246          0        286       1207
-/+ buffers/cache:        272       1739
Swap:            0          0          0

在saltmaster上面自定义grains取到的信息和本机是一致的


除了salt自带和我们自定义的items可以取到系统信息之外,我们还可以使用shell命令在来达到目的;当然,这需要salt的另外一个强大的命令,cmd.run 我要取sa10-003的内存信息,可以使用下面的命令:

root@salt _grains # salt sa10-003 cmd.run 'free -m'
sa10-003:
                 total       used       free     shared    buffers     cached
    Mem:          2012       1769        242          0        286       1207
    -/+ buffers/cache:        275       1736
    Swap:            0          0          0

cmd.run在master端进行操作,后面跟着的是系统相关的shell命令,这种方式,可以实现minion端几乎所有的命令。

 

 

http://www.furion.info/414.html

 

 最近一直搞基于saltstack的配置管理中心,遇到了一个grains和highstate的坑,正好趁这个机会也好好总结grains。

 

1.什么是grains:

 

Grains
Static bits of information that a minion collects about the system when the minion first starts.

The grains interface is made available to Salt modules and components so that the right salt minion commands are automatically available on the right systems.

 

     以上是官方的解释,大致意思是说grains是minion第一次启动的时候采集的静态数据,可以用在salt的模块和其他组件中。其实grains在每次的minion启动(重启)的时候都会采集,即向master汇报一次的。这个很重要,可以让某些同学企图使用grains值来做监控死心了。

 

2.应用场景:

 

      grains的特性–每次启动汇报、静态决定了它没有pillar灵活,要知道pillar是随时可变的,只要在master端修改了那一般都会立刻生效的。所以grains更适合做一些静态的属性值的采集,例如设备的角色(role),磁盘个数(disk_num)等诸如此类非常固定的属性。

 

     那么我们就可以得到一个大致的判断,如果你想定义的属性值是经常变化的,那请采用pillar,如果是很固定、不易变的那请用grains。

 

    

3.grains vs pillar:

 

    grains和pillar的差别是很多同学都会问的问题,具体的讨论不再细说,参见saltstack用户组的相关讨论(https://groups.google.com/forum/#!topic/saltstack-users-cn/wXGcz0N6814)。总结下来有以下几点:

 

     1.grains存储的是静态、不常变化的内容,pillar则相反

     2.grains是存储在minion本地,而pillar存储在master本地

     3.minion有权限操作自己的grains值,如增加、删除,但minion只能查看自己的pillar,无权修改

    

 

4.grains优先级:

   

     grains可以保持在minion端、通过master端下发等多个方式来分发。但不同的方法有不同的优先级的:

    1. /etc/salt/grains

   2. /etc/salt/minion

   3./srv/salt/_grains/  master端_grains目录下

 

    优先级顺序依次为存在在minion端/etc/salt/minion配置文件中的同名grains会覆盖/etc/salt/grains文件中的值,而通过master端_grains目录下grains文件下发的值可以会覆盖minion端的所有同名值。比较拗口,总之记得,通过master下发的grains优先级是最高的可,/etc/salt/minion次之,/etc/salt/grains最低(core grains不大懂,就不讨论了,这个比/etc/salt/grains还低)。

  

 

5.grains的下发:

 

     grains的下发大致可以分为两个思路:

 

      1.自定义的(_grains)可以通过state.highstatesaltutil.sync_grainssaltutil.sync_all 等方法批量下发,切记所有在_grains目录下的所有自定义grains值都会下发到minion,这是血的教训。

 

      2.固定存放在minion端配置文件中,如grains、minion文件中,可以通过file manager的方法去批量下发/etc/salt/grains等配置文件实现grains的批量下发,当然了也通过别的方式把这个文件批量下发下去,都是ok的。

     

       对比:

       1. 通过state.highstate 下发的grains好处是无须重启minion即可生效,但通过下发/etc/salt/grains文件下发的grains值则必须重启minion端服务才可以生效。

 

      2.自定义的_grains每次在highstate调用的时候就会自动下发、刷新,而/etc/salt/grains文件的则不会。

 

6.当_grains遇到highstate:

 

     切记每次state.highstate都会刷新_grains下定义的grain值,那么意味着如果你采用了schedule的方式去实现minion端自动获取配置的时候,那对应的grains每次也是会刷新的。

 

 

 

     有些同学可能觉得无所谓,都是浮云了。But想象一种情况(这是我的痛,倒腾了小半个下午去查这个问题),你如果在_grains目录下定义了一些自定义grains值:

     

 

 

     fc[‘role’] = ‘cpisfc_web’ ,role这个值定义了设备的角色,而不同的业务需要每次修改这个role的值去表示设备的业务归属。

 

    现在有一批设备(100台左右)全部都是跑cpisfc_web业务,那对应的role也是cpisfc_web,ok没问题,我们直接saltutil.sync_all 下发grains值,master端会根据设备具有的role值自动下发相应的配置(web的配置)以及schedule这个pillar值(主要用来做配置自动抓取)的。

 

    现在又有一批(20台)需要跑cpisfc_down的业务,同样我们简单修改了下fc.py中的role改为cpisfc_down、随后下发grains值,master同样根据设备的role下发了cpisfc_down的配置和schedule这个pillar值。

 

    就是这里,粗大事了!截止到目前都是一切和谐的,但马上就要很黄很暴力了。还记得我们前面下发一个scheduce的pillar值吧。10分钟到了,minion调用highstate自动连接到master去抓取自己的配置,这个时候role为cpisfc_web的设备发现_grains/fc.py被修改了,于是它们自动下发新的fc.py(fc[‘role’] = ‘cpisfc_down’ ),然后就是发现自己的role角色变了,最后通过role的适配抓取了新的cpisfc_down的配置!于是所有的设备的role都变成了cpisfc_down,对应的所有的配置都被下发成了down的配置,我直接就吓跪了。。

 

 

7.grains“动静态”分离:

 

    接上面,研究了半天才发现原因是highstate这个混蛋导致的啊,妈蛋。其实这个官方早就有说明了,只是自己没仔细,惭愧个:

   “Custom grains should be placed in a _grains directory located under the file_rootsspecified by the master config file. They will be distributed to the minions whenstate.highstate is run, or by executing the saltutil.sync_grains or saltutil.sync_allfunctions.“

 

   没辙,highstate我是必须要用的,而且也必须用_grains目录这种自定义grains的方法去下发大部分grains值,主要原因是涉及到很多动态计算的东西,如disk_size等,这些属性会根据minion的实际配置去获取的。

 

   那唯一的办法就是拆分了,将grains中的动态生成部分、静态部分(role等)拆分开。具体做法如下:

 

 

 

 

     那么每次下发grains的步骤就变成了:

 

 

 

 

      通过这个sls文件将role属性下发,后续的就不用管了,master会根据minion的role角色自动适配相应的pillar(包含schedule的highstate),后续的配置文件也会自动推送了。终于解决了,世界太平了。

 

7.总结:

     

   “人生若之如初见”,saltstack也只是看上去很美而已,也存在不少的问题滴。saltstack是不错,但更多的问题不在于saltstack而在于与运维本身,借用庆爷的话就是salt解决不了运维真正的痛,所有的东西都是只是工具,真正自动化的道路还是“路漫漫其修远兮”,与各位同勉。

 

 

 

 

 

 

 

 

==============================================================================

 

 

http://pengyao.org/salt-pillar-01.html

Salt中Pillar那点事

基本简介

在 SaltStack 中, Pillar作为定义minion全局数据的接口. 默认存储在master端, Minion启动时会连接master获取最新的pillar数据. Pillar使用类似于State Tree的结构, 默认使用 YAML 作为其描述格式, 在Minion内部最终转换成 Python字典 .

那么在Salt内部, Pillar是如何工作的? 在哪些情况下,需要先执行刷新Pillar操作? 而哪些又不需要?

本文基于 Salt 2014.1.4

配置文件中的Pillar

pillar_roots
存在于master/minion配置文件中. 指定Pillar roots对应环境的目录, 其布局类似于State Tree. 在minion配置文件中配置该选项, 只有当file_client 为 local 时才生效.
state_top
存在于master/minion配置文件中, 默认值为top.sls. 官方描述为用于state system, 用于告诉minion使用哪个环境并且需要执行哪些模块. 其实该选项也应用在pillar system中, 作用和state system类似. 所以如果更改了本选项, pillar system对应的top.sls也需要变更. 在minion配置文件中配置该选项, 只有当 file_client 为 local 时才生效.
file_client
存在于minion配置文件中, 默认值为remote. 用于指定去哪里查找文件. 有效值是 remote 和 localremote 表示使用master, local 用于Masterless 的情况.
pillar_opts
存在于master配置文件中, 默认值为True. 指定是否将master配置选项作为pillar. 如果该选项为True, 修改了master配置选项时, 需要重启master, 才能在pillar中得到最新的值.

Minion中的Pillar实现

Minion中pillar为Python字典, Minion启动时, 默认会连接master获取最新的pillar数据, 存储在 self.opts['pillar'] 中. 对应代码 如下:

class Minion(MinionBase):
    '''
    This class instantiates a minion, runs connections for a minion,
    and loads all of the functions into the minion
    '''
    def __init__(self, opts, timeout=60, safe=True):
        '''
        Pass in the options dict
        '''
        ......
        self.opts['pillar'] = salt.pillar.get_pillar(
            opts,
            opts['grains'],
            opts['id'],
            opts['environment'],
        ).compile_pillar()
        ......

那么 salt.pillar.get_pillar 是如何工作的? 对应代码 如下:

def get_pillar(opts, grains, id_, saltenv=None, ext=None, env=None):
    '''
    Return the correct pillar driver based on the file_client option
    '''
    if env is not None:
        salt.utils.warn_until(
            'Boron',
            'Passing a salt environment should be done using \'saltenv\' '
            'not \'env\'. This functionality will be removed in Salt Boron.'
        )
        # Backwards compatibility
        saltenv = env

    return {
            'remote': RemotePillar,
            'local': Pillar
            }.get(opts['file_client'], Pillar)(opts, grains, id_, saltenv, ext)

也可以从代码中获知, 会从opts中获取 file_client 值, 如果是remote, 则对应的对象为RemotePillar, 如果是local, 则为Pillar, 进行后续处理

如果Minion在运行过程中, 接受到的指令以 refresh_pillar 字符串开头, 则执行 pillar_refresh 操作. 对应代码 如下:

if package.startswith('module_refresh'):
    self.module_refresh()
elif package.startswith('pillar_refresh'):
    self.pillar_refresh()

那么 pillar_refresh() 都进行了哪些工作? 对应代码 如下:

def pillar_refresh(self):
    '''
    Refresh the pillar
    '''
    self.opts['pillar'] = salt.pillar.get_pillar(
        self.opts,
        self.opts['grains'],
        self.opts['id'],
        self.opts['environment'],
    ).compile_pillar()
    self.module_refresh()

从代码中得知, pillar_refresh操作, 除了从Master端/Minion本地获取最新的pillar信息外, 也会执行模块刷新(module_refresh)工作. 可以将minion本地的日志级别调整为 trac, 然后执行 saltutil.refresh_pillar 操作, 然后观察minion日志, 是否会刷新模块进行验证.

Target中的Pillar

Salt指令发送底层网络, 采用ZeroMQ PUB/SUB结构. Minion会监听SUB接口, Master会将指令发送到本地的PUB接口, 然后所有Minion均会收到该指令, 然后在Minion本地判断自己是否需要执行该指令(即Target). 当前版本中, 已经支持pillar作为Target(通过"-I"选项指定). 对应代码 如下:

def pillar_match(self, tgt, delim=':'):
    '''
    Reads in the pillar glob match
    '''
    log.debug('pillar target: {0}'.format(tgt))
    if delim not in tgt:
        log.error('Got insufficient arguments for pillar match '
                  'statement from master')
        return False
    return salt.utils.subdict_match(self.opts['pillar'], tgt, delim=delim)

可以看出, 其匹配使用的是 self.opts['pillar'] 即当前Minion内存中的Pillar的数据. 因此如果在Master/Minion(当 file_client 为 local 时)修改了Pillar数据后, 想要使用最新的Pillar来做Target操作, 需要在执行前先手动执行saltutil.refresh_pillar 操作, 以刷新Minion内存中的Pillar数据.

远程执行模块中的Pillar

pillar.items

对应代码 如下:

pillar = salt.pillar.get_pillar(
    __opts__,
    __grains__,
    __opts__['id'],
    __opts__['environment'])

return pillar.compile_pillar()

会连接Master/Minion(当 file_client 为 local 时)获取最新的pillar数据并返回. 但并不会刷新Minion本地的缓存. 也就是说, 在master端修改了Pillar Tree, 在刷新pillar(saltutil.refresh_pillar)前, 可以先使用 pillar.items来验证其数据是否达到预期.

pillar.data

对应代码 如下:

data = items

只是创建了一个赋值引用, 指定data和执行items一样

pillar.item

对应代码 如下:

ret = {}
pillar = items()
for arg in args:
    try:
        ret[arg] = pillar[arg]
    except KeyError:
        pass
return ret

先使用pillar.items来获取最新的Master端最新的pillar数据. 然后一个for循环, 从items获取所需要的keys对应的值. 所以item可以查询多个key.

pillar.raw

对应代码 如下:

if key:
    ret = __pillar__.get(key, {})
else:
    ret = __pillar__

return ret

从当前Minion本地获取 __pillar__ (self.opts[pillar])的值. 也就是说使用pillar.raw 与 pillar.items 不同, 获取到的是Minion内存中的pillar的值, 并非是master端定义的值. 如果指定了key, 则返回对应key的值. 如果没有, 则返回整个 __pillar__

pillar.get

对应代码 如下:

return salt.utils.traverse_dict(__pillar__, key, default)

和 pillar.raw 工作方式类似, 是从 __pillar__ 中进行的取值, 用于获取pillar中对应的key值. 与 pillar.raw执行key不同的是, get递归获取内嵌字典的值(默认以":"做分隔). 从最新develop分支中看, 下一个版本(Helium)中将增加merge功能.

pillar.ext

与pillar.items工作方式类似, 用于获取ext pillar的值

saltutil.refresh_pillar

对应代码 如下:

__salt__['event.fire']({}, 'pillar_refresh')

在Minion本地Event接口上产生一个 pillar_refresh event. 之前在Minion中的Pillar中, Minion本地会监听本地Event接口, 如果捕捉到以 pillar_refresh 开始的指令, 会刷新本地pillar.

配置管理中的Pillar

在SLS中使用Pillar

在SLS中, 可以直接使用pillar. 如pillar['pkg'], 其直接使用的是Minion当前内存中pillar的值(self.opts['pillar']).

state.sls & state.highstate

将这两个远程执行模块方法放到配置管理中, 因为其功能是用于向Minions发送配置管理指令.

state.sls及state.highstate在代码中, 均为 salt.state.HighState 对象. 在执行时为 State 对象. State类在实例化时,则会刷新pillar, 对应代码 如下:

class State(object):
    '''
    Class used to execute salt states
    '''
    def __init__(self, opts, pillar=None, jid=None):
        if 'grains' not in opts:
            opts['grains'] = salt.loader.grains(opts)
        self.opts = opts
        self._pillar_override = pillar
        self.opts['pillar'] = self._gather_pillar()

而_gather_pillar 对应代码 如下:

def _gather_pillar(self):
    '''
    Whenever a state run starts, gather the pillar data fresh
    '''
    pillar = salt.pillar.get_pillar(
            self.opts,
            self.opts['grains'],
            self.opts['id'],
            self.opts['environment'],
            )
    ret = pillar.compile_pillar()
    if self._pillar_override and isinstance(self._pillar_override, dict):
        ret.update(self._pillar_override)
    return ret

_gather_pillar从Master上获取Minion对应的最新pillar数据, __init__方法中的 self.opts['pillar'] = self._gather_pillar() 将该数据赋值给self.opts['pillar']以完成Minion本地内存中Pillar数据的刷新操作. 这就是为什么修改了Master上的Pillar的值, 而无需执行刷新操作(saltutil.refresh_pillar), 因为在执行state.highstate及state.sls时会自动应该最新的值.

ext_pillar

Salt支持从第三方系统中获取Pillar信息,使Salt易于与现有的CMDB系统进行数据整合. 对应的配置是master配置文件中的ext_pillar选项. 官方当前已经提供了若干驱动 .

如果已经提供的驱动并不满足需求, 自定义ext_pillar驱动也非常简单. 只需要驱动文件放到master端salt代码中pillar目录下即可, 驱动为python代码, 其中包含ext_pillar函数, 且该函数第一个参数是minion_id, 第二个参数为pillar, 其返回值是一个标准的 Python字典 即可. 可以参照 cobbler的ext_pillar 进行编写.

 

 

http://www.saltstack.cn/projects/cssug-kb/wiki/Using_pillar_data_in_saltstack

在SaltStack中使用Pillar

Pillar做为一允许你分发定义的全局数据到目标minion上的接口,Pillar的数据只在匹配的minions上有效。 所以该特性使Pillar常常用于存储敏感类数据.

本文通过例子带你了解如何使用和存储Pillar数据.

/etc/salt/master - Pillar Roots

需要在master配置文件中定义_pillar_roots_,其用来指定Pillar data存储在哪个目录,默认是_/srv/pillar_.

pillar_root:
  base:
    - /srv/pillar

 

/srv/pillar/top.sls

和State系统一样,需要先定义一个_top.sls_文件作为入口,用来指定数据对哪个minion有效.

base:
  '*':
    - packages
  'alpha':
    - database

 

上边的例子定义了_packages_对所有的minion有效,_database_只对名字为'alpha'的minion有效.

/srv/pillar/packages.sls - Pillar Data

通过例子_packages_文件定义不同Linux发行版的软件包名字,通过Pillar进行中心控制它们,这样就可以在State文件中引用Pillar数据使State看起来更简单.

{% if grains['os'] == 'RedHat' %}
apache: httpd
{% elif grains['os'] == 'Debian' %}
apache: apache2
{% endif %}

 

/srv/states/apache.sls - State Data

如上,在State文件中将可以引用Pillar数据,是State更为简单. 线面是_apache.sls_ State文件例子:

apache:
  pkg:
    - installed
    - name: {{ pillar['apache'] }}

 

/srv/pillar/database.sls - Pillar Data

另一个定义Pillar Data的例子是定义服务连接数据库的权限的配置参数:

dbname: project
dbuser: username
dbpass: password
dbhost: localhost

 

website.conf - template

// MySQL settings
define('DB_NAME', '{{ pillar['dbname'] }}');
// MySQL database username
define('DB_USER', '{{ pillar['dbuser'] }}');
// MySQL database password
define('DB_PASSWORD', '{{ pillar['dbpass'] }}');
// MySQL hostname
define('DB_HOST', '{{ pillar['dbhost'] }}');

总结

有许多方法使用Pillar data. 作为另一种基础数据结构,Pillar是优美的. 可以用它定义所有minion上的自定义数据,也可以简单的定义包的名字,或者定义服务凭据(service credentials),Pillar都可以满足.

 

 

http://outofmemory.cn/saltstack/pillar-configuration

saltstack pillar设置

更多

1. 首先需要在master配置文件中修改pillar根目录

pillar_roots:
  base:
    - /home/salt/pillar

2. 然后就可以设置pillar数据了

在pillar目录中添加top.sls

base:
  app_pick:
    - match: nodegroup
    - app_pick_nginx
  app_pack:
    - match: nodegroup
    - app_pack_nginx

这里

  1. 第一行base表示根节点
  2. 第二行app_pick表示要设置pillar数据的分组
  3. 第三行的match表示是根据分组匹配
  4. 第四行的app_pick_nginx表示此分组的pillar设置文件为app_pick_nginx

3. 设置pillar数据,app_pick_nginx文件内容如下:

nginx:
  root: /export/app_pick

这里指定的pillar数据的根节点为nginx,下面是一个字典键为root,值为/export/app_pick

4. 可以通过命令salt ‘*’ pillar.data nginx来验证pillar的设置结果

5. 可以通过命令salt '*' saltutil.refresh_pillar来刷新minion的pillar数据

 

 

 

http://blog.cunss.com/?p=267

 

grains  这个跟puppet的facter功能一样。主要负责采集客户端一些基本信息, 这个也完全可以自定义,可以在客户端自定义,然后自动汇报上来;也可以从服务器端定义然后推下去,采集完后,再汇报上来;pillar  跟grains 比较的话 他的灵活性强点,怎么定义就这么定义,然后取值就行

 

salt ‘test82.salt.cn’ grains.items  打印所有items值

 

[root@test81 ~]# salt 'test82.salt.cn' grains.items
test82.salt.cn:
  cpu_flags: fpu de tsc msr pae cx8 sep cmov pat clflush mmx fxsr sse sse2 ss ht syscall nx lm rep_good aperfmperf unfair_spinlock pni pclmulqdq ssse3 cx16 sse4_1 sse4_2 popcnt aes hypervisor lahf_lm ida arat dts
  cpu_model: Intel(R) Xeon(R) CPU           E5620  @ 2.40GHz
  cpuarch: x86_64
  defaultencoding: UTF8
  defaultlanguage: en_US
  domain: salt.cn
  fqdn: test82.salt.cn
  fqdn_ip4:
      192.168.2.82
  fqdn_ip6:
  gpus:
  host: test82
  id: test82.salt.cn
  ip_interfaces: {'lo': ['127.0.0.1'], 'eth0': ['192.168.2.82']}
  ipv4:
      127.0.0.1
      192.168.2.82

........

此处省略100

 

 

 

 salt ‘test82.salt.cn’ grains.ls  列出所有项

 

 

[root@test81 ~]# salt 'test82.salt.cn' grains.ls
test82.salt.cn:

    - cpu_flags
    - cpu_model
    - cpuarch
    - defaultencoding
    - defaultlanguage
    - domain
    - fqdn
    - fqdn_ip4
    - fqdn_ip6
    - gpus
    - host
    - id
    - ip_interfaces
    - ipv4
    - ipv6

。。。。。。。

 

 

salt ‘test82.salt.cn’ grains.item ipv4  查看单条项的值

 

 

 

[root@test81 ~]# salt 'test82.salt.cn' grains.item ipv4
test82.salt.cn:
  ipv4:
      127.0.0.1
      192.168.2.82

 

 

 

#使用grains添加自定义items
 
第一种方法:
 
在minion端:
 
修改配置文件/etc/salt/minion  中 打开 default_include: minion.d/*.conf 
 
在/etc/salt/minion.d/目录中添加需要增加的items,文件类型与配置项*.conf对应

 

 

 

之后重启minion服务 /etc/init.d/salt-minion restart
 
在master端查看是否添加成功

 

 

 

 

如出现上图所示,则表示添加成功。

 

第二种方法:

 

 

在master端添加
在/srv/salt/ 创建_grains目录,编写grains文件,需要返回一个字典

 

[root@test81 ~]# cd /srv/salt/_grains/
[root@test81 _grains]# ls
nginx.py
[root@test81 _grains]# cat nginx.py 
def nginx():
    nginx={}
    nginx['nginx']='1.5.5'
    return nginx

 

 

 

同步到minion端
salt ‘test82.salt.cn’ state.highstate

 

 

[root@test81 _grains]# salt 'test82.salt.cn' grains.item nginx
test82.salt.cn:
  nginx: 1.5.5

 

 

添加成功

 

 

 

 

pillar
 

Pillar 是 Salt 非常重要的一个组件,它用于给特定的 minion 定义任何你需要的数据, 这些数据可以被 Salt 的其他组件使用。Salt 在 0.9.8 版本中引入了 Pillar。Pillar 在解析完成 后,是一个嵌套的 dict 结构;最上层的 key 是 minion ID,其 value 是该 minion 所拥有的 Pillar 数据;每一个 value 也都是 key/value。这里可以看出 Pillar 的一个特点,Pillar 数据是与特定 minion 关联的,也就是说每一个minion 都只能看到自己的数据, 所以 Pillar 可以用来传递敏感数据 (在 Salt 的设计中, Pillar 使用独立的加密 session,也是为了保证敏感数据的安全性) 。 Pillar 可以用在哪些地方? 

 

敏感数据
例如 ssh key,加密证书等,由于 Pillar 使用独立的加密 session,可以确保这些敏感数据不被其他 minion 看到。

 

变量

可以在 Pillar 中处理平台差异性,比如针对不同的操作系统设置软件包的名字,然后在State 中引用。 

 

其他任何数据

可以在 Pillar 中添加任何需要用到的数据。比如定义用户和 UID 的对应关系,mnion 的角色等。 

 

用在 Targetting 中

Pillar 可以用来选择 minion,使用-I 选项
 
 
默认情况下,master 配置文件中的所有数据都添加到 Pillar 中,且对所有 minion 可用。如果要禁用这一默认值,可以在 master 配置文件中添加如下数据,重启服务后生效,关于Pillar的配置见 /etc/salt/master
 
 
#pillar_roots:
# base:
# – /srv/pillar
 
#ext_pillar:
# – hiera: /etc/hiera.yaml
# – cmd_yaml: cat /etc/salt/yaml
 
# The pillar_opts option adds the master configuration file data to a dict in
# the pillar called “master”. This is used to set simple configurations in the
# master config file that can then be used on minions.
#pillar_opts: True

 

 

 

#创建/srv/pillar目录
[root@test81 pillar]# pwd
/srv/pillar


#创建top.sls入口文件
[root@test81 pillar]# tree
.
├── pp.sls
└── top.sls

0 directories, 2 files
[root@test81 pillar]# cat top.sls 
base:
  '*':
    - pp

#创建pp.sls

[root@test81 pillar]# cat pp.sls 
NAME: fqdn
ID: 567890
CONTENT:  This is a Test !

 

然后执行 salt ‘test82.salt.cn’ pillar.data  命令查看

 

 

[root@test81 pillar]#  salt 'test82.salt.cn' pillar.data
test82.salt.cn:
    ----------
    CONTENT:
        This is a Test !
    ID:
        567890
    NAME:
        fqdn
    master:
        ----------
        auth_mode:
            1
        auto_accept:
            True
        cachedir:

。。。。。。。

 

出现刚刚添加的字段,成功。

 

 

 

http://www.0550go.com/automation-deployment/saltstack/saltstack-grains-pillar.html

 

grains和pillar在之前的案例中基本上已经穿插的讲解了,下面我们来总一下:

一、输出所有grains.items键值

 

 

输出所有grains的key:

 

 

查看grains单个项目:

 

 

二、自定义grains
之前有说过grains可以自定义,而且有两种定义方式:

1、在minion配置文件里定义:

 

 

重启minion:

 

 

master端查看:

 

 

2、在master上编写grains文件:

 

 

同步:

 

 

让客户端重新加载模块

 

 

查看结果:

 

 

三、pillar这个组件,在前面的一些案里已经介绍过,总结来说:Pillar用于给特定的 minion 定义任何你需要的数据, 这些数据可以被Salt的其他组件使用!

 

 

测试:

 

 

测试的最后一条之所以把它列出来,是想说明Pillar用于给特定的 minion 定义任何你需要的数据,不是自己的,想要都木有

 

 

==============================================================================

http://blog.coocla.org/301.html

Salt系统的配置是令人惊讶的简单,对于salt的两个系统都有各自的配置文件,salt-master是通过一个名为master的文件配置,salt-minion是通过一个名为minion的文件配置。

salt-master的配置文件位于/etc/salt/master,可用选项如下:

#######################
主配置

interface
默认值:0.0.0.0(所有的网络地址接口)
绑定到本地的某个网络地址接口

publish_port
默认值:4505
设置master与minion的认证通信端口

user
默认值:root
运行salt进程的用户

max_open_files
默认值:100000
每一个minion连接到master,至少要使用一个文件描述符,如果足够多的minion连接到master上,你将会从控制台上看到salt-master crashes:
Too many open files (tcp_listener.cpp:335)
Aborted (core dumped)
默认值这个值取决于ulimit -Hn的值,即系统的对打开文件描述符的硬限制
如果你希望重新设置改值或者取消设置,记住这个值不能超过硬限制,提高硬限制取决于你的操作系统或分配,一个好的方法是internet找到对应操作系统的硬限制设置,比如这样搜索:
raise max open files hard limit debian

worker_threads
默认值:5
启动用来接收或应答minion的线程数。如果你有很多minion,而且minion延迟你的应答,你可以适度的提高该值.
在点对点的系统环境中使用时,该值不要被设置为3以下,但是可以将其设置为1

ret_port
默认值:4506
这个端口是master用来发送命令或者接收minions的命令执行返回信息

pidfile
默认值:/var/run/salt-master.pid
指定master的pid文件位置

root_dir
默认值:/
指定该目录为salt运行的根目录,改变它可以使salt从另外一个目录开始运行,好比chroot

pki_dir
默认值:/etc/salt/pki
这个目录是用来存放pki认证秘钥

cachedir
默认值:/var/cache/salt
这个目录是用来存放缓存信息,特别是salt工作执行的命令信息

keep_jobs
默认值:24
设置保持老的工作信息的过期时间,单位小时
job_cache
默认值:True
设置master维护的工作缓存,这是一个很好的功能,当你的Minons超过5000台时,他将很好的承担这个大的架构,关闭这个选项,之前的工作执行以及工作系统将无法被利用,一般不推荐关掉改选项,开启改选项将会是很明智的,他将使master获得更快的IO系统

ext_job_cache
默认值:”
对所有的minions使用指定的默认值returner,当使用了这个参数来指定一个returner并且配置正确,minions将会一直将返回的数据返回到returner,这也会默认值禁用master的本地缓存

minion_data_cache
默认值:True
minion data cache是关于minion信息存储在master上的参数,这些信息主要是pillar 和 grains数据.这些数据被缓存在cachedir定义的目录下的minion目录下以minion名为名的目录下并且预先确定哪些minions将从执行回复

enforce_mine_cache
默认值:False
默认情况下当关闭了minion_data_cache,mine将会停止工作,因为mine是基于缓存数据,通过启用这个选项,我们将会显示的开启对于mine系统的缓存功能

sock_dir
默认值:/tmp/salt-unix
指定unix socket主进程通信的socket创建路径

#######################
master的安全配置

open_mode
默认值:False
open_mode是一个危险的安全特性,当master遇到pki认证系统,秘钥混淆和身份验证失效时,打开open_mode,master将会接受所有的身份验证。这将会清理掉pki秘钥接受的minions。通常情况下open_mode不应该被打开,它只适用于短时间内清理pki keys,若要打开它,可将值调整为True

auto_accept
默认值:False
开启auto_accept。这个设置将会使master自动接受所有发送公钥的minions

autosign_file
默认值:/etc/salt/autosign.conf
如果autosign_file的值被指定,那么autosign_file将会通过该输入允许所有的匹配项,首先会搜索字符串进行匹配,然后通过正则表达式进行匹配。这是不安全的

client_acl
默认值:{}
开启对系统上非root的系统用户在master上执行特殊的模块,这些模块名可以使用正则表达式进行表示

client_acl_blacklist
默认值:{}
黑名单用户或模块
这个例子表示所有非sudo用户以及root都无法通过cmd这个模块执行命令,默认情况改配置是完全禁用的

external_auth
默认值:{}
salt的认证模块采用外部的认证系统用来做认证和验证用户在salt系统中的访问区域

token_expire
默认:43200
新令牌生成的时间间隔,单位秒,默认是12小时

file_recv
默认值:False
允许minions推送文件到master上,这个选项默认是禁用的,出于安全考虑

#######################
master模块管理

runner_dirs
默认值:[] 设置搜索runner模块的额外路径

cython_enable
默认值:False
设置为true来开启对cython模块的编译

#######################
master状态系统设置

state_verbose
默认:False
state_verbose允许从minions返回更多详细的信息,通常清空下只返回失败或者已经更改,但是将state_verbose设置为True,将会返回所有的状态检查

state_output
默认值:full
state_output的设置将会改变信息输出的格式,当被设置为”full”时,将全部的输出一行一行的显示输出;当被设置为”terse“时,将会被缩短为一行进行输出;当被设置为”mixed”时,输出样式将会是简洁的,除非状态失败,这种情况下将会全部输出;当被设置为”change”时,输出将会完全输出除非状态没有改变

state_top
默认值:top.sls
状态系统使用一个入口文件告诉minions在什么环境下使用什么模块,这个状态入口文件被定义在基础环境的相对根路径下

external_nodes
默认值:None
这个外部节点参数允许salt来收集一些数据,通常被放置在一个入口文件或外部节点控制器.外部节点的选择是可执行的,将会返回ENC数据,记住如果两者都启用的话salt会将外部节点和入口文件的结果进行综合汇总。

renderer
默认值:yaml_jinja
使用渲染器用来渲染minions的状态数据

failhard
默认值:False
设置一个全局的failhard表示,当单个的状态执行失败后,将会通知所有的状态停止运行状态

test
默认值:False
如果真的要作出改变或者仅仅通知将要执行什么改变时设置所有的状态调用为test

#######################
master文件服务器设置

fileserver_backend
默认值:

salt支持模块化的后端文件系统服务器,它允许salt通过第三方的系统来管理收集文件并提供给minions使用,可以配置多个后端文件系统,这里支持gitfs、hgfs、roots、s3fs文件调用的搜索顺序按照后台文件系统的配置顺序来搜索,默认的设置只开启了标准的后端服务器roots,具体的根选项配置通过file_roots参数设置

file_roots
默认值:

salt运行一个轻量级的文件服务器通过ZeroMQ对minions进行文件传输,因此这个文件服务器是构造在master的守护进程中,并且不需要依赖于专用的端口
文件服务器的工作环境传递给master,每一个环境可以有多个跟目录,但是相同环境下多个文件的子目录不能相同,否则下载的文件将不能被可靠的保证,一个基础环境依赖于主的入口文件,如:

hash_type
默认值:md5
hash_type是用来当发现在master上需要对一个文件进行hash时的hash使用的算法,默认是md5.但是它也支持sha1,sha224,shar256,shar384,shar512

file_buffer_size
默认值:1048576
文件服务器的缓存区大小

#######################
pillar配置

pillar_roots
默认值:

设置不同的环境对应的存放pillar数据的目录,这个配置和file_roots参数配置一样

ext_pillar
当进行pillar数据收集时,这个ext_pillar参数允许调用任意数量的外部pillar接口,这个配置是基于ext_pillar函数,你可以从这个找到这个函数https://github.com/saltstack/salt/blob/develop/salt/pillar
默认情况下,这个ext_pillar接口没有配置运行
默认值:None

从这里可以查到pillar的一些额外细节

#######################
syndic server配置

syncdic是salt master用来通过从整体架构中高于自己层级的master或者syndic接收命令传递给minions的中间角色。使用syndic非常简单,如果这个master在整体架构中,他的下级存在syndic server,那么需要将master的配置文件中的”order_master”值设置为True,如果这个master还需要运行一个syndic进程,扮演另外一个角色,那么需要设置主master server的信息(上一级master)
千万别忘记了,这将意味着它将与其他master共享它的minion的id和pki_dir

order_masters
默认值:False
当额外的数据需要发送和传递,并且这个master控制的minions是被低等级的master或syndic直接管理下,那么”order_masters”这个值必须得设置为True

syndic_master
默认值:None
如果这个master运行的salt-syndic连接到了一个更高层级的master,那么这个参数需要配置成连接到的这个高层级的master的地址

syndic_master_port
默认值:4506
如果这个master运行的salt-syndic连接到了一个更高层级的master,那么这个参数需要配置成连接到的这个高层级master的监听端口

syndic_log_file
默认值:syndic.log
为syndic进程指定日志文件

syndic_pidfile
默认值:salt-syndic.pid
为syndic进程指定pid文件

#######################
Peer Publish设置

salt minions可以向其他minions发送命令,但是仅仅在minion允许的情况下。默认情况下”Peer Publication”是关闭的,当需要开启的时候,需要开启对应的minion和对应的命令,这样可以允许根据个人的minions安全的划分出命令

peer
默认值:{}
这个配置使用正则表达式去匹配minions并且是一个正则表达式列表函数,下面这个例子将允许名为foo.example.com的minion认证通过后执行test和pkg模块中的函数

这将允许所有的minion执行所有的命令

这样的配置是极不推荐的,因为任何人得到架构中的任何一个minion即可拥有所有的minions,这是不安全的

peer_run
默认值:{}
peer_run参数是用来打开runners在master所允许的minions上,peer_run的配置匹配格式和peer参数的配置一样
下面这个例子允许foo.example.com的minion执行manage.up runner

NODE GROUPS
默认值:{}
minions允许通过node groups来分成多个逻辑组,每个组由一个组名和复合模式组成

#######################
Master日志设置

log_file
默认值:/var/log/salt/master
master的日志可以发送到一个普通文件,本地路径名或者网络位置,更多详情
例如:

log_level
默认值:warning
按照日志级别发送信息到控制台,更多详情

log_level_logfile
默认值:warning
按照日志级别发送信息到日志文件,更多详情

log_datefmt
默认值:%H:%M:%S
发送到控制台信息所用的日期时间格式,更多详情

log_datefmt_logfile
默认值: %Y-%m-%d %H:%M:%S
发送到日志文件信息所用的日期时间格式,更多详情

log_fmt_console
默认值: [%(levelname)-8s] %(message)s
控制台日志信息格式,更多详情

log_fmt_logfile
默认值: %(asctime)s,%(msecs)03.0f [%(name)-17s][%(levelname)-8s] %(message)s
%(asctime)s:2003-07-08 16:49:45
%(msecs)03.0f:当前时间的毫秒部分
%(name):日志记录调用器的名字
%(levelname):日志记录级别
%(message)s:日志详细信息
日志文件信息格式,更多详情

log_granular_levels
默认值:{}
这可以更加具体的控制日志记录级别,更多详情

#######################
Include 配置

default_include
默认值:master.d/*.conf
master可以从其他文件读取配置,默认情况下master将自动的将master.d/*.conf中的配置读取出来并应用,其中master.d目录是相对存在于主配置文件所在的目录

include
默认值:not defined
master可以包含其他文件中的配置,要启用此功能,通过此参数定义路径或文件,此路径可以是相对的也可以是绝对的,相对的,会被看作相对于主配置文件所在的目录,路径中还可以使用类似于shell风格的通配符,如果没有文件匹配的路径传递给此选项,那么master将会在日志中记录一条警告的消息





参考文档:http://docs.saltstack.com/ref/configuration/master.html

 

 

http://holbrook.github.io/2014/04/29/cm_tools_via_salt.html

Table of Contents

1 需求

T2,是某厂商开发的ESB产品,用于证券公司交易相关系统之间的互相调用。该产品的设计思路是一套核心的组件实现消息通信, 通过不同的插件实现ESB的协议转换、消息路由、访问控制等功能。每个节点基于xml配置不同的插件,即可扮演不同的角色。

恰恰由于这种灵活性,导致其配置非常复杂,人工进行配置修改和检查很容易出错。再加上每个架构角色可能会有多个节点,重复性的工作让人厌烦。

为此,我想通过salt进行自动化的配置。主要需求如下:

  • 只定义最基本的、非冗余的数据,从这些数据生成所有的配置
  • 支持多个版本的部署
  • 自动实现停止服务、部署、启动服务等一系列操作
  • 支持升级包的部署

2 机制

salt适合固定的配置(state)部署多个实例(minion)的场景。尽管可以在pillar、state中使用python脚本,但仍无法满足本场景中需要的复杂度。 所以拟构建python应用,通过salt client API与salt master进行交互。

为了降低对使用者的要求,需要实现一个web界面。拟采用bottle.py 。

3 设计

salt的“三驾马车”是 state 、 pillar 、 grains 。其中:

  • state是配置项(CI)的集合。配置项即可以是固定的内容,也可以是模板+数据,还可以是命令和脚本
  • pillar中定义数据并分配给minion。这些数据可以用于state中模板的上下文(context)数据
  • grains记录minion自身的属性。可以作为为minion分配pillar和state的依据,也可以用于模板的上下文

针对本文提到的场景,关系如下:

t2_salt.png

  • CI: 在svn中维护各个版本的所有配置项
  • datas: 在文件中维护部署需要的数据
  • pillars.top: 根据datas和各节点的grains数据,组合出每个minion的pillars
  • states.top: 根据各节点的grains和pillars数据,将CI分配到minion
  • pillars: 节点数据,其中可以引用grains
  • states: 节点状态,其中可以引用grains, pillars

3.1 pillarroots目录结构

pillar_roots 是 /etc/salt/master 中配置的参数,指定所有可用pillar的保存位置。 salt中可以按照环境划分不同的pillars,比如 base , dev , prod 等, 还可以指定多个pillar, 比如 ext_pillar 。

本文的场景中,不需要在salt中区分各种环境,故只使用 base 目录。其默认值为 /srv/pillar 。设计的目录结构如下:

/srv/pillar
 ├─ dev.yaml
 ├─ uat.yaml
 ├─ prod.yaml
 ├─ xxx.yaml
 └─ top.sls

其中,yaml是部署配置,通过工具编辑; top.sls是pillar分配,通过脚本生成。

3.2 fileroot目录结构

file_root 是 /etc/salt/master 中配置的参数,指定所有可用state的保存位置。 salt中可以按照环境划分不同的states,比如 base , dev , prod 等。

本文的场景中,不需要在salt中区分各种环境,故只使用 base 目录。其默认值为 /srv/salt 。设计的目录结构如下:

/srv/salt
 ├─ v0.1/
 │ ├─ config items/     配置项,可能是多个目录
 │ └─ states/           salt state定义。会引用上面的 config item。
 ├─ v1.0/
 ├─ v1.0.1/
 ├─ vx.x.x/
 └─ top.sls             状态分配,通过脚本生成

3.3 流程

  1. 从svn中获取需要的各个版本,放入 /srv/salt/
  2. 编辑 /srv/pillar 中的各个部署配置
  3. 生成 /srv/pillar/top.sls 和 /srv/salt/top.sls
  4. 调用salt client API进行部署

4 实现要点(TODO)

 

 

http://devopstarter.info/saltstack-ying-yong-ji-qiao-zhi-pillarde-ling-huo-guan-li/

 

Saltstack使用Pillar和Grains数据来管理和分类Minion,其中Grains数据作为Minion的“固有属性”存储在Minion端,而Pillar则作为“变量数据”存储在Salt-Master端,本文就如何灵活的应用和管理Pillar来实现分类与配置部署的话题予以探讨。

常见的Pillar配置

一般来说,常见的配置Pillar样例如下所示:

 .
├── top.sls
├── appcase
│   ├── conf.sls
│   └── init.sls
├── basiccase
│   └── init.sls
├── schedule.sls
└── users.sls

通过定义top.sls来统一的进行管理,而从分层的sls结构很好的定义一些应用或者OS基础层的相关Pillar参数。

然而,由于Saltstack本身提供的Pillar暂时还不够强大,比如像灵活控制Top.sls或者使用Extends这样的特性在原生的支持上便很难达成,网上因此也出现了很多介绍如何结合Cobbler或者Reclass来辅助增强Pillar的文章(都是非常优秀的技术博客文章,鄙人均一一拜读,感谢大神们的分享)。

鄙人这里不打算介绍如何结合第三方的应用来扩展Pillar,而考虑使用Saltstack本身的良好扩展性来达成效果,具体细节且待我一一说来。

使用Python扩展的Pillar

其实真的应该说是一叶障目,为什么不能简单的直接使用Python去定制Pillar呢?通过查看Saltstack源代码(这便是开源的魅力所在!),我发现其使用类似 yaml_load() 这样的方法来解析Pillar sls(应该state sls也是一样,这里没测试过~)。因此,可以通过将top.sls转换成如下格式来实现灵活的管理:

#!py
#base:
#  '*':
#    - schedule
def pillar_helper():
    return {'base': {'*': ['schedule'], 'TestVM': ['users']}}

def run():
    return pillar_helper()

这样一来,通过pydsl的方式去管理,无论是自定义额外模块还是编写额外方法去判断处理都是可行的了。为了更好的去理解,简单介绍一个应用的实例吧,结构如下所示(注意与常见配置的一些差异~):

 .
├── appcase
│   ├── conf.sls
│   └── init.sls
├── basiccase
│   └── init.sls
├── nodes
│   └── TestVM.sls
├── schedule.sls
├── top.sls
├── top.slsc
└── users.sls

其中,top.sls实际算是pydsl格式文件,内容为:

#!py
#base:
#  '*':
#    - schedule
def pillar_helper():
    return {'base': {'*': ['schedule'], 'TestVM': ['users', 'nodes.TestVM']}}

def run():
    return pillar_helper()

而这样一来,便可以通过Python脚本的扩展方式灵活的管理每台具体主机或者组的Pillar参数,如上的TestVM.sls即定义了TestVM自身的Pillar值:

[root@monitor pillar]# cat /srv/pillar/nodes/TestVM.sls 
role: blog_app

而使用 salt '*' saltutil.refresh_pillar 刷新 pillar 数据后可以确认下,的确是预想的那样:

[root@monitor ~]# salt 'TestVM' pillar.item role
TestVM:
    ----------
    role:
        blog_app

实际还可以根据需求将此扩展到适合的结构,毕竟可以使用Python嘛,扩展性无与伦比。

 

 

http://lixcto.blog.51cto.com/4834175/1429575

 

讲完了grains,pillar是个啥呢?

pillar这东西,楼主刚看的时候,啥也没看懂,于是字典了一下。

靠,意思是柱子,楼主更加云里雾里了,老外这名字咋整成这样?

老外不靠谱,老祖宗有云:"书读百遍,其义自见"。于是楼主也就多看了那么几遍,差不多知道这货是

干什么的了?

pillar这东西其实也是data,对,数据。

pilar是存放在啥地方的呢?存放在master上面的,一个地方是在/etc/salt/master这个配置文件里面。

还有一个地方,默认在/etc/pillar这个文件夹里面。

pillar可以用在什么地方呢?可以用在模块里面,jinja模板里面,state的sls文件里面。一般来说用

yaml写的东西都可以用它

pillar说到底还是minion用的,官网上说pillar是用存敏感数据的,对没错。啥叫敏感数据呢,就是说

你这个minion要是满足我的要求,你才能用我相应的pillar数据,如果不满足我的要求,你就不能用了。

官网上有个简单的小例子,咱们来看看。

{% if grains['os'] == 'RedHat' %}
apache: httpd
git: git
{% elif grains['os'] == 'Debian' %}
apache: apache2
git: git-core
{% endif %}

这个例子说明,你如果系统是RedHat,那么我的apache的名字就叫httpd。系统是Debian的时候,我的apache的名字就叫apache2。

 

下面我们仔细看看pillar这东西。

先看一下/etc/salt/master里面定义的pillar

1
2
3
4
5
6
7
8
9
10
root@salt-master:~# salt '*' pillar.get master:max_open_files 
salt-minion:
    100000
root@salt-master:~# salt '*' pillar.get  master:publish_port
salt-minion:
    4505
root@salt-master:~# for item in {'max_open_files','publish_port'};\
do grep $item /etc/salt/master;done
#max_open_files: 100000
#publish_port: 4505

然后是自定义的pillar

自定义的pillar和state的结构差不多,区别是pillar里面存的都是数据,state里面存的都是干活的

东西

1
2
3
4
5
6
7
8
9
10
root@salt-master:~# tree /srv/pillar/
/srv/pillar/
├── args
│   └── init.sls
├── pkg
│   └── init.sls
├── test.sls
├── top.sls
└── users
    └── init.sls

看一下,test.sls吧

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
root@salt-master:~# cat /srv/pillar/test.sls 
apache: apache2
root@salt-master:~# 
看一下top.sls,和state里面的规则全都一样
root@salt-master:~# cat /srv/pillar/top.sls 
base:
  '*':
    - test
这里需要刷新一下pillar,不然看不到的
root@salt-master:~# salt '*' saltutil.refresh_pillar
salt-minion:
    None
好,查看一下,pillar里面是否有apache
root@salt-master:~# salt '*' pillar.item apache
salt-minion:
    ----------
    apache:
        apache2
root@salt-master:~# 
有了,OK

注意:当然salt '*' state.highstate也是可以刷新pillar的,这个东西啥都可以更新,grains也可以,前一篇咱们看到了。

 

楼主整个小例子吧

楼主的例子可能有点蛋疼,没办法啊,楼主在自己做测试,没啥实际的需求去做,楼主也头脑风暴不出来个牛逼的,不过基本功能能跑通就OK了!先来看看楼主的grains是怎么定义的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
root@salt-master:~# cat  /srv/salt/_grains/check_tmp.py    
#!/usr/bin/env python
from subprocess import Popen,PIPE
import os
def check_tmp():
    grains = {}
    if os.path.exists('/tmp/lixc'):
        result = Popen("du /tmp/lixc -sm",shell=True,stdout=PIPE) 
        result = result.stdout.readlines()
        size = result[0].split('\t')[0]
        if int(size) >= 100: 
            grains['tmp'] = { 'name':result[0].split('/')[2][0:-1], 'remove':True}
        else:
            grains['tmp'] = { 'name':result[0].split('/')[2][0:-1], 'remove':False}
    else:
        grains['tmp'] = {'name':'lixc','remove':False}
    return grains
root@salt-master:~#

楼主这个grains是干啥用的呢?就是看一下/tmp/lixc这个文件夹的大小。咱们来看看结果

1
2
3
4
5
6
7
root@salt-master:/srv/salt# salt '*'   saltutil.sync_grains
salt-minion:
    - grains.check_tmp
root@salt-master:/srv/salt# salt '*'   grains.item tmp
salt-minion:
  tmp: {'name''lixc''remove''True'}
root@salt-master:/srv/salt#

再看看楼主的pillar是怎么定义的。这里在pillar用到了grains

1
2
3
4
5
6
7
8
9
root@salt-master:~# cat /srv/pillar/check_tmp/init.sls     
filename: 
  - {{grains['tmp']['name']}}
 
group: lixc
groupmember:
  user1: lixc
  user2: liss
root@salt-master:~#

再看看楼主的state是咋弄的?楼主在state里面用到了grains和pillar

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
root@salt-master:~# cat /srv/salt/check_tmp/init.sls 
{% set directory = '/tmp' %}
{% set size=salt['grains.get']('tmp:remove''') %}
{% if  size %}
/tmp/lixc:
  file.absent:
    - name: {{directory}}/{{pillar['filename'][0]}}
/home/lixc/test.log:
  file.managed:
    - source: salt://check_tmp/files/test.jinja
    template: jinja
    - user: {{salt['pillar.get']('groupmember:user1','lixc')}}
    - group: {{pillar['group']}}
{% else%}
/home/lixc/exec.log:
  cmd.run:
    - unless: echo 'lisisi' > /home/lixc/exec.log
{%endif%}
   
     
root@salt-master:~#

再看看楼主的state里面的test.jinja是咋弄的?楼主在jinja模板里面,用到了grains和pillar

1
2
3
4
5
root@salt-master:~# cat /srv/salt/check_tmp/files/test.jinja 
hostname:{{grains['fqdn']}}
group:{{pillar['group']}}
groupmeber: {{pillar['groupmember']['user1']}},{{ salt['pillar.get']('groupmember:user2''') }}
root@salt-master:~#

楼主弄了这一大串想实现啥功能的呢?如果/tmp/lixc这个文件夹的大小超过100M,就把这个文件夹干掉,然后把test.jinja模板文件,发送到/home/lixc/test.log,否则在/home/lixc/exec.log这个文件里面增加一行"lisis"。。。唉,楼主的这个例子是有点毫无逻辑可言,和实际运维也完全不搭嘎,但是想说明的东西,差不多都说了。

好,来看看执行结果吧!

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
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
第一,先看看minion上面的/tmp/lixc这个文件夹的大小,是304M
root@salt-master:~# salt '*' cmd.run 'du /tmp/lixc -sm'
salt-minion:
    304 /tmp/lixc
     
第二,同步一些grains
root@salt-master:~# salt '*' saltutil.sync_grains
salt-minion:
    - grains.check_tmp
     
第三,同步之后,看一下我们定义的grains返回来的值
root@salt-master:~# salt '*' grains.item tmp
salt-minion:
  tmp: {'name''lixc''remove': True}
 
第四,刷新一下pillar
root@salt-master:~# salt '*' saltutil.refresh_pillar
salt-minion:
    None
    
第五,看一下,刷新之后,有没有咱们定义的pillar
root@salt-master:~# salt '*' pillar.item filename group groupmember
salt-minion:
    ----------
    filename:
        - lixc
    group:
        lixc
    groupmember:
        ----------
        user1:
            lixc
        user2:
            liss
             
第六,好,执行下咱们定义的check_tmp这个state
root@salt-master:~# salt '*' state.sls check_tmp
salt-minion:
----------
          ID: /tmp/lixc
    Function: file.absent
      Result: True
     Comment: Removed directory /tmp/lixc
     Changes:   
              ----------
              removed:
                  /tmp/lixc
----------
          ID: /home/lixc/test.log
    Function: file.managed
      Result: True
     Comment: File /home/lixc/test.log updated
     Changes:   
              ----------
              diff:
                  New file
              group:
                  lixc
              mode:
                  0644
              user:
                  lixc
 
Summary
------------
Succeeded: 2
Failed:    0
------------
Total:     2
 
第七,看一下/tmp/lixc这个文件夹还在不在?不在了,看到没
root@salt-master:~# salt '*' cmd.exec_code  bash 'if [ -f "/tmp/lixc" ];\
> then echo yes;else echo no;fi'
salt-minion:
    no
     
第八,看看/home/lixc/test.log这个文件生成的内容
root@salt-master:~# salt '*' cmd.run 'cat /home/lixc/test.log'
salt-minion:
    hostname:salt-minion
    group:lixc
    groupmeber: lixc,liss
     
第九,再同步一下grains
root@salt-master:~# salt '*' saltutil.sync_grains
salt-minion:
 
第十,再查看一下咱们自定义的grains返回的值,因为/tmp/lixc这个文件夹不存在了,所以是False了
root@salt-master:~# salt '*' grains.item tmp
salt-minion:
  tmp: {'name''lixc''remove': False}
   
第十一,再执行一下我们定义的state,check_tmp
root@salt-master:~# salt '*' state.sls check_tmp
salt-minion:
----------
          ID: /home/lixc/exec.log
    Function: cmd.run
      Result: True
     Comment: unless execution succeeded
     Changes:   
 
Summary
------------
Succeeded: 1
Failed:    0
------------
Total:     1
 
第十二,查看一下/home/lixc/exec.log的内容
root@salt-master:~# salt '*' cmd.run 'tail -n 1 /home/lixc/exec.log'
salt-minion:
    lisisi

以上是pillar的一些用法,当然pillar还可以用在module里面,这个下节写module的时候再写。

OK,

 

本文出自 “小城运维” 博客,请务必保留此出处http://lixcto.blog.51cto.com/4834175/1429575

 

 

 

 

 

 

 

 

 

 

 

==============================================================================

 

http://docs.saltstack.cn/zh_CN/latest/topics/tutorials/states_pt3.html

这章教程我们将讨论更多 ``sls``文件的扩展模板和配置技巧。

3.3.4.1. 模板SLS的模块

SLS模板块可能需要编程的逻辑或则嵌套的执行。这是通过模块的模板,默认的模块模板系统使用的是`Jinja2`, 我们可以通过更改主配置的:conf_master:`renderer`值来改变这个。

当初始化时所有的状态类型都是通过模板系统获得。使用模板系统只需要简单的添加一些模板标记。SLS模板与模板标记的一个例子,看起来像下面这样。

{% for usr in ['moe','larry','curly'] %}
{{ usr }}:
  user.present
{% endfor %}

这个SLS模板文件一次性构造了如下的内容:

moe:
  user.present
larry:
  user.present
curly:
  user.present

这里有个更复杂点的例子:

{% for usr in 'moe','larry','curly' %}
{{ usr }}:
  group:
    - present
  user:
    - present
    - gid_from_name: True
    - require:
      - group: {{ usr }}
{% endfor %}

3.3.4.2. 使用GRAINS模板

很多时候一个state 在不同的系统上行为要不一样, Salt grains 在模板文本中将可以被应用,`grains`可以被使用在模板内。

apache:
  pkg.installed:
    {% if grains['os'] == 'RedHat' %}
    - name: httpd
    {% elif grains['os'] == 'Ubuntu' %}
    - name: apache2
    {% endif %}

3.3.4.3. 在模板中调用模块

所有的minion从模板系统中调用可用的模块。他们允许实时在目标机器上搜集数据。同时也允许运行简单shell命令在SLS模块中。

``salt:``一个可用的模块函数在salt模板中,就像下面这样。

moe:
  user:
    - present
    - gid: {{ salt['file.group_to_gid']('some_group_that_exists') }}

提示:在上面的例子运行中,some_group_that_exists 必须在状态文件模板引擎处理之前必须存在。

在下面的例子中使用``network.hw_addr``函数取回eth0的MAC地址。

salt['network.hw_addr']('eth0')

3.3.4.4. 更高级的SLS模块语法

在最后,我们将讨论一些不可思议的好技巧在更复杂的state 树中。

3.3.4.4.1. Include declaration

A previous example showed how to spread a Salt tree across several files. Similarly, requisites span multiple files by using an Include declaration. For example:

python/python-libs.sls:

python-dateutil:
  pkg.installed

python/django.sls:

include:
  - python.python-libs

django:
  pkg.installed:
    - require:
      - pkg: python-dateutil

3.3.4.4.2. Extend declaration

You can modify previous declarations by using an Extend declaration. For example the following modifies the Apache tree to also restart Apache when the vhosts file is changed:

apache/apache.sls:

apache:
  pkg.installed

apache/mywebsite.sls:

include:
  - apache.apache

extend:
  apache:
    service:
      - running
      - watch:
        - file: /etc/httpd/extra/httpd-vhosts.conf

/etc/httpd/extra/httpd-vhosts.conf:
  file.managed:
    - source: salt://apache/httpd-vhosts.conf

对比扩展和`required`or watch

扩展申明申明是有别于``require``or watch,它是附加,而不是更改必要的组件。

3.3.4.4.3. Name declaration

You can override the ID declaration by using a Name declaration. For example, the previous example is a bit more maintainable if rewritten as follows:

apache/mywebsite.sls:

include:
  - apache.apache

extend:
  apache:
    service:
      - running
      - watch:
        - file: mywebsite

mywebsite:
  file.managed:
    - name: /etc/httpd/extra/httpd-vhosts.conf
    - source: salt://apache/httpd-vhosts.conf

3.3.4.4.4. Names declaration

Even more powerful is using a Names declaration to override the ID declaration for multiple states at once. This often can remove the need for looping in a template. For example, the first example in this tutorial can be rewritten without the loop:

stooges:
  user.present:
    - names:
      - moe
      - larry
      - curly

3.3.4.5. 下一章

在 第四部分中 我们将讨论如何使用**Salt**的 file_roots 来建立一个工作流程状态提升从开发,测试,生产

 

 

http://www.shencan.net/index.php/2013/05/24/saltstack-%E4%BA%8C-grains%E5%92%8Cpillar/

昨天讲解了一下saltstack的一些基本应用(安装 部署  简单的应用 跟简单的资源管理)   saltstack这东西 很强大 东西也很多今天我就简单讲解下

grains和pillar    这个单词这么读 我也不太清楚  这里简单介绍下吧

grains  这个跟puppet的facter一样 负责采集客户端一些基本信息(查看这些信息 上一篇文章已经介绍了) 这个也完全可以自定义(灵活性牛掰)

可以在客户端自定义 然后自动汇报上来 也可以从服务器端定义然后推下去 采集完后 再汇报上来

pillar  这个东西 我真没看懂是啥  如果跟grains  比较的话 他的灵活性强点  想这么定义就这么定义  然后取值就行

下面先开始讲解 grains 这个吧

salt ‘CMN-NJ-H-3g2′ grains.items 这个默认会打印 一个对象的所有grain值 (grains.ls显示所有项目)

这些值是客户端自动汇报上来的 软件安装后默认会有很多

源码地址是 https://github.com/saltstack/salt/blob/develop/salt/grains/core.py  懂python的可以看看

可能有些人想自定义grains  就是想客户端汇报你想要的数据到服务器   这个可以通过2个方法实现 第一个是在服务器端 往客户端推(可以过滤指定客户端) 第二个就是直接在客户端配置文件里面编辑

我这里因为客户端就一台 我就直接到客户端去编辑文件了

因为我怕改错主配置文件 所以我采用包含其他配置文件来改的

客户端主配置文件默认支持包含 我就到/etc/salt/minion.d/下新建一个.conf 结尾的文件

这个文件的意思很简单  都是 KEY: VALUE 这样的格式  #看图的解释就知道了

好改完了 重启了 客户端服务器 然后我们去服务器端查看下 看汇报上来没

OK 没问题都汇报上来了 ##其他可以用这个做数据收集系统 客户端搞个脚本去定期改某个文件 服务器就能收集信息了

好 grains 这块就先讲到这里  这里先不讲这么调用这些采集上来的数据 等讲完pillar 之后 然后统一讲下 在sls模板或者jinja模板中调用这些值

开始讲pillar 吧   pillar 是我在服务器上定义的  默认安装没有这个文件夹 自己新建一个就行

mkdir /srv/pillar/ && touch  /srv/pillar/top.sls

然后看下sc.sls 文件吧

OK 配置完后 我们查看下吧 有没有生效

在服务器端运行 salt ‘CMN-NJ-H-3g2′ pillar.data

还有一个在最下面 擦

OK 数据生效了    现在grains和pillar 的自定义 都讲完了 数据也出来了  下面我们就看看怎么用这些数据吧

关于grains 的使用 官网一般用到sls模板里面 其实 jinja模板也可以直接用 下面我搞个jinja文件例子吧

再看看squid.conf.jinja模板文件吧

这个是关键 大家一定得记住调用语法

好 下面我们来推下 看看客户端的效果吧

OK  框住的都是动态生成的值 你懂的

关于grains和pillar的调用       官网有很多文档 建议没事的去看看把        jinja模板还支持 简单的判断 我贴下官网的例子吧

{% if grains['os'] == 'Ubuntu' %}
host: {{ grains['host'] }}
{% elif grains['os'] == 'CentOS' %}
host: {{ grains['fqdn'] }}
{% endif %}

通过简单的判断 来产生相应的值  OK 先写这么多 下次继续补上吧

 

 

 

==============================================================================

 

 

 

##################################################################################

 

 

 

 

==============================================================================

 

 

 

##################################################################################

 

 

 

 

 

==============================================================================

 http://www.shencan.net/index.php/2013/06/08/saltstatck%E4%B8%89-module%E5%92%8Cgrains/

前面2篇文章基本上把saltstack的基本应用都讲了下(基本应用而已) 今天讲下自定义module(就是自己写模块)和 自定义grains(上一篇已经讲了 但是是简单的K/V值对形式定义 今天会写通过python脚本来定义 这样一来扩展性强了很多)

现在开始讲自定义模块吧

模块这个大家应该知道是什么了吧  saltstack默认安装完了 就自带很多模块

可以通过下面的命令查看某台minion支持多少模块

salt ‘CMN-NJ-H-3g4′ sys.doc

给个源码包 里面所有模块的源文件吧(自定义模块 也是按照这个来画瓢的)

https://github.com/saltstack/salt/tree/develop/salt/modules

开始弄吧

先新建一个_module目录(我的file_root 路径没有改)

mkdir  /srv/salt/_modules  && cd /srv/salt/_modules

然后再目录下 写个python脚本 (我python 还没入门 我是按照源码里面盗版了一个) 很简单 的一个

就一个函数  return 一个值(如果你python牛掰 这个你可以随便怎么扩展  格式对就行(每个函数 return值就行) )

OK 这样一个最简单 最简单的module 就写完了(因为我python还没入门)

写完模块后  再同步到minion上(可以同步到你指定的minion 或者所有minion上 这个随你 在top.sls 入口文件控制)

同步命令为

salt ‘*’ saltutil.sync_all  我上个图吧

OK  这样就同步完了  我们测试下吧

fc7.shencan 这个简单介绍下

fc7 是_module 目录下的fc7.py 模块

shencan  是fc7.py 模块下的一个函数(调用函数 你懂的)

OK  自定义模块就这些 (我只是简单讲了一下方法  如果你python牛掰 自己可以按照这个思路扩散 )

 

接下来讲grains 吧  前一篇文章 我是在minion 配置文件中手动定义的 grains K/V 值对  这样定义是没问题的  你可以在matser端 把所以minion的这个文件管理起来 以后也好扩展  只是方便性 不咋地  下面就讲解通过python脚本来自定义(官方也是这样来的)

下面给个官网的例子吧

https://github.com/saltstack/salt/tree/develop/salt/grains

自定义grains 也是按照这个画瓢的  你懂的

mkir /srv/salt/_grains && cd /srv/salt/_grains

在目录下新建一个py脚本

我py 脚本真的没入门  这个还是别人教我写的   最主要的记得格式  就OK了 (好像是python的列表)

OK 写完后  同步吧

salt ‘*’ saltutil.sync_all

图就不贴了 跟上面差不多

最后测试下吧

OK  了   就这样  其实方法是简单  扩展那就没法讲了  只能用例子来讲了  如果你py能力牛掰  你随便看下官网的grains 源码

那就不得了了  想这么写就怎么写(看你想要啥信息了)

OK  module 跟grains先写这么多吧    等我py脚本 学好了点  我拿几个例子再讲下吧

下面的saltstack 文章 我可能还会写  renderers  returners states  pillar 专题来写

 

 

http://www.shencan.net/index.php/2013/08/29/saltstack%E5%8D%81%E4%B8%80-%E5%88%A9%E7%94%A8salt-api%E7%BC%96%E5%86%99%E5%91%BD%E4%BB%A4%E6%89%A7%E8%A1%8C%E6%A8%A1%E5%9D%97%EF%BC%88%E5%B8%A6%E6%97%A5%E5%BF%97%E8%AE%B0%E5%BD%95%EF%BC%89/

好久没写博客了,最近没事也很少看salt了 今天没事看了下 salt的模块 因为我很少用到salt自带的模块(cmd.run除外) 今天没事 过了几个模块 发现很多模块 都引用了  salt.utils  logging这2个模块  第一个模块是salt自带的 第2个模块 就不讲了 大家都知道 就是记录日志的 ,

下面说下我的需求吧 我们因为做了 saltstack UI 以后执行命令都在web界面上 ,我们想做一个 记录查询系统(就是什么用户 什么时候 执行了什么命令 返回的结果是什么)。其实这个 功能 我们完全可以在后台执行命令的时候 加一个return 把东西都丢到数据库里面去(其实这个已经实现了)。今天想 利用logging模块 跟salt.utils重新写个 。哎。。。。其实我python MD 太菜了很多源码都看不懂  很多东西都不会 操蛋呀。。

我这里自定义 了一个模块

直接贴代码吧  cpis.py

这个模块是干啥的呢 我简单介绍了下

salt.utils 这个模块很关键 其实他就是  __salt__ 这个东西 我这里用了他的cmd.run

logging  这个是python 的日志记录的东东

我这个脚本的功能是 实现salt 的cmd.run 的功能   就是执行命令的  但是我这里 我加了一个把执行的过程 都记录到一个日志文件了(以后要对这个日志文件进行分析)

看演示吧   大家就明白了   记得同步哟

这个 跟cmd.run 没区别  你懂的

你再看看那个日志文件

知道了吧 多了一个日志记录 功能

哎。。 其实也没啥  先写这么多吧   python 不好 真的md 是硬伤呀   很多东西 看不懂。。 没事还是去补补python吧

先写这么多吧 下面补点吧  这个内容是不是有点少了

posted @ 2014-12-12 16:16  陳聽溪  阅读(1443)  评论(0)    收藏  举报