最近在学习saltstack,对照着官方的文档学习的,官方文档顺序也有些问题,所以看得时候可能觉得顺序安排有些不妥,那就继续往前看,然后看第二遍就会好很多了。


一。target  就是指定你的命令或者模块应用哪写Minion上

1.globbing  默认

salt 'test*' test.ping

2.RE 正则

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

3.List 列表

salt -L '127.0.0.1, test*' test.ping

4.grains

salt -G 'os:CentOS' test.ping

查看所有grains键/值

salt 'test*' grains.items

查看所有grains项

salt 'test*' grains.ls

查看某个grains的值

salt 'test*' grains.item num_cpus


在top file中匹配grains

’node_type:web’:

  - match: grain         ##没有s

  - webserver

 top file中使用jinja模板

 {% set self = grains['node_type'] %}

   - match: grain

- ` self `

5.nodegroups 其实就是对Minion分组

首先在master的配置文件中对其分组,我们推荐写到/etc/salt/master.d/中一个独立的配置文件中,比如nodegroup.conf

vim /etc/salt/master.d/nodegroup.conf   ##写到master中也是这个格式,master.d中*.conf是默认动态加载的

nodegroups:

 test1: 'L@test1,test2 or test3*'

 test2: ‘G@os:CenOS or test2'


salt -N test1 test.ping                ##-N指定groupname


在top file中使用nodegroups


'test1':

 - match: nodegroup                   ##注意没s

 - webserver


6.混合指定,就是将以上的混合起来用

 G Grains glob G@os:Ubuntu

 E PCRE Minion ID E@web\d+\.(dev|qa|prod)\.loc

 P Grains PCRE P@os:(RedHat|Fedora|CentOS)

 L List of minions [email protected],minion3.domain.com or bl*.domain.com

 I Pillar glob I@pdata:foobar

 S Subnet/IP address [email protected]/24 or [email protected]

 R Range cluster R@%foo.bar


 salt -C 'G@os:CentOS and [email protected],192.168.1.12' test.ping


 top file 指定:

 'webserver* and G:CentOS or [email protected],test1':

   - match: compound

- webserver


7.一次在n个minion上执行

  -b n

  --batch-size n

  示例:

  salt '*' -b 5 test.ping 5个5个的ping


二。使用gitfs做fileserver,用gitfs后,master会从git服务器取回文件缓存,minion不会直接联系git服务器

修改master配置文件/etc/salt/master(注:以后说master配置文件就是指该文件)


fileserver_backend:

 - git

gitfs_remotes:

 - git://github.com/saltstack/saltstack.git

 - git://github.com/example/test1.git      ##可以多个git

 - file:///root/td                         ##可以使用本地git


需要:python的模块GitPython >= 0.3.0


saltstack的目录结构

.

|-- bfile

|-- edit

|   `-- vim.sls

`-- top.sls


vim.sls

/tmp/a.txt:

 file.managed:

   - source: salt://bfile

ftp:

 pkg:

   - installed

也可以使用git下的子目录作为文件服务器根目录

gitfs_root: somefolder/otherfolder


也可以混合使用git和本地磁盘作为文件服务器

fileserver_backend:

 - roots

 - git

使用ssh协议的GitFS,私钥为~/.ssh/id_rsa

gitfs_remotes:

 - git+ssh://[email protected]/example/salt-states.git


三。远程批量执行

格式:

 salt '' [argument]

注;

 function是salt带的或自己写的可执行模块里面的function,自带的所有列表http://docs.saltstack.com/ref/modules/all/index.html?highlight=full%20list%20builtin

实例:

 salt '*' at.at 10.10am 'uptime'

 salt '*' test.ping


四。多Master实例

1.在另一台机器上安装salt-master

 yum -y install salt-master

2.将原来master上的master密钥拷贝到新的master是一份

 scp /etc/salt/pki/master/master* newmaster:/etc/salt/pki/master/

3.启动新的Master

 service salt-master start

4.修改minion配置文件/etc/salt/minion设置两个master

 master:

   - master1

- master2

5.重启minion

 service salt-minion restart

6.在新的master上接受所有key

 salt-key -L

 salt-key -A


注意:

 1.2个master并不会共享Minion keys,一个master删除了一个key不会影响另一个

 2.不会自动同步File_roots,所以需要手动去维护,如果用git就没问题了

 3.不会自动同步Pillar_Roots,所以需要手工去维护,也可以用git

 4.Master的配置文件也是独立的



五。pillar的初体验

简介:

 Pillar在salt中是非常重要的组成部分,利用它可以完成很强大的功能,它可以指定一些信息到指定的minion上,不像grains一样是分发到所有Minion上的,它保存的数据可以是动态的,Pillar以sls来写的,格式是键值对

适用情景:

 1.比较敏感的数据,比如密码,key等

 2.特殊数据到特定Minion上

 3.动态的内容

 4.其他数据类型


查看Minion的Pillar信息

 salt '*' pillar.items

查看某个Pillar值

 salt '*' pillar.item      #只能看到顶级的

 或者

 salt '*' pillar.get : #可以取到更小粒度的


编写pillar数据

1.指定pillar_roots,默认是/srv/pillar(可通过修改master配置文件修改),建立目录

 mkdir /srv/pillar

 cd /srv/pillar

2.编辑一个pillar数据文件

 vim test1.sls

 name: 'salt'

 users:

   hadoop: 1000

redhat: 2000

