salt-入门及安装

saltstack简介

SaltStack是一种新型的基础设施管理软件,简单易部署,可伸缩的足以管理成千上万的服务器,和足够快的速度控制,与他们交流,以毫秒为单位。SaltStack提供了一个动态基础设施通信总线用于编排,远程执行、配置管理等等。SaltStack项目于2011年启动,年增长速度较快,五年期固定基础设施编制和配置管理的开源项目。SaltStack社区致力于保持slat项目集中、友好、健康、开放。

简单来说它的两大基础功能就是:配置管理、远程命令执行。剩下就是根据你的需求自由组合,实现更复杂的功能和系统管理

saltstack运行的模式

1:local
2:master/minion
3:salt SSH(可以不依赖客户端)

saltstack三大功能

远程执行
配置管理
云管理(不是特别成熟,不建议生产环境使用)
Salt即可以批量执行命令,也可以单机执行。通常单机执行用于测试:

  1. 单机(立即)执行。 使用salt-call命令单机执行操作
  2. 批量(立即)执行。最常用的操作。使用salt命令,对匹配的minion节点执行操作

saltstack安装实战

salt解析基于DNS,如果做实验发现执行特别慢,可以尝试配置好域名解析.

服务器安装

salt-master可以使用两个源来安装,一个是EPEL源,一个salt的官方源。
推荐使用salt的官方源。

安装epel包

1
2
rpm -ivh http://mirrors.aliyun.com/epel/epel-release-latest-6.noarch.rpm
rpm -ivh http://mirrors.aliyun.com/epel/epel-release-latest-7.noarch.rpm

配置saltstack的官方yum源

centos 7:

1
2
3
4
5
6
7
8
9
vim /etc/yum.repo.d/saltstack-repo
####################
# Enable SaltStack's package repository
[saltstack-repo]
name=SaltStack repo for RHEL/CentOS 7
baseurl=https://repo.saltstack.com/yum/rhel7
enabled=1
gpgcheck=0
gpgkey=https://repo.saltstack.com/yum/rhel7/SALTSTACK-GPG-KEY.pub

centos6

1
2
3
4
5
6
7
8
9
vim /etc/yum.repo.d/saltstack-repo
####################
# Enable SaltStack's package repository
[saltstack-repo]
name=SaltStack repo for RHEL/CentOS 6
baseurl=https://repo.saltstack.com/yum/rhel6
enabled=1
gpgcheck=0
gpgkey=https://repo.saltstack.com/yum/rhel6/SALTSTACK-GPG-KEY.pub

服务端安装salt-master 软件并启动

1
2
3
yum install salt-master -y
[root@centos6 ~]# /etc/init.d/salt-master start
Starting salt-master daemon: [ OK ]

配置saltstack服务端如下内容:

配置文件需要顶头写,不能有空格。
vim /etc/salt/master

原内容:

1
2
3
4
5
6
7
8
9
10
11
12
#default_include: master.d/*.conf
#interface: 0.0.0.0
# file_roots:
# base:
# - /srv/salt/
# dev:
# - /srv/salt/dev/services
# - /srv/salt/dev/states
# prod:
# - /srv/salt/prod/services
# - /srv/salt/prod/states

修改后的文件:

