<服务>saltstack更多用法
目录:
对象管理
代号 | 含义 | 示例 | |
---|---|---|---|
G | Grains glob匹配 | G@os:CentOS | |
E | PCRE minion id匹配(正则匹配) | E@salt[1-3] | |
P | Grains PCRE匹配 | `P@os:(RedHat | CentOS)` |
L | minios列表 | L@why-1.whysdomain.com,why-2.whysdomain.com | |
I | Pillor glob匹配 | I@createdata:20170426 | |
S | IP或者网段匹配 | S@192.168.0.0/24 or 192.168.1.133 | |
R | Range cluster匹配 | R@%foo.bar | |
D | Minion Data匹配 | D@key:value | |
N | 通过group来进行匹配 | N@whysdomain.com | |
C | 通过条件来进行匹配 | C 'G@os:CentOS or L@salt02' |
关于通过条件进行匹配的示例代码
[root@salt-master-00 ~]# salt -C "E@tengine-ads-A-* or E@ads-ads-api-0(2|5)" cmd.run "grep '30/Aug/2017:06:46' /home/ec2-user/logs/nginx/api.chuchujie.com.access.log | awk -F '\x01' '{if(\$6>400){print \$0}}'"
首先要讲一下这个匹配规整的生效,命令在master端接收后通过zeroMQ发送到所有的minion主机,而在minion端进行匹配本机的id是否在此次命令的执行范围内,如果在执行范围内就进行执行并返回结果,如果没有在执行范围内,就不进行任何操作,也不会返回任何结果。
默认匹配规则
最简单的就是*来匹配所有的主机,例如salt0[2-3]或salt0[2,3]来匹配salt02和salt03,但是与正则的规则不同,就类似grep和egrep的区别
正则匹配
正则匹配通过匹配minion id的方式进行管理
salt -E 'sal(02|03)' test.ping
如果是写入到sls文件中
base:
'sal(02|03)'
- match: pcre
- packages等等自定义的模块
列表匹配
通过列表方式指定minion id
salt -L salt02,salt03 test.ping
Grains匹配
salt -G 'os:RedHat' test.ping
自带的Grains
查看grains列表
[root@salt01 ~]# salt '*' grains.ls
salt03:
- SSDs
- biosreleasedate
- biosversion
- cpu_flags
- cpu_model
- cpuarch
- domain
- fqdn
- fqdn_ip4
- fqdn_ip6
- gpus
- host
- hwaddr_interfaces
- id
- init
- ip4_interfaces
- ip6_interfaces
- ip_interfaces
- ipv4
- ipv6
- kernel
- kernelrelease
- locale_info
- localhost
- machine_id
- manufacturer
- master
- mdadm
- mem_total
- nodename
- num_cpus
- num_gpus
- os
- os_family
- osarch
- oscodename
- osfinger
- osfullname
- osmajorrelease
- osrelease
- osrelease_info
- path
- productname
- ps
- pythonexecutable
- pythonpath
- pythonversion
- saltpath
- saltversion
- saltversioninfo
- selinux
- serialnumber
- server_id
- shell
- virtual
- zmqversion
查看每一项的详细信息
[root@salt01 ~]# salt '*' grains.items
查看os项的详细信息
[root@salt01 ~]# salt '*' grains.item os
salt02:
----------
os:
RedHat
salt03:
----------
os:
RedHat
[root@salt01 ~]# salt -G 'os:RedHat' grains.item cpuarch
salt02:
----------
cpuarch:
x86_64
salt03:
----------
cpuarch:
x86_64
自定义grains
[root@salt02 ~]# vi /etc/salt/minion
#grains:
# roles: #属性
# - webserver #值(列表形式)
# - memcache
# deployment: datacenter4 #属性: 值
# cabinet: 13
# cab_u: 14-15
简单添加
grains:
test: why
重启服务生效
[root@salt02 ~]# /etc/init.d/salt-minion restart
Stopping salt-minion daemon: [ OK ]
Starting salt-minion daemon: [ OK ]
[root@salt01 ~]# salt -G 'os:RedHat' grains.item test
salt02:
----------
test:
why
salt03:
----------
test:
如果是想获取字典的就需要
[root@salt01 ~]# salt '*' grains.item hwaddr_interfaces
salt02:
----------
hwaddr_interfaces:
----------
eth0:
00:0c:29:ac:a6:7c
lo:
00:00:00:00:00:00
salt03:
----------
hwaddr_interfaces:
----------
eth0:
00:0c:29:07:d4:cd
lo:
00:00:00:00:00:00
[root@salt01 ~]# salt '*' grains.item hwaddr_interfaces:eth0
salt02:
----------
hwaddr_interfaces:eth0:
00:0c:29:ac:a6:7c
salt03:
----------
hwaddr_interfaces:eth0:
00:0c:29:07:d4:cd
组匹配
salt -N test test.ping
组需要在master端定义,组内也可以通过其他匹配方式构成组,当然也可以把两个甚至更多的组组成一个组
[root@salt01 ~]# vi /etc/salt/master
#nodegroups:
# group1: 'L@foo.domain.com,bar.domain.com,baz.domain.com and bl*.domain.com'
# group2: 'G@os:Debian and foo.domain.com'
nodegroups:
test: 'E@salt*'
[root@salt01 ~]# salt -N test test.ping
salt03:
True
salt02:
True
更多的组配置方式,未完待续
复合匹配
salt -C 'G@os:CentOS and L@salt02,salt03'
如果是写入sls文件
base:
'G@os:CentOS and L@salt02,salt03'
- match: compound
- webserver
Pillar值匹配
通过master端定义minion的数据,pillar在解析完成后,是一个嵌套的dict结构,最上层的key是minion ID,其value是该minion所拥有的所有数据,每一个value也是以key/value的形式存在,piller数据与特定的minion关联,每一个minion只能看到自己的数据,可以用来传递敏感数据
可以用于敏感数据,例如ssh key,加密证书等,由于pillar使用独立加密的session,可以确保敏感数据不被其他minion看到 变量,可以在pillar中处理平台的差异性,比如针对不同的操作系统设置不同的软件包的名字,在state中引用 任何数据,可以定义用户和UID的对应关系,minion的角色等
未完待续
CIDR匹配
模块
常用模块
- test
- service
- cmd
- saltutil
- file
- pkg
salt '*' pkg.install httpd
安装软件包salt '*' cp.getfile salt://httpd.conf /etc/httpd/conf/httpd.conf
分发文件 当然,如果是拷贝master所在文件系统的文件,可以使用salt-cp '*' /usr/local/apache/conf/httpd.conf /etc/httpd/conf/httpd.conf
salt '*' service.start httpd
启动服务
文件系统
[root@salt01 ~]# vi /etc/salt/master
# Example:
# file_roots:
# base: #基础
# - /srv/salt/
# dev: #开发
# - /srv/salt/dev/services
# - /srv/salt/dev/states
# prod: #生产
# - /srv/salt/prod/services
# - /srv/salt/prod/states
可以看到给我们提供的例子,我们在操作的过程中会在不同的仓库来获取一些文件,例如压缩包,配置文件等,可根据需要来设置多个。
取消注释
file_roots:
base:
- /srv/salt
生成目录
[root@salt01 ~]# mkdir /srv/salt
[root@salt01 ~]# cd !$
cd /srv/salt
[root@salt01 salt]# mkdir etc
[root@salt01 salt]# mkdir script
[root@salt01 salt]# cd script/
远程执行
创建测试脚本
[root@salt01 salt]# vi /srv/salt/script/test.sh
#!/bin/bash
while true
do
sleep 1
echo 1 >> /tmp/log
done
一个死循环脚本,这样可以看到这个脚本的情况
执行脚本
[root@salt01 script]# salt -N test cmd.script salt://script/test.sh
可以看都master端是启动一个python执行刚才输入的命令
[root@salt01 ~]# ps -ef | grep cmd.script
root 7920 6321 2 01:08 pts/3 00:00:06 /usr/bin/python2.6 /usr/bin/salt -N test cmd.script salt://script/test.sh
root 8058 6818 0 01:12 pts/4 00:00:00 grep --color cmd.script
而minion端会在tmp目录下生成一个随机名字的脚本
[root@salt02 ~]# ps -ef | grep /bin/bash
root 4513 4510 0 01:09 ? 00:00:00 /bin/bash /tmp/tmpuDpb5k.sh
root 4749 3926 0 01:11 pts/1 00:00:00 grep --color /bin/bash
配置管理
[root@salt01 salt]# vi hosts.sls
[root@salt01 salt]# cat hosts.sls
/tmp/hosts:
file.managed:
- source: salt://etc/hosts
- user: root
- group: root
- mode: 600
第一行,为name,可以随便定义,就是这个文件需要同步的绝对路径,如果在第一行没有定义name,需要在下边file.manager中添加- name: /tmp/hosts
,这个只是做个示范
第二行,file.managed:代表使用file模块的managed方法来管理这个文件
第三行,- source: salt://etc/hosts
代表源文件的地址,后面分别是用户,组和权限
[root@salt01 salt]# vi top.sls
[root@salt01 salt]# cat top.sls
base:
'*':
- hosts
第一行,base:
对应使用file_roots配置的仓库,base对应的即为/srv/salt
第二行,'*'
匹配的minion
第三行,- hosts
对应使用的sls文件,此处代指hosts.sls
拷贝需要同步的配置文件到仓库中
[root@salt01 salt]# cp /etc/hosts /srv/salt/etc/
执行命令
[root@salt01 salt]# salt '*' state.highstate
salt02:
----------
ID: /tmp/hosts
Function: file.managed
Result: True
Comment: File /tmp/hosts updated
Started: 23:35:41.932641
Duration: 342.232 ms
Changes:
----------
diff:
New file
Summary
------------
Succeeded: 1 (changed=1)
Failed: 0
------------
Total states run: 1
salt03:
----------
ID: /tmp/hosts #name名字
Function: file.managed #使用的函数
Result: True
Comment: File /tmp/hosts updated
Started: 23:35:41.939952
Duration: 370.099 ms
Changes:
----------
diff: #会做文件比对,文件修改了什么,但是此次是一个新文件
New file
Summary
------------
Succeeded: 1 (changed=1) #因为命令是直接执行top.sls中的所有,会返回成功了多少
Failed: 0
------------
Total states run: 1
[root@salt01 salt]# cat /srv/salt/etc/hosts
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
[root@salt02 ~]# cat /tmp/hosts
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
如果是调试可以加test=True
salt '*' state.highstate test=True
修改此文件
[root@salt01 salt]# echo '192.168.0.191 salt01' >> /srv/salt/etc/hosts
[root@salt01 salt]# salt '*' state.sls hosts #state.sls是在salt文件系统的根目录进行查找,hosts会自动补全为hosts.sls
salt03:
----------
ID: /tmp/hosts
Function: file.managed
Result: True
Comment: File /tmp/hosts updated
Started: 23:42:57.820794
Duration: 942.963 ms
Changes:
----------
diff:
---
+++
@@ -1,2 +1,3 @@
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
+192.168.0.191 salt01
Summary
------------
Succeeded: 1 (changed=1)
Failed: 0
------------
Total states run: 1
salt02:
----------
ID: /tmp/hosts
Function: file.managed
Result: True
Comment: File /tmp/hosts updated
Started: 23:42:58.065344
Duration: 1171.583 ms
Changes:
----------
diff:
---
+++
@@ -1,2 +1,3 @@
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
+192.168.0.191 salt01
Summary
------------
Succeeded: 1 (changed=1)
Failed: 0
------------
Total states run: 1
如果在目录结构中,可以通过以下方式执行
[root@salt01 salt]# echo '192.168.0.192 salt02' >> /srv/salt/etc/hosts
[root@salt01 salt]# mkdir /srv/salt/hosts
[root@salt01 salt]# mv /srv/salt/hosts.sls /srv/salt/hosts
[root@salt01 salt]# salt '*' state.sls hosts.hosts
还有这个目录下的sls文件会有一个入口文件的,为init.sls
[root@salt01 salt]# mv /srv/salt/hosts/hosts.sls /srv/salt/hosts/init.sls
[root@salt01 salt]# salt '*' state.sls hosts
默认是先查找hosts.init.sls,如果没有,就会查找hosts.sls,如果两个都不存在就会报错
Batch Size
salt支持指定执行命令的主机数量,可以按照百分比或者直接指定固定数量,通过-b(--batch-size)参数实现,原理是batch size会维护一个运行的minions数量的窗口,第一次指定数量的minion运行,一旦有一个minion执行完成,会立刻新增一个minion进行执行。
salt '*' -b 10 test.ping 或者 salt '*' -b 20% service.restart apache
salt语法
YAML
state状态的核心为sls,语法为YAML
YAML语法使用固定的缩进风格表示数据层结构关系,salt需要的每个缩进级别由两个空格组成,字典的话以冒号为结尾的字符串,每个value在冒号后用空格隔开,列表项则为一个短横杠进和一个空格,多个项用相同的缩进级别作为同一列表的一个部分。更多的内容可以参考http://docs.saltstack.cn/topics/yaml/index.html
模块用法 https://docs.saltstack.com/en/latest/ref/states/all/index.html
https://docs.saltstack.com/en/latest/ref/states/all/salt.states.file.html#module-salt.states.file
通过python进行演示
[root@salt01 ~]# vi test.yaml
[root@salt01 ~]# cat test.yaml
why:
- name: why
- age: 24
mb:
- name: mabiao
- age: 26
[root@salt01 ~]# vi testyaml.py
[root@salt01 ~]# cat testyaml.py
#!/usr/bin/env python
import yaml
import sys
fd = open(sys.argv[1])
print yaml.load(fd)
[root@salt01 ~]# chmod +x testyaml.py
[root@salt01 ~]# ./testyaml.py test.yaml
{'why': [{'name': 'why'}, {'age': 24}], 'mb': [{'name': 'mabiao'}, {'age': 26}]}
这样yaml就被解析为python的字典了
官方示例
/etc/http/conf/http.conf:
file.managed:
- source: salt://apache/http.conf
- user: root
- group: root
- mode: 644
- template: jinja
- defaults:
custom_var: "default value"
other_var: 123
{% if grains['os'] == 'Ubuntu' %}
- context:
custom_var: "override"
{% endif %}
根据系统进行匹配
jinja2
salt默认使用jinja2模板系统生成yaml
- 变量: {{foo}},变量的属性可以通过{{foo.bar}}或者{{foo['bar']}}
- 注释: {# comment #}
- for:
{% for eachitem in items %}
{{eachitem}}
{% endfor %}
- if:
{% if GFW %}
Welcome to China!
{% elif not Internet %}
Welcome to North Korea!
{% else %}
Freedon!
{% endif %}
requisites
- require:本state执行时需要先执行哪些state,用于前置条件,例如同步配置文件前需要安装软件包
- require_in:与require位置相反
- watch:除了require之外,也会对监控依赖的state的状态,如果状态发生改变,做出反应,例如配置文件变更,重启服务或者reload
- watch_in:与watch位置相反
- prereq:通过test=True接口检查依赖状态
- prereq_in:与prereq位置相反
可用的模块
注意,以下模块与远程执行模块同名,但不一样
软件包状态模块
https://docs.saltstack.com/en/latest/ref/states/all/salt.states.pkg.html
- pkg.installed 确保软件包安装,如果没有安装则进行安装
- pkg.latest 确保软件包是最新版本,如果不是最新版本,进行升级
- pkg.remove 确保软件包已卸载,如果之前已安装则进行卸载
- pkg.purge 除了remove还会删除配置文件
文件状态模块
https://docs.saltstack.com/en/latest/ref/states/all/salt.states.file.html
- file.managed 确保文件存在且为对应状态
- file.recurse 确保目录存在且为对应状态
- file.absent 确保文件不存在,如果存在则删除
服务状态模块
https://docs.saltstack.com/en/latest/ref/states/all/salt.states.service.html
- service.running 确保服务处于运行状态,如果没有运行则进行启动
- service.enabled 确保服务会开机启动
- service.disabled 确保服务不会开机启动
- service.dead 确保服务当前没有运行
saltstack安装nginx
[root@salt01 ~]# cd /srv/salt/
[root@salt01 salt]# mkdir nginx
[root@salt01 salt]# cd nginx
[root@salt01 nginx]# vi nginx.sls
nginx:
pkg: #pkg模块
- installed #installed方法
service: #service模块
- running #启动状态
- enable: True #是否允许进行相应的操作,例如restart,reload
- reload: True #允许进行reload
- watch: #reload的触发条件,触发条件执行reload
- pkg: nginx #监控的服务
- file: /etc/nginx/nginx.conf #监控的变动的文件,对应下方的/etc/nginx/nginx.conf
- file: /etc/nginx/conf.d/default.conf #监控的变动的文件,对应下边的/etc/nginx/conf.d/default.conf,也可以进行自定义,就是需要配置的过程中添加- name
/etc/nginx/nginx.conf:
file.managed:
- source: salt://etc/nginx/nginx.conf
- user: root
- group: root
- mode: 644
- request:
- pkg: nginx
/etc/nginx/conf.d/default.conf:
file.managed:
- source: salt://etc/nginx/conf.d/default.conf
- user: root
- group: root
- mode: 644
- request:
- pkg: nginx
当然也可以有另一种写法,例如
serivce.running:
- enable: True
而不写
service:
- running
- enable: True
还有就是request和request_in的用法,如果这个文件需要用require_in来写
nginx:
pkg:
- installed
- require_in:
- file: /etc/nginx/nginx.conf
- file: /etc/nginx/conf.d/default.conf
service:
- running
- enable: True
- reload: True
- watch:
- pkg: nginx
- file: /etc/nginx/nginx.conf
- file: /etc/nginx/conf.d/default.conf
/etc/nginx/nginx.conf:
file.managed:
- source: salt://etc/nginx/nginx.conf
- user: root
- group: root
- mode: 644
/etc/nginx/conf.d/default.conf:
file.managed:
- source: salt://etc/nginx/conf.d/default.conf
- user: root
- group: root
- mode: 644
获取nginx配置文件
[root@salt01 nginx]# yum install -y nginx
[root@salt01 nginx]# cp /etc/nginx/nginx.conf /srv/salt/etc/nginx/
[root@salt01 nginx]# cp /etc/nginx/conf.d/default.conf /srv/salt/etc/nginx/conf.d/
远程执行
[root@salt01 nginx]# salt '*' state.sls nginx.nginx
可以看到两台minion的80端口都已经打开
[root@salt01 nginx]# salt '*' cmd.run 'ss -nlt|grep 80'
salt02:
LISTEN 0 128 :::80 :::*
LISTEN 0 128 *:80 *:*
salt03:
LISTEN 0 128 :::80 :::*
LISTEN 0 128 *:80 *:*
修改配置文件
listen 80 default_server;
改为
listen 8080 default_server;
通过minion端执行命令
[root@salt02 ~]# salt-call state.sls nginx.nginx
[INFO ] Loading fresh modules for state activity
[INFO ] Fetching file from saltenv 'base', ** done ** 'nginx/nginx.sls'
[ERROR ] You should upgrade pyOpenSSL to at least 0.14.1 to enable the use of X509 extensions
[INFO ] Running state [nginx] at time 08:05:17.334971
[INFO ] Executing state pkg.installed for nginx
[INFO ] Executing command ['rpm', '-qa', '--queryformat', '%{NAME}_|-%{EPOCH}_|-%{VERSION}_|-%{RELEASE}_|-%{ARCH}_|-(none)\n'] in directory '/root'
[INFO ] Package nginx is already installed.
[INFO ] Completed state [nginx] at time 08:05:18.590533
[INFO ] Running state [/etc/nginx/nginx.conf] at time 08:05:18.610151
[INFO ] Executing state file.managed for /etc/nginx/nginx.conf
[INFO ] File /etc/nginx/nginx.conf is in the correct state
[INFO ] Completed state [/etc/nginx/nginx.conf] at time 08:05:18.633830
[INFO ] Running state [/etc/nginx/conf.d/default.conf] at time 08:05:18.636151
[INFO ] Executing state file.managed for /etc/nginx/conf.d/default.conf
[INFO ] Fetching file from saltenv 'base', ** done ** 'etc/nginx/conf.d/default.conf'
[INFO ] File changed:
---
+++
@@ -3,7 +3,7 @@
#
server {
- listen 80 default_server;
+ listen 8080 default_server;
listen [::]:80 default_server;
server_name _;
root /usr/share/nginx/html;
[INFO ] Completed state [/etc/nginx/conf.d/default.conf] at time 08:05:18.924077
[INFO ] Running state [nginx] at time 08:05:18.925517
[INFO ] Executing state service.running for nginx
[INFO ] Executing command '/sbin/service nginx status' in directory '/root'
[INFO ] Executing command '/sbin/chkconfig --list nginx' in directory '/root'
[INFO ] Executing command '/sbin/runlevel' in directory '/root'
[INFO ] Executing command '/sbin/runlevel' in directory '/root'
[INFO ] Executing command '/sbin/chkconfig --list nginx' in directory '/root'
[INFO ] Executing command '/sbin/chkconfig nginx on' in directory '/root'
[INFO ] Executing command '/sbin/chkconfig --list nginx' in directory '/root'
[INFO ] Executing command '/sbin/runlevel' in directory '/root'
[INFO ] {'nginx': True}
[INFO ] Completed state [nginx] at time 08:05:19.150004
local:
----------
ID: nginx
Function: pkg.installed
Result: True
Comment: Package nginx is already installed.
Started: 08:05:17.334971
Duration: 1255.562 ms
Changes:
----------
ID: /etc/nginx/nginx.conf
Function: file.managed
Result: True
Comment: File /etc/nginx/nginx.conf is in the correct state
Started: 08:05:18.610151
Duration: 28.544 ms
Changes:
----------
ID: /etc/nginx/conf.d/default.conf
Function: file.managed
Result: True
Comment: File /etc/nginx/conf.d/default.conf updated
Started: 08:05:18.636151
Duration: 261.897 ms
Changes:
----------
diff:
---
+++
@@ -3,7 +3,7 @@
#
server {
- listen 80 default_server;
+ listen 8080 default_server;
listen [::]:80 default_server;
server_name _;
root /usr/share/nginx/html;
----------
ID: nginx
Function: service.running
Result: True
Comment: Service reloaded
Started: 08:05:18.925517
Duration: 204.327 ms
Changes:
----------
nginx:
True
Summary
------------
Succeeded: 4 (changed=2)
Failed: 0
------------
Total states run: 4
在salt02节点上也可以看到端口变为8080
[root@salt02 ~]# ss -nlpt | grep 8080
LISTEN 0 128 *:8080 *:* users:(("nginx",23545,11),("nginx",25037,11))
Schedule
Schedule可以定时执行任务,可以在master,minion和pillar配置
schedule: #固定语法
job1: #名字
function: state.sls #模块.方法
seconds: 3600 #时间
args:
- httpd #传参
kwargs:
test: True #也可以传参以字典的形式
还有更多的splay,when等方式,都可以参考http://docs.saltstack.cn/topics/jobs/#scheduling-jobs
定义目录
pillar属于一个单独的模块,需要定义目录
[root@salt01 ~]# vi /etc/salt/master
#pillar_roots:
# base:
# - /srv/pillar
取消默认注释的即可
配置定时任务
[root@salt01 ~]# mkdir -p /srv/pillar
[root@salt01 ~]# cd /srv/pillar
[root@salt01 pillar]# vi top.sls
base:
'*':
- nginx
[root@salt01 pillar]# vi nginx.sls
schedule:
nginx:
function: state.sls
minutes: 1
args:
- 'nginx.nginx'
查看minion的pillar信息
[root@salt01 pillar]# salt '*' pillar.data
salt03:
----------
schedule:
----------
nginx:
----------
args:
- nginx.nginx
function:
state.sls
minutes:
1
salt02:
----------
schedule:
----------
nginx:
----------
args:
- nginx.nginx
function:
state.sls
minutes:
1
查看minion端是否生效
因为在上边修改salt base库中的配置文件中的端口为8080,salt02是通过salt-call进行配置同步的,这里salt03还有没有变更,看一下配置pillar后salt03的nginx的端口。
[root@salt03 ~]# ss -nlput | grep 8080
[root@salt03 ~]#
可以看到配置完pillar只是在master端生效。
刷新配置
[root@salt01 pillar]# salt '*' saltutil.refresh_pillar
salt02:
True
salt03:
True
再次验证
[root@salt03 ~]# ss -nlput | grep 8080
[root@salt03 ~]# ss -nlput | grep 8080
[root@salt03 ~]# ss -nlput | grep 8080
tcp LISTEN 0 128 *:8080 *:* users:(("nginx",23568,11),("nginx",37170,11))
如果出现不生效,可以修改一下salt仓库的配置文件
jinja模板管理配置文件
通过直接修改配置文件过于麻烦,可以通过jinja模板来实现通过在sls文件定义配置文件内容
修改被管理文件
[root@salt01 ~]# vi /srv/salt/etc/nginx/conf.d/default.conf
server {
listen 8080 default_server;
改为
server {
listen {{ port }} default_server;
模板添加映射
[root@salt01 ~]# vi /srv/salt/nginx.sls
nginx:
pkg:
- installed
service:
- running
- enable: True
- reload: True
- watch:
- pkg: nginx
- file: /etc/nginx/nginx.conf
- file: /etc/nginx/conf.d/default.conf
/etc/nginx/nginx.conf:
file.managed:
- source: salt://etc/nginx/nginx.conf
- user: root
- group: root
- mode: 644
/etc/nginx/conf.d/default.conf:
file.managed:
- source: salt://etc/nginx/conf.d/default.conf
- user: root
- group: root
- mode: 644
- template: jinja
- context:
port: 9090
指定了jinja的模板,然后给予了port对应的值9090
执行命令
[root@salt01 ~]# salt '*' state.sls nginx
ID: /etc/nginx/conf.d/default.conf
Function: file.managed
Result: True
Comment: File /etc/nginx/conf.d/default.conf updated
Started: 01:34:05.127787
Duration: 463.375 ms
Changes:
----------
diff:
---
+++
@@ -3,7 +3,7 @@
#
server {
- listen 8080 default_server;
+ listen 9090 default_server;
listen [::]:80 default_server;
server_name _;
root /usr/share/nginx/html;
可以在执行结果中看到配置文件的变更,minion在产生配置文件的时候已经进行了渲染,替换port为9090
minion端查询
[root@salt02 ~]# ss -nlpt | grep 9090
LISTEN 0 128 *:9090 *:* users:(("nginx",23545,10),("nginx",44932,10))
根据minion进行匹配
如果是需要根据minion进行匹配
更改模板映射(添加判断)
[root@salt01 ~]# vi /srv/salt/nginx.sls
template和context可以配置为
- template: jinja
- context:
{% if grains['id'] == 'salt02' %}
port: 9092
{% elif grains['id'] == 'salt03' %}
port: 9093
{% else %}
port: 9091
{% endif %}
执行命令
[root@salt01 ~]# salt '*' state.sls nginx
检查执行结果
[root@salt02 ~]# ss -nlpt | grep '\b90'
LISTEN 0 128 *:9092 *:* users:(("nginx",23545,11),("nginx",49584,11))
[root@salt03 ~]# ss -nlpt | grep '\b90'
LISTEN 0 128 *:9093 *:* users:(("nginx",23568,11),("nginx",49223,11))
通过pillar
[root@salt01 ~]# cd /srv/pillar/
[root@salt01 pillar]# mkdir nginx
[root@salt01 pillar]# cd nginx
[root@salt01 nginx]# vi init.sls
nginx:
{% if grains.id == 'salt02' %}
port: 9192
{% elif grains.id == 'salt03' %}
port: 9193
{% else %}
port: 9190
{% endif %}
[root@salt01 nginx]# cd ..
[root@salt01 pillar]# vi top.sls
base:
'*':
- nginx
刷新pillar并检验
[root@salt01 ~]# salt '*' saltutil.refresh_pillar
salt02:
True
salt03:
True
[root@salt04 ~]# salt '*' pillar.get nginx:port
salt02:
9192
salt03:
9193
修改sls文件
[root@salt04 ~]# vi /srv/salt/nginx.sls
- template: jinja
- context:
port: {{ salt['pillar.get']('nginx:port',80) }}
当然这样是一个负责的写法,即使在minion中没有pillar被定义nginx的key,也会使用默认的端口80
不负责任的写法就是
port: pillar['nginx']['port']
这个问题在于,如果minion中没有pillar被定义nginx的key,就会报错
检验
[root@salt04 ~]# salt '*' state.sls nginx
可以在minion上检查
[root@salt02 ~]# ss -nlpt | grep '\b91'
LISTEN 0 128 *:9192 *:* users:(("nginx",23545,11),("nginx",49584,11))
[root@salt03 ~]# ss -nlpt | grep '\b91'
LISTEN 0 128 *:9193 *:* users:(("nginx",23568,11),("nginx",49223,11))
如果是salt '' state.highstate nginx执行,可以不执行salt '' saltutil.refresh_pillar,因为在执行的过程会刷新pillar信息
官方还有更多的实例提供 https://github.com/saltstack-formulas
salt proxy
proxy是为了解决salt master处理时间过长的问题,采取通过在master端和minion端添加proxy代理层的方式实现,原理是master端发起命令后,将命令原封不动发送给proxy端,proyx接收命令后,对选定主机进行匹配,发送对应命令给minion端,minion端执行后将结果返回给proxy端,proxy端再返回给master端。
proxy上也有一个master,通过syndic接收由master进行执行
syndic接口允许建立salt命令拓扑,通过master连接到master上指挥minion。
IP | 主机名 | 作用 |
---|---|---|
192.168.0.191 | salt01 | salt-master |
192.168.0.192 | salt02 | salt-minion |
192.168.0.193 | salt03 | salt-minion |
192.168.0.194 | salt04 | salt-syndic |
192.168.0.195 | salt05 | salt-syndic |
清除缓存的key
[root@salt01 ~]# rm -rf /etc/salt/pki/
[root@salt01 ~]# salt-key -D -y
Deleting the following keys:
Accepted Keys:
salt02
salt03
Key for minion salt02 deleted.
Key for minion salt03 deleted.
删除pki目录
生产环境下建议改名
[root@salt02 ~]# rm -rf /etc/salt/pki/
[root@salt02 ~]# /etc/init.d/salt-minion restart
Stopping salt-minion daemon: [ OK ]
Starting salt-minion daemon: [ OK ]
[root@salt03 ~]# rm -rf /etc/salt/pki/
[root@salt03 ~]# /etc/init.d/salt-minion restart
Stopping salt-minion daemon: [ OK ]
Starting salt-minion daemon: [ OK ]
准备环境
[root@salt04 ~]# rpm -ivh http://mirror.centos.org/centos/6.8/extras/x86_64/Packages/epel-release-6-8.noarch.rpm
Retrieving http://mirror.centos.org/centos/6.8/extras/x86_64/Packages/epel-release-6-8.noarch.rpm
warning: /var/tmp/rpm-tmp.G3MsQu: Header V3 RSA/SHA1 Signature, key ID c105b9de: NOKEY
Preparing... ########################################### [100%]
1:epel-release ########################################### [100%]
[root@salt04 ~]# /usr/sbin/ntpdate pool.ntp.org
29 Apr 02:45:41 ntpdate[3046]: step time server 85.199.214.100 offset -28803.232360 sec
[root@salt04 ~]# echo '*/5 * * * * /usr/sbin/ntpdate pool.ntp.org >/dev/null 2>&1' >> /var/spool/cron/root
[root@salt04 ~]# service iptables stop
iptables: Setting chains to policy ACCEPT: filter [ OK ]
iptables: Flushing firewall rules: [ OK ]
iptables: Unloading modules: [ OK ]
[root@salt04 ~]# yum install -y salt-master salt-syndic
修改配置文件
[root@salt04 ~]# vi /etc/salt/master
#syndic_master: masterofmaster
改为
syndic_master: salt01
#order_masters: False
改为
order_masters: True
启动服务
[root@salt04 ~]# /etc/init.d/salt-master start
Starting salt-master daemon: [ OK ]
[root@salt04 ~]# /etc/init.d/salt-syndic start
Starting salt-syndic daemon: [ OK ]
认证key
[root@salt01 ~]# salt-key -A -y
The following keys are going to be accepted:
Unaccepted Keys:
salt04
salt05
Key for minion salt04 accepted.
Key for minion salt05 accepted.
minion的master修改为proxy
[root@salt02 ~]# vi /etc/salt/minion
master: salt01
改为
master: salt04
[root@salt02 ~]# /etc/init.d/salt-minion restart
Stopping salt-minion daemon: [ OK ]
Starting salt-minion daemon: [ OK ]
[root@salt03 ~]# vi /etc/salt/minion
master: salt01
改为
master: salt05
[root@salt03 ~]# /etc/init.d/salt-minion restart
Stopping salt-minion daemon: [ OK ]
Starting salt-minion daemon: [ OK ]
认证key
[root@salt04 ~]# salt-key -L
Accepted Keys:
Denied Keys:
Unaccepted Keys:
salt02
Rejected Keys:
[root@salt04 ~]# salt-key -A -y
The following keys are going to be accepted:
Unaccepted Keys:
salt02
Key for minion salt02 accepted.
[root@salt04 ~]# salt '*' test.ping
salt02:
True
[root@salt05 ~]# salt-key -L
Accepted Keys:
Denied Keys:
Unaccepted Keys:
salt03
Rejected Keys:
[root@salt05 ~]# salt-key -A -y
The following keys are going to be accepted:
Unaccepted Keys:
salt03
Key for minion salt03 accepted.
[root@salt05 ~]# salt '*' test.ping
salt03:
True
测试
[root@salt01 ~]# salt '*' test.ping
salt02:
True
salt03:
True
另外需要注意的是,虽然此时我们执行test.ping可能正常获取返回,但是自定义模块无法正常获取返回
[root@salt01 ~]# salt '*' state.sls nginx
salt03:
Data failed to compile:
----------
No matching sls found for 'nginx' in env 'base'
salt02:
Data failed to compile:
----------
No matching sls found for 'nginx' in env 'base'
这是因为minion是从proxy获取这些sls文件,也就是需要在proxy上配置base和pillar并同步sls文件才行
job管理
jid为job id,格式为%Y%m%d%H%M%S%f
显示JID
[root@salt01 ~]# salt '*' test.ping -v
Executing job with jid 20170502230853712401
-------------------------------------------
salt02:
True
salt03:
True
查看job执行过程
[root@salt01 ~]# salt '*' cmd.run 'sleep 200' -v
可以在minion下缓存目录看到jid的文件,而master会通过判断minion端的jid文件是否存在确定命令是否还在执行
[root@salt02 ~]# ll /var/cache/salt/minion/proc/
total 4
-rw-r--r--. 1 root root 99 May 2 23:22 20170502232214623279
master端也在缓存目录下记录返回结果,不过是以hash的方式,默认缓存24小时
[root@salt01 ~]# ls /var/cache/salt/master/jobs/
04 06 0a 15 17 23 27 2e 35 3b 3d 41 46 4b 51 53 56 5a 62 64 68 6f 75 7c 80 88 8f 92 94 98 a0 a9 af b8 ba c0 c2 c6 c9 cd d6 d8 e6 eb f3 f6 fe
05 08 12 16 1e 24 2a 32 3a 3c 3e 43 49 4f 52 54 57 5c 63 65 6e 72 7b 7d 83 8c 91 93 96 9c a7 aa b7 b9 bb c1 c4 c7 cc d0 d7 d9 ea ee f5 fb ff
查看所有job命令
[root@salt01 ~]# salt-run jobs.list_jobs
查看jid返回结果
[root@salt01 ~]# salt-run jobs.lookup_jid 20170502230853712401
salt02:
True
salt03:
True
查看当前所有minion正在运行的jobs
[root@salt01 ~]# salt-run jobs.active
可以通过刚才执行sleep 200的命令后,新开启终端执行
[root@salt01 ~]# salt-run jobs.active
20170503000138921306:
----------
Arguments:
- sleep 200
Function:
cmd.run
Returned:
Running:
|_
----------
salt02:
18692
|_
----------
salt03:
17965
Target:
*
Target-type:
glob
User:
root
当然也有另一种查看方式
[root@salt01 ~]# salt '*' saltutil.running
salt02:
|_
----------
arg:
- sleep 200
fun:
cmd.run
jid:
20170503000138921306
pid:
18692
ret:
tgt:
*
tgt_type:
glob
to:
4
user:
root
salt03:
|_
----------
arg:
- sleep 200
fun:
cmd.run
jid:
20170503000138921306
pid:
17965
ret:
tgt:
*
tgt_type:
glob
to:
4
user:
root
不过区别是,后者在查看以前的job的时候是无法查看的
[root@salt01 ~]# salt '*' saltutil.find_job 20170502230853712401
salt02:
----------
salt03:
----------
[root@salt01 ~]# salt '*' saltutil.find_job 20170503000847093876
salt02:
----------
arg:
- sleep 200
fun:
cmd.run
jid:
20170503000847093876
pid:
19328
ret:
tgt:
*
tgt_type:
glob
to:
4
user:
root
salt03:
----------
arg:
- sleep 200
fun:
cmd.run
jid:
20170503000847093876
pid:
18601
ret:
tgt:
*
tgt_type:
glob
to:
4
user:
root
发送信号
发送指定信号
[root@salt01 ~]# salt '*' saltutil.signal_job 201705030008470938769 9
salt02:
salt03:
发送终止任务信号
[root@salt01 ~]# salt '*' saltutil.term_job 20170503001108876741
salt02:
Signal 15 sent to job 20170503001108876741 at pid 19582
salt03:
Signal 15 sent to job 20170503001108876741 at pid 18855
发送
[root@salt01 ~]# salt '*' saltutil.kill_job 20170503001230542501
salt02:
Signal 9 sent to job 20170503001230542501 at pid 19704
salt03:
Signal 9 sent to job 20170503001230542501 at pid 18977
salt-ssh
saltssh基于ssh,解决了salt依赖root用户执行命令,而saltssh则可以通过sudo进行执行命令,另外salt只支持glob和正则匹配target
安装服务
[root@salt01 ~]# yum install -y salt-ssh
配置salt-ssh
[root@salt01 ~]# vi /etc/salt/roster
[root@salt01 ~]# cat /etc/salt/roster
salt02:
host: 192.168.0.192
user: root
passwd: 123456
检验
注意要先同意连接。
[root@salt01 ~]# salt-ssh '*' test.ping
salt02:
----------
retcode:
254
stderr:
stdout:
The host key needs to be accepted, to auto accept run salt-ssh with the -i flag:
The authenticity of host '192.168.0.192 (192.168.0.192)' can't be established.
RSA key fingerprint is ad:99:6b:06:34:4a:20:1b:83:d6:41:5d:6d:de:3e:8c.
Are you sure you want to continue connecting (yes/no)?
[root@salt01 ~]# ssh 192.168.0.192
The authenticity of host '192.168.0.192 (192.168.0.192)' can't be established.
RSA key fingerprint is ad:99:6b:06:34:4a:20:1b:83:d6:41:5d:6d:de:3e:8c.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '192.168.0.192' (RSA) to the list of known hosts.
root@192.168.0.192's password:
Last login: Tue May 2 20:31:09 2017 from 192.168.0.101
[root@salt02 ~]# exit
logout
Connection to 192.168.0.192 closed.
[root@salt01 ~]# salt-ssh '*' test.ping
salt02:
True
[root@salt01 ~]# salt-ssh '*' -r 'hostname'
salt02:
----------
retcode:
0
stderr:
stdout:
root@192.168.0.192's password:
salt02