ubuntu: 2001

3.建立top file指定minion到pillar数据文件

 vim top.sls

 base:

   '*':

     - test1

4.刷新Pillar数据

salt '*' saltutil.refresh_pillar

5.测试

 salt '*' pillar.get name

 salt '*' pillar.item name


在state中通过jinja使用pillar数据

vim /srv/salt/user.sls

 {% for user, uid in pillar.get(’users’, {}).items() %}  ##pillar.get('users',{})可用pillar['users']代替,前者在没有得到值的情况下,赋默认值

 `user`:

   user.present:

     - uid: `uid`

 {% endfor %}


当然也可以不使用jinja模板

vim /srv/salt/user2.sls

{{ pillar.get('name','') }}:

 user.present:

   - uid: 2002

通过jinja模板配合grains指定pillar数据

/srv/pillar/pkg.sls


pkgs:

 {% if grains[’os_family’] == ’RedHat’ %}

 apache: httpd

 vim: vim-enhanced

 {% elif grains[’os_family’] == ’Debian’ %}

 apache: apache2

 vim: vim

 {% elif grains[’os’] == ’Arch’ %}

 apache: apache

 vim: vim

 {% endif %}




六。grains 就是服务器的一些静态信息,这里强调的是静态,就是不会变的东西,比如说os是centos,如果不会变化,除非重新安装系统

定义minion的grains可以写在/etc/salt/minion中格式如下

grains:

 roles:

   - webserver

   - memcache

 deployment: datacenter4

 cabinet: 13

 cab_u: 14-15


或者卸载/etc/salt/grains中,格式如下

roles:

 - webserver

 - memcache

deployment: datacenter4

cabinet: 13

cab_u: 14-15


也可以在master中编写grains的模块,同步到minion中,用Python来写很简单的

1.在/srv/salt中建立_grains目录

 mkdir /srv/salt/_grains

2.编写grains文件,需要返回一个字典

 vim test1.py

 def hello():                      ##函数名字无所谓,应该是所有函数都会运行

   agrain = {}

   agrain['hello'] = 'saltstack'

return agrain                   ##返回这个字典

3.同步到各个minion中去

 salt '*' saltutil.sync_grains | salt '*' saltutil.sync_all | salt '*' state.highstate

4.验证

 salt '*' grains.item hello


七。使用 salt state

使用salt state system是非常简单的,它的核心是写sls(SaLt State file)文件,sls文件默认格式是YAML格式(以后会支持XML),并默认使用jinja模板,YAML与XML类似,是一种简单的适合用来传输数据的格式,而jinja是根据django的模板语言发展而来的语言,简单并强大,支持for if 等循环判断。salt state主要用来描述系统,软性,服务,配置文件应该出于的状态,常常被称为配置管理!

通常state,pillar,top file会用sls文件来编写。state文件默认是放在/srv/salt中,它与你的master配置文件中的file_roots设置有关


示例:

apache.sls文件内容 ##/srv/salt/apahce.sls,以后没有用绝对路径意思就是在/srv/salt下


apache:            ##state ID,全文件唯一,如果模块没跟-name默认用的ID作为-name

 pkg:             ##模块

   - installed    ##函数

  #- name: apache ##函数参数,可以省略

 service:         ##模块

   - running      ##函数

  #- name: apache ##函数参数,这个是省略的,也可以写上

   - require:     ##依赖系统

     - pkg: apache  ##表示依赖id为apache的pkg状态


YAML通过用缩进来分层,且'-' ':'等后面必须跟一个空格,YAML与python数据类型对比


a:                                

 b: test           vs               a = {'b': 'test', 'c': 'ok'}           字典

 c: ok


a:

 - b

 - c               vs               a = ['b', 'c', 'd']                    列表

 - d


下面来解释上面示例的意思:

声明一个叫apache的状态id,该id可以随意,最好能表示一定意思,pkg代表的是pkg模块,installed是pkg模块下的一个函数,描述的是状态,该函数表示apache是否部署,返回值为True或者False,为真时,表示状态OK,否则会去满足该状态(下载安装apache),如果满足不了会提示error,在该模块上面省略了参数-name: apache,因为ID为apache,这些参数是模块函数需要的(可以去查看源码),,service是指的service模块,这个模块下主要是描述service状态的函数,running状态函数表示apache在运行,省略-name不在表述,-require表示依赖系统,依赖系统是state system的重要组成部分,在该处描述了apache服务的运行需要依赖apache软件的部署,这里就要牵涉到sls文件的执行,sls文件在salt中执行时无序(如果没有指定顺序,后面会讲到order),假如先执行了service这个状态,它发现依赖pkg包的安装,会去先验证pkg的状态有没有满足,如果没有依赖关系的话,我们可以想象,如果没有安装apache,apache 的service肯定运行会失败的,我们来看看怎么执行这个sls文件:


# salt '*' state.sls apache   ##在命令行里这样执行就ok了,.sls不要写,如果在目录下,将目录与文件用'.'隔开,如: httpd/apache.sls --> httpd.apache

或者

# salt '*' state.highstate    ##这需要我们配置top file执定哪个minion应用哪个状态文件


top.sls内容


base:

 '*':

   - apache


下面我们继续看一些比较复杂的:


ssh/init.sls文件内容


openssh-client:

 pkg.installed

/etc/ssh/ssh_config:

 file.managed:

   - user: root

- group: root

- mode 644

- source: salt://ssh/ssh_config

