saltstack系统中管理对象叫做Target,在master上可以采用不同的Tatget去管理不同的minion。这些Target都是通过去管理和匹配Minion的ID来做一些集合。
# salt -E '[a-z].*' test.ping #直接就是匹配字母开头的minion
# salt -E 'a.*' test.ping #匹配a开头的minion
# salt -E '(a|z).*' test.ping #匹配a或者z开头的minion,切记是开头而不是包含。
#salt -L 'dasha_ceshi_172.16.5.239,dasha_ceshi_172.16.5.240' test.ping ##同时让多个minion去执行,多minion之间用逗号隔开(这里只是ID,组的不行)。
minions的Grains信息时在Minions服务启动的时候汇总给Master的,Grains是saltstack组建中非常重要的,因为在配置部署的过程中会经常使用它,Grains是saltstack记录minion的一些静态信息的组件,grains里面记录着每台minion的一些常用属性如CPU、内存、操作系统类型和版本等,可以通过grains.item查看某台minion的所有grains信息。
# salt -G 'os:CentOS' test.ping #让minion端操作系统是CentOS去执行,当然也支持正则表达式的方式
# salt -G 'os:C*' test.ping #如匹配操作系统是C开头的
# salt -G 'osmajorrelease:[1-9]' test.ping #匹配系统版本是数字的。
cat /etc/salt/master | grep nodegroups
这里还可以使用正则及其他匹配方式,我这里写的是最简单,也是最繁琐的一种。
nodegroups: ceshi1: dasha_ceshi_172.16.5.239 ceshi2: dasha_ceshi_172.16.5.240
#salt -N ceshi1 test.ping #测试test这组。
解释:复合匹配的意思是,使用不同的判断条件精准的在指定的minion中执行。
#salt -C 'G@os:CentOS and G@osmajorrelease:7' test.ping #让os是CentOS并且系统版本是7的去执行 #salt -C 'G@os:CentOS and G@osmajorrelease:7 and E@dasha_ceshi*' test.ping # 在操作系统是CentOS版本是7,并且id开头是dasha_ceshi的机器是执行test.ping操作。
[root@bogon ~]# salt -S '172.16.5.0/24' test.ping #匹配IP是172.16.5.0网段的的所有IP地址,执行test.ping操作 dasha_ceshi_172.16.5.240: True dasha_ceshi_172.16.5.239: True [root@bogon ~]# salt -S '172.16.5.239' test.ping #在IP是172.16.5.239服务器上执行test.ping操作。 dasha_ceshi_172.16.5.239: True
Grains上面已经介绍过了,类似于facter。简单的说就是把minion端在启动的时候把自身的的各种属性信息采集汇报给master端,可以使用 salt ‘id’ grains.items查看。
# salt '*' grains.ls #可以查看有哪些属性可以查看,显示的是属性的名字,类似于os之类的。
#salt 'dasha_ceshi_172.16.5.239' grains.item os osrelease oscodename ##知道了属性的名称,我们就可以查看属性的值,这里就是查看os,osrelease,oscodename这三个属性的值,多属性用空格隔开。
# salt '*' grains.items #这种就是将所有minion端属性以及属性的值全打印出来,建议打印是指定某个minion id,否则打印的东西太多。
上面我们说了,在master上执行grains.items能查看到很多minion的参数,但是比如设备的具体位置,业务名称等信息就显的力不从心了,但是有了minion自定义grains后,就没有那么难了。
minion端的操作:
grains: #以grains开头 roles: #设置一个属性叫roles,下面如果多条就像下面一样- value值,这里的意思是标注服务器属于什么业务 - webserver - memcache deployment: bj-zb-5F #这里是标注所在机房的位置 cabinet: B11 #标注所在机柜的位置 cab_u: 19-21 #标注所在机柜的U位
# systemctl restart salt-minion #上面已经说了,grains信息是在minion端启动的时候才会发送,所以要重启minion端。
master端的查看:
# salt 'dasha_ceshi_172.16.5.240' grains.ls #用这个查看会发现我们自定义的哪几个grains的属性已经出现了。
#salt '*' grains.item roles deployment cabinet cab_u #查看我们在minion自定义的grains信息。
#salt 'dasha_ceshi_172.16.5.239' grains.append purpose 'ceshi' #通过grains.append方法为dasha_ceshi_172.16.5.239机器添加了一个属性,purpose 用途,后面跟的值是ceshi,注意空格和引号。
这种自定义的方法配置文件位置再minion的/etc/salt/grains配置文件中,永久生效,删除的话,可以直接去minion操作。还可以使用其他的方法,如grains.setvals来定义多个属性,或者还可以删除自定义的grains。这都是立马生效并永久生效的。
Pillar是saltstack组件中非常重要的一个,是数据管理中心,经常配合states在大规模的配置管理工作中使用它,它的主要作用是存储和定义配置管理中需要的一些数据。它的定义存储格式跟grains类似,都是YAML格式。
下面的操作都是在master端的操作:
# mkdir /srv/pillar #这是master配置文件里面#pillar_roots:默认指定的路径。默认不存在需要手工创建。 # cat /srv/pillar/top.sls #top.sls是配置管理的入口文件,一切都是从这里开始,这里是默认位置,在这里定义谁来执行那个方法或者说模块。 base: #top.sls 默认从 base 标签开始解析执行,下一级是操作的目标,可以通过正则,grain模块,或分组名,来进行匹配,再下一级是要执行的state文件,不包换扩展名。 '*': - pkgs # cat /srv/pillar/pkgs.sls #一个简单的根据minion端的grains信息,动态的设置apache软件包对应的name名称。前面我们学习saltstack的minion,我们知道给客户端定义新的属性时候,是需要在客户端文件加内容的,但是pillar则是在服务器给客户端定义新属性,而且不用重启服务, pkgs: {% if grains['os_family'] == 'RedHat' %} apache: httpd {% elif grains['os_family'] == 'Debian' %} apache: apache2 {% elif grains['os'] == 'Arch' %} apache: apache {% endif %} # salt '*' pillar.item pkgs
有结果来看,pillar数据是在Salt master上生成的并被安全地分布到minions上。Salt当定义pillar的时候,不必限制在sls文件,也可以从外部资源获得数据,我们可以把Pillar数据。pillar中最强大的抽象之一就是将states参数化的能力。
States是SaltStack中的配置语言,在日常进行配置管理时需要编写大量的States文件。如安装软件啊,更改配置啊等,就需要编写states sls文件(描述状态配置的文件)去描述和实现这些功能。编写states sls文件一般是是YAML语法格式,也支持使用Python语言来编写。
#salt 'dasha_ceshi_172.16.5.239' sys.list_state_modules ##查看minion支持的所有states列表。
1 - acl 2 - alias 3 - alternatives 4 - archive 5 - artifactory 6 - beacon 7 - bigip 8 - blockdev 9 - buildout 10 - ceph 11 - chronos_job 12 - cloud 13 - cmd 14 - composer 15 - cron 16 - cryptdev 17 - csf 18 - disk 19 - elasticsearch 20 - elasticsearch_index 21 - elasticsearch_index_template 22 - environ 23 - esxdatacenter 24 - etcd 25 - ethtool 26 - event 27 - file 28 - firewall 29 - firewalld 30 - gem 31 - glassfish 32 - gnomedesktop 33 - gpg 34 - grafana4_dashboard 35 - grafana4_datasource 36 - grafana4_org 37 - grafana4_user 38 - grains 39 - group 40 - highstate_doc 41 - hipchat 42 - host 43 - http 44 - incron 45 - infoblox_a 46 - infoblox_cname 47 - infoblox_host_record 48 - infoblox_range 49 - ini 50 - ipset 51 - iptables 52 - jboss7 53 - jenkins 54 - junos 55 - k8s 56 - kernelpkg 57 - keyboard 58 - kmod 59 - ldap 60 - libcloud_dns 61 - libcloud_loadbalancer 62 - libcloud_storage 63 - locale 64 - logrotate 65 - loop 66 - lxc 67 - marathon_app 68 - modjk 69 - modjk_worker 70 - module 71 - mount 72 - msteams 73 - network 74 - nexus 75 - openstack_config 76 - opsgenie 77 - pagerduty 78 - pagerduty_escalation_policy 79 - pagerduty_schedule 80 - pagerduty_service 81 - pagerduty_user 82 - pkg 83 - pkgbuild 84 - pkgng 85 - pkgrepo 86 - powerpath 87 - process 88 - pushover 89 - pyenv 90 - rbenv 91 - rvm 92 - salt 93 - salt_proxy 94 - schedule 95 - serverdensity_device 96 - service 97 - slack 98 - smtp 99 - solrcloud 100 - sqlite3 101 - ssh_auth 102 - ssh_known_hosts 103 - stateconf 104 - status 105 - statuspage 106 - supervisord 107 - sysctl 108 - syslog_ng 109 - telemetry_alert 110 - test 111 - timezone 112 - tuned 113 - uptime 114 - user 115 - vault 116 - vbox_guest 117 - virtualenv 118 - winrepo 119 - zenoss
#salt 'dasha_ceshi_172.16.5.239' sys.list_state_functions file host ##查看file和host的所有function,多模块用空格隔开
1 dasha_ceshi_172.16.5.239: 2 - file.absent 3 - file.accumulated 4 - file.append 5 - file.blockreplace 6 - file.cached 7 - file.comment 8 - file.copy 9 - file.decode 10 - file.directory 11 - file.exists 12 - file.line 13 - file.managed 14 - file.missing 15 - file.mknod 16 - file.mod_run_check_cmd 17 - file.not_cached 18 - file.patch 19 - file.prepend 20 - file.recurse 21 - file.rename 22 - file.replace 23 - file.retention_schedule 24 - file.sdecode 25 - file.serialize 26 - file.shortcut 27 - file.symlink 28 - file.touch 29 - file.uncomment 30 - host.absent 31 - host.only 32 - host.present
# salt 'agent1.salt' sys.list_state_modules #查看minion支持的所有states列表。
# salt 'agent1.salt' sys.list_state_functions file host #查看file和host的所有function,多模块用空格隔开
# salt 'agent1.salt' sys.state_doc file #查看指定模块的function的用法与例子,日常编写states按照例子编写便可。
# salt 'agent1.salt' sys.state_doc file.managed #查看file.managed的详细用法与例子,这也是我们经常用到的function。
现在我们有个需求,往minion的特定目录下传一个配置文件,前面我们说过使用cp.get_file方法就可以传文件,但是我们经常要给某些minion传特定的配置文件的话,使用state的文件传送就很方便。
首先我们先来看一下master里面state路径定义的方法,我们一共定义了三个路径,base是必须要有的,剩下的随意,注意空格。注意:salt://这几个字符分别代表了里面的三个路径,比如salt://file/test,绝对路径就是/srv/salt/base/file/test,/srv/salt/prod/file/test,/srv/salt/test/file/test。
分别创建配置文件里面的三个路径,最后完成后一定要重启master服务。
现在我们来看看写法,首先你要定义个需要传送到客户端的文件,可以新建,随便写点内容即可,首先我们分析一下基本环境,只需要看你标红位置即可。
我在base里面又新建了一个目录files,我把my.cnf配置文件放在了这里面,然后我在base下面新建了衣蛾cp_file.sls文件,在这个文件中写了点传送文件的内容。
基本写法介绍:
cp-file-my.cnf: #唯一表示ID file.managed: #方法,我用哪个方法,这里用file.managed方法传送文件 - name: /root/my.cnf #目标机器上的哪个文件,一定要加文件名。 - source: salt://files/my.cnf #master端的路径,上线我们说过,这里的绝对路径是/srv/salt/base/files/my.cnf - user: root #文件属主 - group: root #文件属组 - mode: 644 #文件权限 注意:salt所有配置文件里面禁止用tab键,层级关系用两个空格隔开,-符号后面还有个空格,例如- name: 冒号后面也得有空格。
写好具体要做什么以后,这里要发送了
#state.sls是用state.sls这个方法,cp_file是只cp_file.sls这个文件,这里去掉文件.后面的内容即可,test=True指先测试一下,如果确定要发送的话,去掉test=True即可。 salt '*' state.sls cp_file test=True
这里可能有同学要说了,好麻烦啊,我直接scp过去就ok了,你这里还得写这么东东西,别着急,如果有1000台机器,你也一个一个scp么,而这里我只需要匹配哪些服务器需要即可。
#如果你源文件没有发生改变,再次执行的话,Comment会提示你这个文件是正确的。Changes:下面没内容。Succeeded: 1,这就是区别,也就是不更新
SLS(代表SaLt State文件)是Salt State系统的核心。SLS描述了系统的目标状态,由格式简单的数据构成。这经常被称作配置管理,简单的讲就说你写了那么多的路径和sls文件,到底要让谁来执行top里面可以写谁来执行哪些sls文件。
因为我们用YAML格式来编写sls文件,所以掌握编写技巧利于后面少出错。
5.1.1 什么是YAML?
YAML 语言(发音 /ˈjæməl/ )的设计目标,就是方便人类读写。它实质上是一种通用的数据串行化格式。语法很简单,结构通过空格来展示,项目使用“-”来代表,键值对使用“:”分隔。
它的基本语法规则如下:
大小写敏感,以“:”来分隔key和value。对象:键值对的集合,又称为映射(mapping)/ 哈希(hashes) / 字典(dictionary)。
使用固定的缩进风格表示层级关系。缩进时不允许使用Tab键,只允许使用空格,一般每个缩进级别由两个空格组成。
# 表示注释,从这个字符一直到行尾,都会被解析器忽略。
想要表示列表项,使用一个短横杠加一个空格。多个项目使用同样的缩进级别作为同一列表的一部分。列表可以作为一个键值对的value。
top.sls是配置管理的入口文件,这个很重要在生产中很重要,默认存放在/srv/salt/目录.默认从base标签开始解析执行,下一级是操作的目标也就是要对哪些主机进行操作,可以通过正则、grain模块或分组名等来进行匹配,然后再下一级是要执行的state文件(不包含.sls扩展名)。
基本写法1:
首先top文件必须写在base环境下,必须要叫top.sls,然后我们看一下基本写法:
base: #下面的sls在哪个路径这里就写什么 'dasha_ceshi_172.16.5.239' #哪个minion去执行 - cp_file #执行哪个方法
基本写法2:
base: 'dasha_ceshi_172.16.5.239' - cp_file 'dasha_ceshi_172.16.5.240' - cp_file
正则写法1:
base: #下面的sls在哪个路径这里就写什么 'dasha_ceshi*' #哪个minion去执行,不会正则的同学可以去看看 - cp_file #执行哪个方法
# cat /srv/salt/base/top.sls
base:
centosgroups: #这里就是我们上面在master配置文件里面定义的那个组名
- match: nodegroup #这句话是必须要有的,指定以组匹配
- cp_file
# cat /srv/salt/base/top.sls #同上-match: grain也是必须要带的,指定让其按照grain进行匹配,指定让os是Centos的操作系统来执行。
base:
'os:CentOS':
- match: grain
- cp_file
# cat /srv/salt/base/top.sls #上面的grain模块匹配可能满足不了我们的匹配条件,我想要更加精确的让所有Centos6.4的操作系统去执行,就是我下面的设置。
base:
'G@os:CentOS and G@osrelease:6.4':
- match: compound
- cp_file
# cat /srv/salt/base/top.sls
base:
'192.168.1.0/24':
- match: ipcidr
- cp_file
# salt '*' state.highstate #master将会指导所有的目标minions运行 state.highstate。当minion执行highstate,它将会下载top文件中匹配的内容,minion将表达式中匹配的内容下载、编译、执行。一旦完成,minion将返回所有的动作执行结果和所有更改。基本意思就是谁来执行什么操作,去看top文件里面是怎么写的,就怎么执行。
# salt '*' state.highstate test=True #只是测试执行,类似于模拟,不会在minion真正执行,便于我们编写测试时使用,建议每次执行都测试一下。
5.5 state的层级关系
include:将别的SLS添加到当前文件中,所以可以require或watch被引用的SLS中定义的内容,还可以extend覆盖其内容。include语句使得state可以跨文件引用。使用include相当于把被引用的内容文件添加到自身。
extend:扩展被引用的SLS数据。不需要重头写新的SLS,可以先直接include sls文件,然后在其基础上增加或者覆盖内容。
首先说应用场景,现在我在prod下面新建了三个目录web,php,mysql,里面分别写了init.sls(初始化环境配置),按照上面的写法,我需要一键执行的话,首先需要在top里面把它们加进去,如下图
top.sls
这样的话,如果我要安装的环境特别的多,这里都直接下载top里面就比较乱了,所以为了醒目,我在prod下直接新建一个lamp.sls文件,然后把这些操作文件都写进去,然后就方便了,然后只需要在top文件里面写上lamp就oK了,是不是很方便。
这里只会一种用法,生产中还有很多种用法。
环境需求,如果已经写好了lamp的安装配置环境了,然后突然发现还有安装一个软件,这个时候直接去改文件就显的有点粗暴了,这里可以直接在include的里面写,例如,这里我需要给lamp环境下安装一个tree的包。
其它的什么都不需要动,只需要在lamp下添加extend即可。
这里注意,既然是扩展,那就得知道给谁扩展,include的中我们已经标注了要执行的操作是web,php,mysql下的init操作。但是扩展的还怎么写呢?extend:是标准写法,层级关系是两个空格,那这个id怎么写呢?有人说随便写,你写个试试,肯定不行。既然是扩展你得指定给谁扩展。我在php里面的init文件中写过php-install这个id,这里我指定是给它扩展,所以必须得把它的id写在这里,然后再写是什么方法,要干什么。这里需要注意的就是这个id写法,其实也不难理解,既然是扩展,肯定是要写给谁扩展的,否则不是乱套了。
match : 配模某个模块,比如 match: grain match: nodegroup
require: 依赖某个state,在运行此state前,先运行依赖的state,依赖可以有多个,被谁依赖是require_in
watch : 在某个state变化时运行此模块,watch除具备require功能外,还增了关注状态的功能,被谁依赖是watch_in。
order : 优先级比require和watch低,有order指定的state比没有order指定的优先级高,假如一个state模块内安装多个服务,或者其他依赖关系,可以使用
require和require_in示例:
应用场景,首先我们是确定哪些操作都做了以后才能执行此操作,比如所有的安装操作都完成,最后要重启一些服务,就可以使用此参数
如下,如果file这个模块下的id是apache-config这个操作成功的话,就执行id是apache-service操作,如果有enable就是重启,如果有reload的参数就是重载配置。
require:
require_in:
写法如下,可以理解为被谁依赖,如下,如果我这个文件操作成功的话就执行service这个模块的id是apache-service的操作。
watch和watch_in示例:
这个就NB了,它具备require的特性。应用场景,如果我们服务都安装完了,这个时候我需要给所有的minion修改一下配置文件,修改完成后重新加载配置文件,用watch就可以解决,用法和require一模一样。
如果file这个模块下的id是apache-config这个操作成功(首先是从source这个路径传送到minino端的name路径下后,重新加载httpd这个服务)。watch_in用法刚好相反,类似于require_in0。
6.1、介绍
Jinja2 是一个现代的,设计者友好的,仿照 Django 模板的 Python 模板语言。 它速度快,被广泛使用,并且提供了可选的沙箱模板执行环境保证安全:
参考地址:http://docs.jinkan.org/docs/jinja2/
Jinja的使用分为三个步骤:
File状态使用template参数 - template: jinja。
模板文件里面变量使用{{名称}},比如{{PORT}}.
File状态模块里面指定变量列表。
6.2、jinji的基本使用
环境介绍,为了区分,我在master配置文件中新加一个/srv/salt/jiaja2的模块。
基本写法
{% set iplist= grains['ipv4'] %} #申明变量名称 /files/minion.conf: #定义传输文件id file.managed: #执行方法 - name: /root/minion.conf #目的路径 - source: salt://files/minion.conf.jinja #文件存放位置 - template: jinja #申请只用jinja模板 - defaults: #定义默认将值传递给模板 IP_ADDR: {{iplist[1]}} #获取iplist这个变量的值,因为返回的是一个列表,所以我们需要取第2个值。
cat files/minion.conf.jinja 这里为了明显,我只写了一个值,
ipaddr:{{IP_ADDR}}
minion效果
总结,这就很厉害了,比如我定义安装minion客户端的某个服务要根据写入自己的ip地址或者固定端口,就可以在这里定义多个变量defaults下面新加就行。它不但可以写变量还支持条件判断和循环。
6.3、逻辑判断
Jinja还主要用来给状态增加逻辑关系,如for循环,或者if判断,也是经常使用到的。
salt,grains,pillar是salt中jinja里面的三个特殊字典,salt是包含所有salt函数对象的字典,grains是包含minion上grains的字典,pillar是包含minion上pillar的字典。上面已经介绍了如何使用了。
if...elif...endif的示例:
# cat /srv/pillar/pkgs.sls
apache: pkg.installed: #这是根据系统的不同,判断安装的软件名称。如果有变量就放到{{}}中 {% if grains['os_family'] == 'RedHat' %} #jinja中判断,循环等标签是放在{% %}中 - name: httpd {% elif grains['os_family'] == 'Debian' %} - name: apache2 {% elif grains['os'] == 'Arch' %} - name: apache {% endif %} #也会有结束标签{% end** %}
#当然还支持:{% if %}...{% elif %}...{% else %}...{% endif %}之类的写法。
for循环的示例:
{% set userlist = ['yunwei','cacti','www'] %} {% for user in userlist %} {{ user }}: user.present: - shell: /bin/bash - home: /home/{{ user }} {% endfor %}
参考地址:http://www.51niux.com/?id=117