1
2
3
4
5
6
7
8
default_include: master.d/*.conf
interface: 0.0.0.0
file_roots:
base:
- /etc/salt/states
prod:
- /etc/salt/states/prod
[root@centos6 ~]# mkdir /etc/salt/states/prod -p

修改完配置文件后,需要重启服务

1
2
3
[root@centos6 ~]# /etc/init.d/salt-master restart
Stopping salt-master daemon: [ OK ]
Starting salt-master daemon: [ OK ]

注意:salt的书写一定要注意格式。基础环境(base),生产环境(prod),测试环境(test)分三个目录。通过不同的目录创建不同的内容。

关于salt-master配置文件更多的内容可以参考salt配置文件详解

补充一个线上的配置文件

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
interface: 192.168.56.11
ipv6: False
max_open_files: 65535
worker_threads: 5
timeout: 30
state_verbose: False
file_roots:
base:
- /data/salt/base
prod:
- /data/salt/prod
config:
- /data/salt/config
linux:
- /data/salt/linux
log_file: /var/log/salt/master
log_level_logfile: debug
mysql.host: '192.168.56.13'
mysql.user: 'salt'
mysql.pass: '123456'
mysql.db: 'salt'
mysql.port: 3306
external_auth:
pam:
saltapi:
- .*
- '@runner'
- '@jobs'
rest_cherrypy:
port: 8088
ssl_crt: /etc/pki/tls/certs/localhost.crt
ssl_key: /etc/pki/tls/private/localhost_nopass.key

客户端安装方法:

安装salt-minion 软件

1
yum install salt-minion -y

配置并启动saltstack客户端。

1
2
3
4
[root@centos6 ~]# cd /etc/salt/
[root@centos6 salt]# vim minion
master: 192.168.56.11
id: minion.saltstack.com

重启minion进程

1
2
3
4
5
6
[root@centos6 salt]# /etc/init.d/salt-minion start
Starting salt-minion daemon: [ OK ]

[root@centos6 salt]# /etc/init.d/salt-minion restart
Stopping salt-minion daemon: [ OK ]
Starting salt-minion daemon: [ OK ]

ID 存放在这个文件中

1
2
[root@data-1-1 salt]# cat /etc/salt/minion_id
data-1-1

删除旧的key文件

1
[root@centos6 salt]# mv minion_id /tmp/

master的key存放位置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# cd /etc/salt/pki/master/
# tree
+-- master.pem
+-- master.pub
+-- minions
| +-- linux-node1 (minion的公钥)
| +-- linux-node2 (minion的公钥)
+-- minions_autosign
+-- minions_denied
+-- minions_pre
+-- minions_rejected

5 directories, 4 files
[root@linux-node1 master]#

master端修改minion端的key名称

1
2
3
4
5
6
7
8
9
10
[root@linux-node1 minions]# mv linux-node1 linux-node3
[root@linux-node1 minions]# ls
linux-node2 linux-node3
[root@linux-node1 minions]# salt-key -L
Accepted Keys:
linux-node2
linux-node3
Denied Keys:
Unaccepted Keys:
Rejected Keys:

salt-key命令补充

  • salt-key -d www.etiantian.org 删除一个key 。
  • salt-key -A 同意所有未注册的minion端。
  • salt-key -a www.etiantian.org 同意一个机器。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
[root@centos6 ~]# salt-key
Accepted Keys:
Denied Keys:
Unaccepted Keys:
centos6.6-mupan
minion.saltstack.com
Rejected Keys:
[root@centos6 ~]# salt-key -a minion.saltstack.com ####允许客户端连入服务器。
The following keys are going to be accepted:
Unaccepted Keys:
minion.saltstack.com
Proceed? [n/Y] y
Key for minion minion.saltstack.com accepted.
[root@centos6 ~]#

salt-stakck 状态查询

  • 查看还在运行的程序:salt-run jobs.active
  • 查看以前的操作历史记录来:salt-run jobs.list_jobs
  • 查看minion支持的module列表的命令 salt '*' sys.list_modules
  • 查看CMD模块下的所有function。salt '*' sys.list_functions cmd
  • 查看cmd 模块的详细用法。salt '*' sys.doc cmd

salt远程执行

命令格式:salt 'Trgetiong' module

  • 目标:Trgetiong
  • 模块:Module
  • 返回:Returners

目标匹配方式

通配符使用:

1
2
3
4
5
6
7
salt '*' test.ping
salt '*.example.net' test.ping
salt '*.example.*' test.ping
salt 'web?.example.net' test.ping
salt 'web[1-5]' test.ping
salt 'web[1,3]' test.ping
salt 'web-[x-z]' test.ping

正则表达式使用:

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

也可以在top.sls中使用正则表示:

1
2
3
4
base:
'web1-(prod|devel)':
- match: pcre
- webserver

lists使用:

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

IP地址使用:

1
2
3
[root@centos6 ~]# salt -S '192.168.2.0/24' test.ping
minion.saltstack.com:
True

Grains使用:

1
salt -G 'os:centos' test.ping

也可以在top.sls中使用Grains表示:

1
2
3
4
5
6
base:
'os:centos':
- match: grain
- init.env_init
- zabbix-agent-linux.config
- salt.agent

Pillar使用:

1
salt -I 'master:True' test.ping

salt 异步执行方法

1
2
3
4
5
[root@xxx ~]# salt --async test01 cmd.run "echo 'test'"
Executed command with job ID: 20150915151813222323
[root@xxx ~]# salt-run jobs.lookup_jid 20150915151813222323
Fabric:
test

还有个-v参数在返回结果的同时,一同返回本次任务的jid,如果超时还是会返回jid的。

1
2
3
4
5
[root@test ~]# salt -v test01 test.ping
Executing job with jid 20150917172323566343
-------------------------------------------
test01:
True

如果是调用saltapi来实现异步执行语句和获取jid信息,参数可以这样:

1
2
params = {'client':'local_async', 'fun':'test.echo', 'tgt':'test01', 'arg1':'hello'}
params = {'client':'runner', 'fun':'jobs.lookup_jid', 'jid': '20150827163231404925'}

salt权限控制

salt 使用 pam 模块对普通账号进行权限控制

salt 扩展认证 PAM,可以利用PAM 认证机制对系统账户做出功能操作上的限制。依赖的模块salt.states.external_auth

开启PAM认证

编辑 /etc/salt/master

1
2
3
4
external_auth:
pam:
salt:
- '*'

创建 salt 用户 设置密码

验证

salt PAM 认证用户 只能通过-a pam 参数才能使用

1
salt -a pam test.ping

会提示登陆用户,输入密码,如果正确返回结果,说明pam认证已经生效

实例 :

1
2
3
4
5
6
7
8
9
10
11
12
/etc/salt/master

external_auth:
pam:
admin:
- '*' # 所有模块
salt:
- test.ping # test.ping 模块
test:
- 'dev*' # 主机配置规则
- test.ping # Salt 模块

解释:

  • admin 用户可管理所有主机,使用所有salt功能模块
  • salt 用户可管理所有主机,仅能使用test.ping模块
  • test 用户只能管理部分主机,仅能使用test.ping模块

实例1: 以salt用户为例,认证用户必须打开PAM 参数才能操作

失败操作:

1
2
 salt '*' test.ping
Failed to authenticate, is this user permitted to execute commands?

成功操作:

1
2
3
4
5
 salt -a pam '*' test.ping
username: salt
password:
ubuntu-master:
True

实例2: 以salt用户为例,执行未授权模块被拒绝

1
2
3
4
salt -a pam '*' state.highstate
username: salt
password:
Failed to authenticate, is this user permitted to execute commands?

以test用户为例,操作未授权主机被拒绝
失败操作

1
2
3
4
salt -a pam '*' test
username: test
password:
Failed to authenticate, is this user permitted to execute commands?

成功操作

1
2
3
4
5
salt -a pam 'test-001' test
username: test
password:
test-001:
True

支持文档:

官方帮助文档
官方github
saltstack 中文用户组
Saltstack SLS文件解读
[官方的 salt-states 仓库地址] (https://github.com/saltstack/salt-states)

来自于社区的一些salt states例子:

https://github.com/blast-hardcheese/blast-salt-states
https://github.com/kevingranade/kevingranade-salt-state
https://github.com/uggedal/states
https://github.com/mattmcclean/salt-openstack/tree/master/salt
https://github.com/rentalita/ubuntu-setup/
https://github.com/brutasse/states
https://github.com/bclermont/states
https://github.com/pcrews/salt-data

参考文档
文档: http://docs.saltstack.com/topics/tutorials/starting_states.html
文档: http://docs.saltstack.com/ref/states/writing.html
文档: http://docs.saltstack.com/ref/states/ordering.html
文档: http://www.ituring.com.cn/article/37783
文档: http://docs.saltstack.com/topics/tutorials/starting_states.html

问题汇总:

报错一:

1
2
3
4
5
6
7
8
9
10
----------
ID: limit-conf-config
Function: file.managed
Name: /etc/securilty/limits.conf
Result: False
Comment: Parent directory not present
Started: 17:05:44.606040
Duration: 11.448 ms
Changes:

解决办法:

出现这个的原因是Minion上没有name参数定义的目录. 在minion上定义对应的目录就可以了

报错:salt 管理配置文件时,报错。

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
[root@master files]# salt '*' state.highstate
agent.niu.com:
Data failed to compile:
----------
Rendering SLS init.limit failed, render error: expected '<document start>', but found '<block mapping start>'
in "<unicode string>", line 2, column 1:
limit-conf-config:
^
Traceback (most recent call last):
File "/usr/lib/python2.7/site-packages/salt/state.py", line 2509, in render_state
sls, rendered_sls=mods
File "/usr/lib/python2.7/site-packages/salt/template.py", line 79, in compile_template
ret = render(input_data, saltenv, sls, **render_kwargs)
▽ File "/usr/lib/python2.7/site-packages/salt/renderers/yaml.py", line 50, in render
data = load(yaml_data, Loader=get_yaml_loader(argline))
File "/usr/lib64/python2.7/site-packages/yaml/__init__.py", line 71, in load
return loader.get_single_data()
File "/usr/lib64/python2.7/site-packages/yaml/constructor.py", line 37, in get_single_data
node = self.get_single_node()
File "/usr/lib64/python2.7/site-packages/yaml/composer.py", line 39, in get_single_node
if not self.check_event(StreamEndEvent):
File "/usr/lib64/python2.7/site-packages/yaml/parser.py", line 98, in check_event
self.current_event = self.state()
File "/usr/lib64/python2.7/site-packages/yaml/parser.py", line 174, in parse_document_start
self.peek_token().start_mark)
ParserError: expected '<document start>', but found '<block mapping start>'
in "<unicode string>", line 2, column 1:
limit-conf-config:
^

解决办法:

配置文件的路径配置错误。导致报错。修改配置文件,问题解决。

报错:saltstack 执行后CPU占用率为百分之百。

1
2
[root@10-10-121-200 ~]# salt 'linux-backup-saltminion' test.ping
Salt request timed out. The master is not responding. If this error persists after verifying the master is up, worker_threads may need to be increased.

解决办法:

使用top 查看CPU占用率为百分之百。
降低salt的线程数。

报错:配置完return后,不能向数据库写入数据:

1
2
mysql> select * from salt_returns;
Empty set (0.00 sec)

解决思路:

当遇到问题是可以将log的级别更改为debug模式来调试。

解决办法:

因为是客户端直接返回给数据库,所有客户端需要数据库的连接权限。顾所有数据库都需要添加如下内容:

1
2
3
4
5
6
7
8
9
10
11
vim /etc/salt/minion
mysql.host: '192.168.2.150'
mysql.user: 'salt'
mysql.pass: 'salt'
mysql.db: 'salt'
mysql.port: 3306
[root@centos6 ~]# /etc/init.d/salt-minion restart
Stopping salt-minion daemon: [ OK ]
Starting salt-minion daemon: [ OK ]
[root@centos6 ~]#

报错: 执行state.sls 报错

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
root@10.10.121.200 files]# salt '*.service' state.sls ssh.config env=prod
chuye.backup1.service:
Data failed to compile:
----------
Requisite declaration file.sshd-files in SLS ssh.config is not formed as a single key dictionary
----------
Requisite declaration file.sshd-files in SLS ssh.config is not formed as a single key dictionary
chuye.logstash1.service:
Data failed to compile:
----------
Requisite declaration file.sshd-files in SLS ssh.config is not formed as a single key dictionary
----------
Requisite declaration file.sshd-files in SLS ssh.config is not formed as a single key dictionary
chuye.logstash2.service:
Data failed to compile:
----------
Requisite declaration file.sshd-files in SLS ssh.config is not formed as a single key dictionary
----------
Requisite declaration file.sshd-files in SLS ssh.config is not formed as a single key dictionary

解决办法:

1
2
3
4
- require:
- file.sshd-files
- watch:
- file.sshd-files

上面的值配置错误

1
2
3
4
- require:
- file: sshd-files
- watch:
- file: sshd-files

报错:在文件中调用grains报错

1
2
3
4
5
6
7
8
9
----------
ID: zabbix-agent-install
Function: file.managed
Name: /etc/zabbix_agentd.conf.bak
Result: False
Comment: Unable to manage file: Jinja variable 'item' is undefined
Started: 16:12:39.454923
Duration: 17.407 ms
Changes:

解决办法:

1
2
3
Hostname={{ grains[fqdn] }}
没有加引号
Hostname={{ grains['fqdn'] }}

报错:调用jinjia模板的时候多了一对括号

1
2
3
#!/bin/sh
-IPADDR=['10.10.86.159']
+IPADDR=chuye.logstash2.service

解决办法:

1
2
3
4
5
Solution:

Address {{ grains['fqdn_ip4'][0] }}
Result:
Address 111.111.111.111