- require:

 - pkg: openssh-client

ssh/server.sls文件内容


include:

 - ssh


openssh-server:

 pkg.installed


sshd:

 service.running:

   - require:

 - pkg: openssh-client

 - pkg: openssh-server

 - file: /etc/ssh/banner

 - file: /etc/ssh/sshd_config


/etc/ssh/sshd_config:

 file.managed:

   - user: root

- group: root

- mode: 644

- source: salt://ssh/sshd_config

- require:

 - pkg: openssh-server


/etc/ssh/banner:

 file:

   - managed

- user: root

- group: root

- mode: 644

- source: salt://ssh/banner

- require:

 - pkg: openssh-server


两个文件的内容,主要是描述ssh服务的状态的,有没有觉得YAML看起来确实是比较好看的,有层次感,如果用XML的话可能就不是那么赏心悦目了,我们从开头开始说起,ssh/init.sls,学过Python的都知道目录下面的init文件是特殊文件,它怎么特殊呢,它特殊在当我们应用目录时会应用该文件的内容,如我们执行 salt '*' state.sls ssh时应用的就是init.sls文件,明白了吗?再看里面的内容,前两行我们已经看过了,是描述某个rpm包有没有安装的,第三行是ID,也可以用来表示-name,以省略-name,file.managed是file模块与函数managed的快捷写法,看server.sls下最后就知道了,managed它描述了某个文件的状态,后面跟的是managed的参数,user,group,mode你们一看就知道什么意思了,关于这个source是指从哪下载源文件,salt://ssh/sshd_config是指的从salt的文件服务器里面下载,salt文件服务器其实就是file_roots默认/srv/salt/明白了吗,所以salt://ssh/sshd_config指的就是 /srv/salt/ssh/sshd_config,出来用salt的文件服务器,也可以用http,ftp服务器。- require是依赖系统不表,以后会详细说它的。再往下是server.sls文件,include表示包含意思,就是把ssh/init.sls直接包含进来,省的复制粘贴了,为什么include的不是ssh/init你懂了吗?下面的相信你能看懂了。


这时你会看到/srv/salt的目录树是:


ssh/init.sls

ssh/server.sls

ssh/banner

ssh/ssh_config

ssh/sshd_config


下面再来看一个官方样例:

ssh/custom-server.sls 文件内容


include:

 - ssh.server

extend:

 /etc/ssh/banner:

   file:

 - source: salt://ssh/custom-banner


python/mod_python.sls文件内容


include:

 - apache


extend:

 apache:

   service:

 - watch:

   - pkg: mod_python


其实我就想让你看看extend的用法而已,嘿嘿,首先我们include的别的文件,但是里面的内容并不是全部符合我们的要求,这时我们就需要用extend来重写部分内容,特殊的是依赖关系都是追加。custom-server.sls文件意思是包含ssh/server.sls,扩展/etc/ssh/banner,重新其source而其它的如user,group等不变,与include一致。 mode_python.sls文件意思是把apache.sls包含进来,想apache-service是追加了依赖关系(watch也是依赖系统的函数).


八。关于渲染器render system

我们上面也提过salt默认的渲染器是yaml_jinja,salt处理我们的sls文件时,会先把文件用jinja2处理,然后传给ymal处理器在处理,然后生成的是salt需要的python数据类型。除了yaml_jinja还有yaml_mako,yaml_wempy,py,pydsl,我比较感兴趣的就是yaml_jinja,还有py,yaml_jinja是默认的,而py是用纯python来写的。下面来看个样例吧,


apache/init.sls文件内容


apache:

 pkg:installed:

   {% if grains['os'] == 'RedHat' %}

- name: httpd

{% endif %}

 service.running:

   {% if grains['os'] == 'Redhat' %}

- name: httpd

{% endif %}

- watch:

 - pkg: apache


这个样例很简单,就是加了个判断,如果Minion的grains的os是RedHat那么apache的包名是httpd,默认是apache,我们知道在别的Linux发行版上,如ubuntu,suse他们的apache的包名就是叫apache,而在redhat系上则叫httpd,所以才有了这个判断写法,下面的service也是如此。我们着重说语法,jinja中判断,循环等标签是放在{%  %}中的,通常也会有结束标签{% end** %},而变量是放在 ` `中的,salt,grains,pillar是salt中jinja里面的三个特殊字典,salt是包含所有salt函数对象的字典,grains是包含minion上grains的字典,pillar是包含minion上pillar的字典。


示例:for

user/init.sls文件内容


{% set users = ['jerry','tom','gaga'] %}

{% for user in users %}

` user `:

 user.present:

   - shell: /bin/bash

   - home: /home/` user `

{% endfor %}


示例;salt字典

user/init.sls文件内容


{% if salt['cmd.run']('uname -i') == 'x86_64' %}

hadoop:

 user.present:

   - shell: /bin/bash

   - home: /home/hadoop

{% elif salt['cmd.run']('uname -i') == 'i386' %}

openstack:

 user.present:

   - shell: /bin/bash

- home: /home/openstack

{% else %}

django:

 user.present:

   - shell: /sbin/nologin

{% endif %}


py渲染器

说明:py渲染器是用纯python写的sls文件,它返回的数据与yaml_jinja经过jinja处理经过yaml处理后的数据类似 ,用其他渲染器需要在sls文件头行声明用的渲染器类型,#!py就是声明用的py渲染器,py中可用的变量有__salt__,__grains__,__pillar__,__opts__,__env__,__sls__,前三个分别对应jinja里的salt,grains,pillar,__opts__是minion的配置文件的字典,__env__对应的是环境如base,__sls__对应的是sls的文件名


示例:

user/init.sls


#!py


import os

def run():

   '''add user hadoop'''

platform = os.popen('uname -a').read().strip()

if platform == 'x86_64':

   return {'hadoop': {'user': ['present',{'shell': '/bin/bash'}, {'home': '/home/hadoop'}]}}

elif platform == 'i386':

       return {'openstack': {'user': ['present', {'shell': '/bin/bash'}, {'home': '/home/openstack'}]}}

else:

   return {'django': {'user': ['present', {'shell': '/sbin/nologin'}]}}


说明: 首行声明了使用py作为渲染器,导入了os模块,声明run函数,py渲染sls文件是从run函数开始的,其它的就是python的语法了,注意的是return的数据结构{ID: {module: [func, arg1,arg2,...,]}} 或 {ID: {module.func: [arg1,arg2,..,]}} 。表示的内容与“示例;salt字典”表达的相同


九。state的执行顺序  

以前我们说过,state的执行时无序,那个无序是指执行我们写的那个sls是无序的,正是因为那个无序,salt保证每次执行的顺序是一样的,就加入了state order,在说它之前看看High Data(高级数据?)和Low Data(低级数据?),高级数据我理解的就是我们编写sls文件的数据,低级数据就是经过render和parser编译过的数据。


查看highdata

salt ’*’ state.show_highstate

查看lowdata

salt ’*’ state.show_lowstate


通过查看lowdata我们发现里面有一个字段order,因为salt默认会自动设置order,从10000开始。可以通过设置master配置文件参数state_auto_order: False来关闭


Order的设定:

1.include 被include的文件Order靠前,先执行

2.手动定义order字段,如

  apache:

    pkg:

  - installed

  - order: 1

 order的数字越小越先执行从1开始,-1是最后执行

3.依赖关系系统


十。依赖关系系统requisite system

前面我们已经用过了依赖关系系统,就是定义状态与状态之间的依赖关系的,经常遇到的依赖系统的函数有'require'和'watch'和它们的变种'require_in','watch_in',require和watch有什么区别吗?

1.不是所有的state都支持watch,比较常用的是service

2.watch定义的依赖条件发生变化时会执行一些动作,如当配置文件改变时,service会重启


示例:

apache/init.sls文件内容


/etc/httpd/httpd.conf:

 file:

   - managed

- source: salt://httpd/httpd.conf

httpd:

 pkg:

   - installed

 service:

   - running

   - require:

     - pkg: httpd

   - watch:

     - file: /etc/httpd/httpd.conf            ##当httpd.conf改变时,重启httpd服务

require与require_in, watch与watch_in

require,watch是指依赖,require_in,watch_in是指被依赖

a reuire b 那么就是b require_in a

a watch b  那么就是b watch_in a


示例:

apache/init.sls文件内容


/etc/httpd/httpd.conf:

 file:

   - managed

- source: salt://httpd/httpd.conf

- watch_in:

 - service: httpd

httpd:

 pkg:

   - installed

- require_in:

 - service: httpd

 service:

   - running


十一。salt state环境

针对不用环境,应用不同的state的file,salt支持多环境,比如开发,测试,生产等环境,我们通过修改Master配置文件对不同的环境应用不同的目录!


file_roots:

 base:

   - /srv/salt/prod   ##生产环境

 qa:

   - /srv/salt/qa     ##测试环境,如果没发现去prod里面找

- /srv/salt/prod

 dev:

   - /srv/salt/dev    ##开发环境,如果找不到,先去qa里找,如果找不到再去prod里面找

- /srv/salt/qa

- /srv/salt/prod

/srv/salt/prod/top.sls文件内容

base:

 'web*prod*':

   - webserver.foobarcom

qa:

 'web*qa*':

   - webserver.foobarcom

dev:

 'web*dev':

   - webserver.foobarcom

pillar的目录与file_roots无关,所以Pillar的目录默认还是/srv/salt,pillar只是Minion的一些信息,不会对系统有什么改变,所以不需要区分环境,通常base即可。

/srv/pillar/top.sls文件内容


base:

 'web*prod*':

   - webserver.prod

 'web*qa*':

   - webserver.qa

 'web*dev*':

   - webserver.dev


/srv/pillar/webserver/prod.sls文件内容


webserver_role: prod


/srv/pillar/webserver/qa.sls文件内容


webserver_role: qa


/srv/pillar/webserver/dev文件内容


webserver_root: dev


最后sls文件/srv/salt/prod/webserver/foobarcom.sls(该文件会被所有环境访问到)的内容:

{% if pillar.get('webserver_role', '') %}

/var/www/foobarcom:

 file.recurse:

   - source: salt://webserver/src/foobarcom

- env: {{ pillar['webserver_role'] }}

- user: www

- group: www

- dir_mode: 755

- file_mode: 644

{% endif %}


开发完成后,应用sls文件

1.现在开发环境

salt -I 'webserver_role:dev' state.sls webserver.foobarcom


十一。关于salt简介,安装和基本配置

说明:salt是一个异构平台基础设置管理工具(虽然我们通常只用在Linux上),使用轻量级的通讯器ZMQ,用Python写成的批量管理工具,完全开源,遵守Apache2协议,与Puppet,Chef功能类似,有一个强大的远程执行命令引擎,也有一个强大的配置管理系统,通常叫做Salt State System。


安装:

1.安装epel源

 For RHEL 5:

   rpm -Uvh http://mirror.pnl.gov/epel/5/i386/epel-release-5-4.noarch.rpm

 For RHEL 6:

   rpm -Uvh http://ftp.linux.ncsu.edu/pub/epel/6/i386/epel-release-6-8.noarch.rpm

2.安装salt-master端,也就是服务端

 yum -y install salt-master

3.安装salt-minion端,也就是client端

 yum -y install salt-minion


配置:

通常学习环境,master用默认配置就好,修改Minion配置文件/etc/salt/minion

master: master_ip或master_FQDN     ##注明master的ip或者域名

id: minion_id                      ##取一个独一无二的minion名字,以方便辨认


启动:

service salt-master start

service salt-minion start


master接受minion的key:

salt-key -L ##查看所有minion_key

salt-key -a 'key-name' ##接受该key

或者salt-key -A        ##接受所有key


测试:

 salt '*' test.ping   ##查看在线minion

 salt '*' pkg.install ftp  ##所有Minion安装ftp

 说明:

 1. '*' 代表的是target是指在那些minion上操作

 2. ’test' ,'pkg'是一个执行模块,所有的执行模块见http://docs.saltstack.com/ref/modules/all/index.html?highlight=full%20list%20builtin

 3. 'ping','install'是执行模块下面的函数,同样参加上述链接查看帮助

 4. 'ftp' 是函数的参数(arg),有的函数需要参数,有的不需要


帮助:

   salt '*' sys.doc     ##查看所有执行模块的doc

salt '*' sys.doc test   ##查看test模块的帮助

salt '*' sys.doc test.ping ##查看test.ping函数的帮助

遇到弄不清楚的,尽管sys.doc吧

执行命令:

   salt '*' cmd.run 'uptime'  ##在所有机器上执行命令uptime

salt '*' cmd.run '--reboot--'  ##这类命令很危险,请不要尝试,请想办法禁止

基本原理:

 salt区分server和client,server端就是salt的master,client端就是minion,minion与master之间通过ZeroMQ消息队列通信,minion上线后先与maste端联系,把自己的pub key发过去,这时master端通过salt-key -L命令就会看到minion的key,接受该minion-key后,也就是master与minion已经互信,master可以发送任何指令让minion执行了,salt有很多可执行模块,比如说cmd模块,在安装minion的时候已经自带了,它们通常位于你的python库中,locate salt | grep /usr/ 可以看到salt自带的所有东西。这些模块是python写成的文件,里面会有好多函数,如cmd.run,当我们执行salt '*’ cmd.run 'uptime'的时候,master下发任务匹配到的minion上去,minion执行模块函数,并返回结果。master监听4505和4506端口,4505对应的是ZMQ的PUB system,用来发送消息,4506对应的是REP system是来接受消息的。


十二。salt常用命令

1.salt 该命令执行salt的执行模块,通常在master端运行,也是我们最常用到的命令

 salt [options] '' [arguments]

 如: salt '*' test.ping

2.salt-run 该命令执行runner(salt带的或者自定义的,runner以后会讲),通常在master端执行,比如经常用到的manage

 salt-run [options] [runner.func]

 salt-run manage.status   ##查看所有minion状态

 salt-run manage.down     ##查看所有没在线minion

 salt-run manged.up       ##查看所有在线minion

3.salt-key 密钥管理,通常在master端执行

 salt-key [options]

 salt-key -L              ##查看所有minion-key

 salt-key -a   ##接受某个minion-key

 salt-key -d   ##删除某个minion-key

 salt-key -A              ##接受所有的minion-key

 salt-key -D              ##删除所有的minion-key

4.salt-call 该命令通常在minion上执行,minion自己执行可执行模块,不是通过master下发job

 salt-call [options] [arguments]

 salt-call test.ping           ##自己执行test.ping命令

 salt-call cmd.run 'ifconfig'  ##自己执行cmd.run函数

5.salt-cp  分发文件到minion上,不支持目录分发,通常在master运行

 salt-cp [options] '' SOURCE DEST

 salt-cp '*' testfile.html /tmp

 salt-cp 'test*' index.html /tmp/a.html

6.salt-ssh 0.17.1版本加入的salt-ssh,以后会讲

7.salt-master master运行命令

 salt-master [options]

 salt-master            ##前台运行master

 salt-master -d         ##后台运行master

 salt-master -l debug   ##前台debug输出

8.salt-minion minion运行命令

 salt-minion [options]

 salt-minion            ##前台运行

 salt-minion -d         ##后台运行

 salt-minion -l debug   ##前台debug输出

9.salt-syndic  syndic是salt的代理,以后会说到


十三。普通用户执行salt

普通用户执行salt两种方案:1,salt ACL   2.salt external_auth

1.ACL

 1) 设置master配置文件

     client_acl:

   monitor:

     - test*:

   - test.*

dev:

 - service.*

sa:

 - .*

 2) 重启Master

     # service salt-master restart

 3) 目录和文件权限

     # chmod +r /etc/salt/master

 # chmod +x /var/run/salt

 # chmod +x /var/cache/salt

 4) 测试

     # su - monitor

 # salt 'test*' test.ping

 # exit; su - sa

 # salt '*' test.ping

 # salt '*' cmd.run 'uptime'

 # exit;

2.external_auth

 1) 修改master配置文件

     external_auth:

   pam:

 monitor:

   - 'test*':

 - test.*

 sa:

   - .*

 2) 3)与ACL相同

 4) 测试

     # salt -a pam 'test*' test.ping    ##会提示输入账号密码,所以external_auth与当前用户无关

   username: monitor

       password:

 # su - monitor

 # salt -a pam '*' cmd.run 'uptime'

   username: sa

password:

 5) 使用Token不必每次都输入账号密码,使用external_auth每次都是需要密码的,这样多麻烦,这里引入了Token,它会保存一串字符到在当前用户家目录下.salt_token中,在有效时间内使用external_auth是不需要输入密码的,默认时间12hour,可以通过master配置文件修改

     # salt -T -a pam '*' test.ping

   username: sa

password:

 # salt -a pam '*' test.ping    #不会提示输入密码了

十四。salt schedule

salt的schedule是什么东西?schedule是salt中的crontab,就是周期性执行一些函数,需要注意的是在minion上执行的函数是salt的可执行模块里的函数,在master上执行的是runner模块的函数,下面看看如何设置:

master是修改master配置文件/etc/salt/master:

schedule:

 overstate:                    ##这个是ID,可以随意起,全文件唯一

   function: state.over        ##对于master,function就是runner

   seconds: 35                 ##间隔秒数

   minutes: 30                 ##间隔分数

   hours: 3                    ##间隔小时数

这时每隔3小时30分35秒,master就会运行一个state.over这个runner


minion的schedule定义有两种方式

1.通过修改minion的配置文件,这种方式需要修改所有Minion的配置文件略麻烦

schedule:

 highstate:

   function: state.highstate

seconds: 30

minutes: 5

hours: 1


2.为Minion指定pillar

/srv/pillar/schedule.sls文件内容

schedule:

 highstate:

   function: state.highstate

seconds: 30

minutes: 5

hours: 1

通过top file指定到Minion

/srv/pillar/top.sls文件内容

base:

 *:

   - schedule


十五。YAML语法风格

1.空格和Tabs

 在YAML中不要使用Tab

2.缩进

 YAML推荐缩进为2个空格,':','-'后面缩进1个空格再写

3.数字会解析成数字

 如mode: 0644会解析成mode: 644,可用'括住防止mode: '0644'此情况

4.YAML不允许双简写

 vim:

   pkg.installed   ##第一个简写,单一个简写没问题

user.present    ##第二个简写,加上它是不支持的

 不要偷懒写成下面这样吧。

 vim:

   pkg:          

 - installed

user:

 - present

5.YAML只支持ASCII

 其它字符集最好不要使用,如果非要使用用以下格式:

 - micro: '\u00b5'

6.下划线_将会被删除

 date: 2013_05_13  --> date: 20130513

 通过'括住防止出现该问题

 date: '2013_05_13'  

十六。salt事件系统与反应系统 event and reacter system

我们知道Master与Minion是基于ZMQ通信的,他们通信我们看来是消息队列,对它们来说这些消息就是一些事件,什么事件应该做什么,是salt基本已经预设好了。我们学习它的事件系统来完成一些自定义的行为,后面的反应系统就是基于事件系统的。一条消息其实就是一个事件,事件通常是一个字典数据,这个字典数据通常包含tag,这个tag是用来区分用途过滤消息的,详见绿大-https://groups.google.com/forum/#!topic/saltstack-users-cn/wXVE4ydnnzc ,让我们来看看这些事件。


捕捉事件(listen event)

1.下载官方给的事件捕捉程序eventlisten

https://github.com/saltstack/salt/blob/develop/tests/eventlisten.py

打开网址,复制下载,不要直接wget

2.运行该程序

Master: python2.6 eventlisten.py                         ##捕捉master端的event直接运行即可

Minion: python2.6 eventlisten.py -n minion   ##捕捉minion端的需要额外参数,minion-id是该Minion的id


发送事件(fire event)

Master发给minion

salt '*' event.fire "{'data': 'some message'}" "tag"     ##前面必须是字符串包住的字典,后面是tag,如果你的minion在监听event,你会看到这条event的


Minion发给minion

salt-call event.fire_master 'some message' 'tag'  ##前面数据类型没有要求,后面是tag,去master那看看收到了没有


Minion发给自己

salt-call event.fire "{'data': 'some message'}" 'tag' ##前面必须是字符串包住的字典,后面是tag



用code来捕捉,并发送event


捕捉事件

Maste:

# python2.6

>>> import salt.utils.event

>>> event = salt.utils.event.SaltEvent('master', '/var/run/salt/master')

##master表明是在master端监听,/var/run/salt/master是你master的sock_dir

>>> data = event.get_event()

>>> print(data)       ##查看内容

>>> data = event.get_event(wait=10, tag='auth') ##wait是指timeout时间,默认5s,用tag来过滤事件,可省略

>>> print(data)                

>>> for data in event.iter_events(tag='auth'):  ##用迭代器一直查看事件

>>>     print(data)

Minion:

#python2.6

>>> import salt.utils.event

>>> event = salt.utils.event.SaltEvent('minion', '/var/run/salt/minion',id='minion_id')

##minion代表是在minion端监听,/var/run/salt/minion是minion端的sock_dir,minion_id是该Minion的id

>>> data = event.get_event()

>>> print(data)

>>> for data in event.iter_events(tag='auth'):  ##用迭代器一直查看事件

>>>     print(data)


-----------------先这样吧

发送事件:

Master:

>>> import salt.utils.event

>>> event = salt.utils.event.SaltEvent('master', '/var/run/salt/minion')

>>> event.fire_event({'hello': 'world'}, 'hello')

-----------------先这样


反应系统(reacter system)

反应系统是基于事件系统的,它的作用是当master收到来自minion的特殊事件后就触发某些动作,比如minion上线后发送一个init事件,master收到后,对其应用init的状态文件,minion没有反应系统,事情就是这样的。


配置reactor

1.修改master配置文件或者在/etc/salt/master.d/中建立reactor.conf,内容

reactor:

 - 'testtag':                    ##接收到的tag

   - /srv/reactor/start.sls

- /srv/reactor/monitor.sls

 - 'test1*tag':                  ##接收到的tag,支持通配符

   - /srv/reactor/other.sls

2.建立reactor响应sls文件

/srv/reacter/start.sls文件内容


{% if data['id'] == 'mysql1' %}

delete_file:

 cmd.cmd.run:

   - tgt: 'G@os:CentOS'

- expr_form: compound

- arg:

 - rm -rf /tmp/*

{% endif %}


/srv/reactor/other.sls文件内容


{% if data['data']['state'] == 'refresh' %}

overstate_run:

 runner.state.over

{% endif %}


下面来解释一下这两个文件,reacter的sls文件是支持jinja的,所以第一行是通过jinja来判断,reacter的sls支持两个变量data和tag, data是接受事件的那个字典,tag就是事件的tag,所以第一行的判断就很好理解了,第二行是id,可以随意起,第三行是要运行的执行模块或者runner,如果是执行模块,以cmd.开始,如果是runner则以runner.开始,可执行模块执行需要target,所以- tat:后面跟的就是可执行模块的target,- expr_form指的target的匹配方式,- arg是只执行模块函数的参数,runner一般不需要这些。所以第一个示例相当于执行了salt -C 'G@mysql1' cmd.run 'rm -rf /tmp/*' 第二个相当于执行了 salt-run state.over


练习:

自己写个reacter在让minion触发一个event测试一下吧




十七。salt Mine

salt的用的词都太高明,像Grains,Pillar,Mine真心没一个合适的词去翻译,Mine是做什么的呢?Mine的作用是在静态数据和动态数据建立起一座桥梁(官方文档如是说),Mine从minon收集数据然后发送给Master,并缓存在Master端,所有Minion都可以轻易的共享到,Master通常会维护比较新的数据,如果需要维护长期数据,就要考虑retruner或外部的工作缓存了。 mine的出现是用来解决一定问题的. 在Salt的网络体系中,各个minion是毫无关系,相互独立的. 但是在实际应用中,minion之间其实是有一定关联的,比如一台机器需要获取到另一台机器的一些信息或者执行一些命令. 后来Salt加入了peer系统(http://docs.saltstack.com/ref/peer.html)使其成为可能. 但是peer系统每次使用的时候都会重新执行一遍, 显然很多不常变化的信息重复执行效率较低,性能开销较大. 所以就有了后来的mine(peer和mine的关系是我杜撰出来的,如有雷同,纯属巧合). mine系统存储在master端, minion想获取的时候, 通过mine.get获取下就可以了,简单方便 by绿肥


修改minion配置文件,配置Mine

mine_functions:

 network.interfaces: []

 test.ping: []

 mine_interval: 1


重启Minion,在master端测试

salt '*' mine_get '*' network.interfaces

salt '*' mine_get '*' test.ping

salt 'test1' mine_get '*' test.ping    ##查看test1上能得到mine数据


十八。salt ssh

从0.17.0开始salt加入salt ssh,salt ssh不需要在客户端安装salt-minion包了,是通过ssh协议来完成运城命令执行,状态管理等任务的。它是作为master-minion形式的补充出现的,原理是有一个花名册的文件,里面记录了各个minion的信息,ip,账号,密码,等,需要远程执行命令时,直接通过ssh来执行,速度与master-minion形式慢很多。


使用:

1.配置/etc/salt/roster格式如下

test1:

 host: 192.168.1.133

 user: salt

 passwd: redhat

 sudo: True

 port: 22

 timeout: 5

test2:

 host: 192.168.1.134

 user: root

 passwd: redhat

test3:

 host: 192.168.1.135

 user: sa

 sudo: True

 说明: test1我们定义了所有常见的选项,test2我们用了超级用户,使用账号密码,test3我们使用普通用户,没有写密码,就是通过key来认证了,并且以sudo方式执行的,需要注意的是1.key认证用的是/etc/salt/pki/master/ssh/目录下的密钥。2.如果普通用户的话,需要有sudo权限,因为一些功能,包括test.ping都需要sudo权限。


测试:

 salt-ssh '*' test.ping

 salt-ssh '*' -r 'ls /'   ##执行shell命令

 salt-ssh '*' cmd.run 'ls /' ##用模块来执行也是可以的

 salt-ssh '*' state.sls   ##执行状态,state.sls在0.71.0中还存在bug,0.72.0中已解决


十九。Returners

默认所有minion返回的值都会发送到master端,我们可以看到,returner就是让Minion把返回的值发给其它地方,如redis,MySQL,或者一个文本

下面我们来自定义一个returner:

1.建立自定义returner

# mkdir -p /srv/salt/_returners;

# vim mysql.py  ##就用官方给的例子吧,修改其中mysql的Host,user和pass

 内容见https://github.com/saltstack/salt/blob/develop/salt/returners/mysql.py

2.建立需要的数据库

 见https://github.com/saltstack/salt/blob/develop/salt/returners/mysql.py注释里的见表语句

3.授权其他主机用户可写该表

 > grant all on salt.* to 'user_in_returner'@'%' identified by 'passwd_in_returner';

4.同步

# salt '*' saltutil.sync_all      ##同步到minion上去

5.测试

# salt '*' test.ping --return mysql    ##数据返回到mysql上去,打开mysql查看


二十。扩展salt

通过自定义各个模块来扩展salt,常见自定义模块有:

1.可执行模块 Execution Modules

 如我们常用的cmd.run , test.ping这样的可执行模块

2.Grains

 扩展grains,grains是一些静态信息,可能好多我们需要的没有,我们可以通过编写grains模块自定义grains

3.状态模块 State Module

 如我们常用的pkg.install,file.managed

4.Returners

 我们可以自定义returner,将返回的数据发送到其他存储,只要符合固定的格式就行了

5.Runner

 Runner是在master端快速执行的模块,自定义很方便


135.97


二十一。自定义可执行模块

所有可执行module见https://github.com/saltstack/salt/tree/develop/salt/modules,或http://docs.saltstack.com/ref/modules/all/index.html?highlight=full%20list%20builtin

1.建立自定义模块目录,通常所有自定义模块放在该目录下

# mkdir /srv/salt/_modules

2.编写模块

# vim test.py

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

'''

support for yum of RedHat family!

'''


def __virtual__():

   '''

   Only RedHat family os can use it.

   '''

   if __grains__.get('os_family', 'unkown') == 'RedHat':

       return 'yum'

   else:

       return False


def install(rpm):

   cmd = 'yum -y install {0}'.format(rpm)

   ret = __salt__['cmd.run'](cmd)

   return ret


说明: __virtual__函数通常用来匹配是否满足该模块的环境,如果满足return出来的字符串作为该模块的名字而不是文件名,如果return的是False代表的此模块无效,不能使用。在自定义模块中可以中__grains__是一个包含了minion 所有grains的字典,__pillar__是包含了所有Pillar的grains字典,__salt__是所有可执行函数对象的字典,通常最常使用的就是这三个变量了。再往下面是定义了函数install,在salt中一般不用'%s' % var这种格式化形式,而是使用字符串的format方法,具体使用见百度。下面就是通过__salt__执行了cmd.run这个函数来运行yum命令,很简单吧,最后把结果返回回去。

3.测试

# salt '*' yum.install ftp  ##查看返回值


二十二。自定义grains

自定义的grains也是由Python写成的,通常放在/srv/salt/_grains下,grains需要返回一个字典,__salt__,__grains__,__pillar__也是可以在grains中使用的。前面已经介绍过写简单自定义grains了,复杂就就参照https://github.com/saltstack/salt/blob/develop/salt/grains/core.py官方这个吧


二十三。自定义returner

前面已经看过官方的mysql的returner了,今天来说说自定义returner需要注意的,来个例子吧。

/srv/salt/_returners/file.py内容


def __virtual__():

   return 'file'

def returner(ret):

   '''

   Return information to /tmp/returns.txt.

   '''

   # open a file

   result_file = '/tmp/returns.txt'

   f = open(result_file, 'a+')

   f.write(str(ret))

   f.close()

# salt '*' saltutil.sync_all         ##同步模块

# salt '*' test.ping --return file   ##测试

# cat /tmp/returns.txt               ##在minion上查看

 {'jid': '20131227153001246117', 'return': True, 'retcode': 0, 'success': True, 'fun': 'test.ping', 'id': 'test1'}


说明:

通过这个简单的例子我们了解返回的值是个字典,字典包括的项就是上面我们看到的,以后写其它returner时,也就是把这个字典的值写到不同的地方而已。这个returner的意思就是把返回的值写到各个minion的/tmp/returns.txt中。



二十四。file state backup

来例子看看吧。

/srv/salt/test.sls文件内容


/tmp/test.txt:

 file.managed:

   - source: salt://test.txt

   - backup: minion


其中多了一个参数backup,后面跟的值minion,意思是说这个文件在minion中备份一份,文件名带着时间戳,备份位置在/var/cache/salt/minion/file_backup


执行并测试:

# salt '*' state.sls test    ##注,多修改几次test.txt,多运行几次该state

# salt '*' file.list_backups /tmp/test.txt ##这是会返回备份序号,时间,位置,大小

 test1:

   ----------

...省略

   3:

       ----------

       Backup Time:

           Fri Dec 27 2013 16:44:05.840061

       Location:

           /var/cache/salt/minion/file_backup/tmp/test.txt_Fri_Dec_27_16:44:05_840061_2013

       Size:

           3300

   4:

       ----------

       Backup Time:

           Fri Dec 27 2013 16:32:47.785399

       Location:

           /var/cache/salt/minion/file_backup/tmp/test.txt_Fri_Dec_27_16:32:47_785399_2013

       Size:

           2


回退

当文件改错后,我们可以用备份文件回退

# salt '*' file.restore_backup /tmp/test.txt 2   ##回退的文件,与想要回退的序列号

删除

删除不需要的备份文件

# salt '*' file.delete_backup /tmp/test.txt 3