SaltStack 基础


简介

简单介绍

  1. 一个配置管理系统,能够维护预定义状态的远程节点。(比如,确保指定的软件被安装,指定的服务在运行)
  2. 一个分布式远程执行系统,用来在远程节点(可以是单个节点,也可以是任意规则挑选出来的节点)上执行命令和查询数据。
  3. 开发其的目的是为:远程执行提供最好的解决方案,并使远程执行变得更好,更快,更简单。
  4. SaltStack是使用Python语言开发的,同时提供Rest API方便二次开发以及和其它平台进行集成。

参考学习

1
2
3
https://www.cnblogs.com/wangxu01/tag/saltstack/
https://github.com/unixhot
https://github.com/unixhot/saltbook-code/tree/master/salt/prod

常用网址

• 官方网站:http://www.saltstack.com
• 官方文档:http://docs.saltstack.com
• GitHub:https://github.com/saltstack
• 中国SaltStack⽤户组:http://www.saltstack.cn

四大功能

  1. 配置管理
  2. 远程执行
  3. 云管理
  4. 事件驱动

基础架构

• Saltstack基于C/S架构
– 服务端:Master
– 客户端:Minion

• 可以实现传统处理方式,即:客户端发送请求给服务器,服务器收到请求后处理请求,再将结果返回

• 也可以使用消息队列中的发布与订阅(pub/sub)服务模式

工作原理

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

运行流程

  1. Salt stack的Master与Minion之间通过ZeroMq进行消息传递,使用了ZeroMq的发布-订阅模式,连接方式包括tcp,ipc
  2. salt命令,将cmd.run ls命令从salt.client.LocalClient.cmd_cli发布到master,获取一个Jobid,根据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执行结果,将结果输出到终端。

通信端口

master端:4505,4506
minion端:4506

工作方式

  1. Local
  2. Master/Minion
  3. Salt SSH
  • 最传统的运行方式还是C/S模式,管理端安装Master,被管理节点上安装Minion客户端

安装和配置

实验环境

• CentOS6 10.0.0.200 linux-node1 master/minion
• CentOS6 10.0.0.201 linux-node2 minion

关闭 Selinux

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
查看selinux状态
[root@linux-node2]# sestatus
SELinux status: enabled
SELinuxfs mount: /sys/fs/selinux
SELinux root directory: /etc/selinux
Loaded policy name: targeted
Current mode: permissive
Mode from config file: enforcing
Policy MLS status: enabled
Policy deny_unknown status: allowed
Max kernel policy version: 28
[root@linux-node2 minion]# geten
getenforce getent

[root@linux-node2]# getenforce
Permissive

# 临时关闭
[root@linux-node2]# setenforce 0

# 永久关闭
可以修改配置文件/etc/selinux/config,将其中SELINUX设置为disabled。

安装

1
2
3
4
5
6
7
8
9
curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo
curl -o /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo


* For RHEL/CentOS 6: 需要python2.7以上版本
rpm -ivh http://repo.saltstack.com/yum/redhat/salt-repo-latest.el6.noarch.rpm

* For RHEL/CentOS 7:
yum install https://repo.saltstack.com/yum/redhat/salt-repo-latest.el7.noarch.rpm

Salt Master安装

1
[root@linux-node1 yum.repos.d]# yum install -y salt-master salt-minion

Salt Minion安装

1
[root@linux-node2 ~]# yum install -y salt-minion

启动 salt-master

1
2
3
4
systemctl start salt-master
systemctl enable salt-master
ps -ef | grep salt-master|grep –v grep
systemctl status salt-master

查看目录

1
2
3
4
5
6
7
8
9
10
11
12
13
[root@linux-node1 salt]# pwd
/etc/salt
[root@linux-node1 salt]# tree pki/
pki/
├── master
│   ├── master.pem # 启动后的密钥
│   ├── master.pub # 启动后的公钥
│   ├── minions
│   ├── minions_autosign
│   ├── minions_denied
│   ├── minions_pre
│   └── minions_rejected
└── minion

客户端修改配置文件

1
2
3
4
5
6
7
8
9
# 修改minion配置文件:告诉master是谁
# 两台客户端一起修改
# 配置文件里不能敲tab键
# 78 ID 该参数告诉master "我是谁",如果不配,默认是主机名

[root@linux-node1 salt]# vim minion
16 master: 10.0.0.250

[root@linux-node2 ~]# sed -i 's#\#master: salt#master: 10.0.0.250#g' /etc/salt/minion

启动 salt-minion

1
2
3
systemctl start salt-minion
systemctl enable salt-minion
systemctl status salt-minion

查看客户端目录

1
2
3
4
5
6
7
# 客户端启动后创建自己的公钥和私钥
[root@linux-node2 ~]# tree /etc/salt/pki
/etc/salt/pki
├── master
└── minion
├── minion.pem # 启动后的密钥
└── minion.pub # 启动后的公钥
1
2
3
4
# 客户端ID文件
# 如果之后要修改ID值,还需要再重新启动之前删除该文件
[root@linux-node2 salt]# cat /etc/salt/minion_id
linux-node2

配置认证 salt-key

  • 在启动minion后,会将自己的公钥发送给master
1
2
3
4
5
6
7
8
9
10
11
[root@linux-node1 pki]# tree /etc/salt/pki/master
/etc/salt/pki/master
├── master.pem
├── master.pub
├── minions
├── minions_autosign
├── minions_denied
├── minions_pre
│   ├── linux-node1 # 通过ID命名
│   └── linux-node2 # 通过ID命名
└── minions_rejected
  • 通过命令同意公钥,让 master 管理 minions
1
2
3
4
5
6
7
8
9
# 查看minion salt-key -L

[root@linux-node1 pki]# salt-key -L
Accepted Keys:
Denied Keys:
Unaccepted Keys:
linux-node1
linux-node2
Rejected Keys:
1
2
3
4
5
salt-key -A                         # 同意所有minion
salt-key -a linux-node1 -y # 同意指定的node

salt-key -D # 拒绝,删除
salt-key -d linux-node1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
[root@linux-node1 pki]# salt-key -L
Accepted Keys:
Denied Keys:
Unaccepted Keys:
linux-node1
linux-node2
Rejected Keys:

[root@linux-node1 pki]# salt-key -A
The following keys are going to be accepted:
Unaccepted Keys:
linux-node1
linux-node2
Proceed? [n/Y] y
Key for minion linux-node1 accepted.
Key for minion linux-node2 accepted.

[root@linux-node1 pki]# salt-key
Accepted Keys:
linux-node1
linux-node2
Denied Keys:
Unaccepted Keys:
Rejected Keys:

  • 查看 minion 目录,master 会把公钥发过来
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[root@linux-node1 pki]# tree /etc/salt/pki/
/etc/salt/pki/
├── master
│   ├── master.pem
│   ├── master.pub
│   ├── minions
│   │   ├── linux-node1
│   │   └── linux-node2
│   ├── minions_autosign
│   ├── minions_denied
│   ├── minions_pre
│   └── minions_rejected
└── minion
├── minion_master.pub # master 把公钥发过来了,双向的交换了密钥
├── minion.pem
└── minion.pub
  • 查看 master目录,原来是在 minions_pre 现在到了minions,说明master可以管理
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[root@linux-node1 pki]# tree /etc/salt/pki/
/etc/salt/pki/
├── master
│   ├── master.pem
│   ├── master.pub
│   ├── minions # 原来是在 minions_pre
│   │   ├── linux-node1
│   │   └── linux-node2
│   ├── minions_autosign
│   ├── minions_denied
│   ├── minions_pre
│   └── minions_rejected
└── minion
├── minion_master.pub
├── minion.pem
└── minion.pub

验证通信

1
2
3
4
5
6
7
8
# 返回true为正常 
# * 代表所有,单引号为转义

[root@linux-node1 pki]# salt '*' test.ping
linux-node2:
True
linux-node1:
True

1
2
3
4
5
6
7
8
# 如果出现salt '*' test.ping出错Minion did not return. [Not connected]
# 解决这种错误,需要删除minion端的key,重新认证。
rm -rf /etc/salt/pki/minion/minion_master.pub
rm -rf /etc/salt/pki/minion/
# 重启minion端
systemctl restart salt-minion

# 一定要记得初始化环境要关闭SEXLINUX
1
2
3
4
5
# 单独验证
# 实际上所有的minion 都收到了 但是只有 node2返回了结果
[root@linux-node1 pki]# salt 'linux-node2' test.ping
linux-node2:
True

查看端口

  • 服务端与客户端发送消息 通过 消息队列 zeromq
  • 所有的minion 都连接到 slat的 4505端口上
1
2
3
4
5
6
7
# master 

[root@linux-node1 pki]# netstat -tnlp
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:4505 0.0.0.0:* LISTEN 1470/python
tcp 0 0 0.0.0.0:4506 0.0.0.0:* LISTEN 1476/python
...
1
2
3
4
5
6
7
8
9
# -n 不做域名解析
# -i 检查所有和4505所有的连接

[root@linux-node1 pki]# lsof -n -i:4505
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
salt-mast 1470 root 16u IPv4 20545 0t0 TCP *:4505 (LISTEN)
salt-mast 1470 root 18u IPv4 39421 0t0 TCP 10.0.0.250:4505->10.0.0.250:58670 (ESTABLISHED)
salt-mast 1470 root 19u IPv4 39477 0t0 TCP 10.0.0.250:4505->10.0.0.251:45200 (ESTABLISHED)
salt-mini 7502 root 27u IPv4 39420 0t0 TCP 10.0.0.250:58670->10.0.0.250:4505 (ESTABLISHED)
1
2
3
4
# 返回消息 发送给4506
[root@linux-node1 pki]# lsof -n -i:4506
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
salt-mast 1476 root 24u IPv4 20569 0t0 TCP *:4506 (LISTEN)

端口开启

1
2
3
# master使用两个端口和minion通信,要确保这两个端口通信正常。
# 4505 publish_port 消息发布系统端口
# 4506 ret_port 客户端与服务端通信端口
1
2
3
4
# 可以关闭掉防火墙,或者将端口添加至INPUT链表。
# iptables链表规则是自上而下,这里插入在REJECT ALL之前。
iptables -I INPUT 5 -p tcp --dport 4505 -j ACCEPT -m comment --comment "salt_publish_port"
iptables -I INPUT 5 -p tcp --dport 4506 -j ACCEPT -m comment --comment "salt_ret_port"

普通用户使用saltstack

修改minion_ID

1
2
3
4
5
6
停止minion服务
salt-key –d minion_id 删除minion ID
minion端rm –f /etc/salt/minion_id
minion端 rm –rf /etc/salt/pki/
修改配置文件id
启动minion

Salt 远程执行命令

基础语法

  • 执行salt的基本语法:
1
salt '<target>' <function> [arguments]
1
2
3
4
5
6
7
# 在所有客户端上执行uptime命令
# cmd.run
[root@linux-node1 ~]# salt '*' cmd.run 'uptime'
linux-node1:
18:02:09 up 17 min, 1 user, load average: 0.01, 0.05, 0.12
linux-node2:
18:02:09 up 17 min, 1 user, load average: 0.00, 0.02, 0.06

选择目标

1
https://docs.saltstack.com/en/latest/topics/targeting/index.html

和 minion_ID 相关的

  • 通配符
1
2
salt '*' test.version
salt 'linux-node*' test.ping
  • 正则
1
[root@linux-node1 base]# salt -E 'linux-node(1|2)' test.ping
  • 列表
1
2
3
4
5
6
7
salt -L 'linux-node1,linux-node2' test.version

# top file: 所有匹配目标的方式,都可以用到top file里面来指定目标。
base:
'web1-(prod|devel)':
- match: pcre
- webserver
  • minion ID设置方案:IP地址、根据业务来进行设置
1
2
3
4
5
redis-node1 # redis第一个节点

redis04 # 集群

game01 # 业务线

和 minion_ID 无关的

  • GRAINS匹配
1
salt -G 'os:CentOS' test.version
  • IP地址
1
salt -S 10.0.0.0/24 test.version
  • 批处理
1
2
3
slat并发改成串行   每次自行10个
salt '*' -b 10 test.versio
salt -G 'os:RedHat' --batch-size 25% apache.signal restart #一次处理25%

执行模块

  • 远程执行三大组件
1
2
3
1. 选择目标:通配符、正则、list
2. 返回:job cache
3. 执行模块:network、service、state
1
2
3
4
虚拟模块:针对不同的操作系统 调用不同的方法
通过yum默认安装salt所有模块存放路径 /usr/lib/python2.7/site-packages/salt/modules(centos 7)
https://www.unixhot.com/docs/saltstack/ref/modules/all/index.html#all-salt-modules
https://www.unixhot.com/docs/saltstack/ref/modules/all/salt.modules.service.html#module-salt.modules.service
  • network

    1
    2
    3
    salt '*' network.active_tcp
    salt '*' network.arp
    salt '*' network.connect archlinux.org 8
  • service

1
2
3
# 如果所有的服务器都是统一的操作系统 比如CentOS7 那么可以使用cmd.run 执行命令
# 如果 既有7也有6 那么就使用service模块,他底层封装好了帮我们,针对不同的系统,调用不同的命
salt '*' service.get_all
  • state
1
2
3
4
5
6
7
https://www.unixhot.com/docs/saltstack/ref/modules/all/salt.modules.state.html#module-salt.modules.state

salt '*' state.show_top
1. 执行模块和状态模块本质区别:
1. 执行模块上来就执行
2. 状态模块先看你有没有,没有就帮你执行
salt '*' state.single pkg.installed name=vi
1
2
3
4
5
6
7
8
9
# 常用
salt '*' network.active_tcp # 列出所有主机运行的tcp连接
salt '*' network.arp # 列出所有主机arp
salt '*' service.available sshd # 列出所有主机sshd
salt '*' service.get_all # 列出所有主机的所有运行服务
salt '*' service.status sshd # 列出所有主机sshd运行状态
salt-cp '*' /etc/hosts /tmp/test # 将master上/etc/hosts文件拷贝到所有主机的/tmp/test
salt '*' state.show_top # 查看top
salt '*' state.single pkg.installed name=lsof # 所有主机安装lsof

Salt 配置管理

YAML

YAML 是一个可读性高,用来表达数据序列化的格式。
在使用YANL编辑配置文件时,需要注意:

  1. 格式: 两个空格缩进
  2. 冒号后面要后空格
  3. - 代表列表, - 后面有空格

数据结构可以用类似大纲的缩排方式呈现,结构通过缩进来表示,连续的项目通过减号“-”来表示,
map结构里面的key/value对用冒号“:”来分隔。

样例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
house:
family:
name: Doe
parents:
- John
- Jane
children:
- Paul
- Mark
- Simone
address:
number: 34
street: Main Street
city: Nowheretown
zipcode: 1234

Salt 状态管理

  • 什么叫状态管理
    状态是对minion的一种描述和定义,管理人员可以不关心具体部署任务时如何完成的,只需要描述minion要达到什么状态,底层由salt的状态模块来完成功能

创建状态配置文件目录

  • 告诉 master 状态文件放在哪个位置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 编辑master配置文件
# 搜索: /file_roots
# base基础环境 dev开发环境 test测试环境 prod生产环境

[root@linux-node1 ~]# vim /etc/salt/master
file_roots:
base:
- /srv/salt/base
dev:
- /srv/salt/dev
test:
- /srv/salt/test
prod:
- /srv/salt/prod
  • 创建目录
1
2
3
4
5
6
7
[root@linux-node1 ~]# mkdir -p /srv/salt/{base,dev,test,prod}
[root@linux-node1 ~]# tree /srv/salt/
/srv/salt/
├── base # 必须有
├── dev # 开发环境
├── prod # 生产环境
└── test # 测试环境
  • 重启master,改完配置就要重启
1
2
3
4
5
6
7
[root@linux-node1 ~]# systemctl restart salt-master
[root@linux-node1 ~]# systemctl status salt-master
[root@linux-node1 ~]# salt '*' test.ping
linux-node2:
True
linux-node1:
True
  • 查看日志
1
2
3
vim /etc/salt/master
log_level: debug
[root@linux-node1 salt]# tail /var/log/salt/master

简单状态管理 自动化安装apache并启动

  • 编写状态文件需要注意
1
2
3
所有的状态文件 都需要以.sls结尾 --> Salt State
所有文件名小写
所有主机名都用-,不许用_下划线,因为DNS解析不支持_,主机名也都小写
  • CentOS7 服务管理
1
2
3
4
5
6
7
8
9
10
11
12
13
14
1.启动、终止、重启
systemctl start httpd.service #启动
systemctl stop httpd.service #停止
systemctl restart httpd.service #重启

2.设置开机启动/关闭
systemctl enable httpd.service #开机启动
systemctl disable httpd.service #开机不启动

3.检查httpd状态
systemctl status httpd.service

4.查看服务开机启动列表
systemctl list-unit-files;

apache.sls

1
2
3
4
5
6
7
8
9
10
11
[root@linux-node1 base]# cd /srv/salt/base/
[root@linux-node1 base]# vim apache.sls

apache-install: # 唯一表示ID
pkg.installed: # pkg状态模块,installed方法
- name: httpd # installed方法参数,这台机器安装http,如果有什么也不做,没有就安装

apache-service: # 唯一表示ID
service.running: # service状态模块.running方法
- name: httpd # 保证http处于运行状态,运行啥也不做,没有就起来
- enable: True # 开机自动启动,等于当前状态 yum install httpd | systemctl start|enable httpd
1
2
3
4
5
6
7
8
9
10
[root@linux-node1 base]# vim apache.sls

apache-install:
pkg.installed:
- name: httpd

apache-service:
service.running:
- name: httpd
- enable: True

单独执行

1
2
3
4
# salt '*' state.sls apache
# state(状态执行模块).sls(方法)
# 去base下找 apache.sls 文件 并执行这个状态
# .sls(省略)
1
2
3
4
# 去node2看看是否在yum安装httpd
[root@linux-node2 ~]# ps aux | grep yum
root 1829 0.0 2.3 322532 23896 ? R 18:57 0:00 /usr/bin/python /usr/bin/yum --quiet --assumeyes check-update --setopt=autocheck_running_kernel=false
root 1833 0.0 0.0 112712 956 pts/0 R+ 18:57 0:00 grep --color=auto yum
  • 查看node1的执行状态

1
2
3
4
5
6
7
8
# 需要关注的执行状态
ID: apache-service # 状态ID
Result: True # 返回结果
Changes: # 变化
Succeeded: 2 (changed=2) # 成功2个,改变2个
Failed: 0

Total states run: 2 # 总共运行了2
  • 查看node2上的服务和端口状态

  • 可以将node2的httpd关闭 再执行测试
1
[root@linux-node2 ~]# systemctl stop httpd

1
2
3
使用彩色输出时,颜色代码如下:
green表示成功,red表示失败,blue表示更改和成功以及yellow表示预期的将来配置更改。
状态管理,就算你卸载了httpd,再执行都会帮你安装并启动

分类

  • 分类
    所有的sls文件都存放在base目录下,在生产项目中会相当难找到,所以需要根据软件的功能进行目录分类
1
2
3
4
5
6
7
8
9
10
11
12
# 创建分类目录
[root@linux-node1 base]# mkdir -p {sql,web,nosql,monitor}

[root@linux-node1 base]# mv apache.sls web/

[root@linux-node1 base]# tree
.
├── monitor
├── nosql
├── sql
└── web
└── apache.sls
  • 多级目录执行
1
2
# base是基准目录
[root@linux-node1 base]# salt '*' state.sls web.apache

高级状态管理 top.sls

  • 编辑top.sls
    如果我们有很多的sls文件,但是这些文件只能单独执行,如果批量执行呢?
    这个时候我们可以使用top.sls,他相当于任务编排
1
2
3
4
[root@linux-node1 base]# vim /etc/salt/master
/top.sls
# 打开注释
state_top: top.sls
1
2
3
4
5
6
7
# top.sls默认放在base环境下
[root@linux-node1 base]# vim /srv/salt/base/top.sls
base: # 执行环境
'linux-node1': # minion_id
- web.apache # 要执行的状态
'linux-node2':
- web.apache
1
2
3
4
5
6
7
[root@linux-node1 base]# vim /srv/salt/base/top.sls

base:
'linux-node1':
- web.apache
'linux-node2':
- web.apache
  • 执行
1
2
3
4
5
[root@linux-node1 base]# salt '*' state.highstate
# 高级状态根据ID单独执行
[root@linux-node1 base]# salt 'linux-node1' state.highstate
# 高级状态,salt默认会去base下找top.sls,读取编排,哪个minion执行什么状态
# 如果80端口被nginx服务占用,记得要先关闭,salt无法帮你关闭不是要求的工作状态

常用的状态模块

  • 服务的基本要求: 安装、配置、启动

pkg

  • 功能:管理软件包状态
  • 常用方法:
1
2
3
4
• pkg.installed # 确保软件包已安装. 如果没有安装就安装
• pkg.latest # 确保软件包是最新版本, 如果不是, 升级
• pkg.remove # 确保软件包已卸载, 如果之前已安装, 卸载
• pkg.purge # 除remove外, 也会删除其配置文件
  • 官方文档:
  1. https://docs.saltstack.cn/ref/states/all/index.html
  2. https://docs.saltstack.cn/ref/states/all/salt.states.pkg.html#module-salt.states.pkg
1
2
3
4
# pkg是虚拟模块,在CentOS上调用 yum安装
# 正确的写法是 先找一台机器,yum安装看看需要哪些包,然后再写
# 一个ID下面只允许一个状态执行一次
# pkgs:要从软件存储库安装的软件包列表
1
2
3
4
5
6
7
8
9
10
lamp-install:
pkg.installed:
- pkgs:
- httpd
- php
- php-pdo
- php-mysql
- php-cli
- php-common
- mysql

file

  • 功能:管理文件状态
  • 常用方法:
1
2
3
• file.managed  # 保证文件存在并且为对应的状态
• file.recurse # 保证目录存在并且为对应状态
• file.absent # 确保文件不存在, 如果存在就删除
  • 官方文档:
  1. https://docs.saltstack.cn/ref/states/all/salt.states.file.html#module-salt.states.file
1
2
3
4
name      # 在客户端的位置
source # 源目录base/web/ 会把源目录下的文件,替换放过去,也支持ftp和http下载
# 以后都以 source 的文件为准了,所有的位置都在一个地方改
# 不一样的配置如何设置呢?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
apache-config:
file.managed:
- name: /etc/httpd/conf/httpd.conf
- source: salt://web/files/httpd.conf
- user: root
- group: root
- mode: 644

php-config:
file.managed:
- name: /etc/php.ini
- source: salt://web/files/php.ini
- user: root
- group: root
- mode: 644

mysql-config:
file.managed:
- name: /etc/my.cnf
- source: salt://web/files/my.cnf
- user: root
- group: root
- mode: 644
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 其他模块方法
file.copy /etc/nginx/nginx.conf /home/zhanqi/nginx.conf # 文件复制

file.get_sum /home/zhanqi/nginx.conf md5 # 文件md5校验

file.chown /home/zhanqi/nginx.conf zhanqi zhanqi # 修改文件所属用户以及组

file.set_mode /home/zhanqi/nginx.conf 755 # 修改文件权限

file.mkdir /home/zhanqi/testdir # 创建目录

file.remove /home/zhanqi/testdir # 移除目录

file.append /home/zhanqi/nginx.conf 'add_header "Access-Control-Allow-Origin" "*";' # 追加内容到文件

file.recurse # 下发目录

service

  • 功能:管理服务状态
  • 常用方法:
1
2
3
4
• service.running     # 确保服务处于运行状态,如果没有行就启动
• service.enabled # 确保服务开机启动
• service.disabled # 确保服务开机不启动启动
• service.dead # 确保服务当前没有运行,如果运行就停止
  • 官方文档:
  1. https://docs.saltstack.cn/ref/states/all/salt.states.service.html#module-salt.states.service
1
2
3
4
5
6
7
8
9
httpd-service:
service.running:
- name: httpd
- enable: True

mariadb-service:
service.running:
- name: mariadb
- enable: True
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
# 执行成功日志
[root@linux-node1 web]# salt 'linux-node2' state.sls web.lamp
linux-node2:
----------
ID: lamp-install
Function: pkg.installed
Result: True
Comment: All specified packages are already installed
Started: 09:09:40.109789
Duration: 664.41 ms
Changes:
----------
ID: apache-config
Function: file.managed
Name: /etc/httpd/conf/httpd.conf
Result: True
Comment: File /etc/httpd/conf/httpd.conf is in the correct state
Started: 09:09:40.776230
Duration: 18.621 ms
Changes:
----------
ID: php-config
Function: file.managed
Name: /etc/php.ini
Result: True
Comment: File /etc/php.ini is in the correct state
Started: 09:09:40.795022
Duration: 9.828 ms
Changes:
----------
ID: mysql-config
Function: file.managed
Name: /etc/my.cnf
Result: True
Comment: File /etc/my.cnf is in the correct state
Started: 09:09:40.805020
Duration: 8.337 ms
Changes:
----------
ID: httpd-service
Function: service.running
Name: httpd
Result: True
Comment: The service httpd is already running
Started: 09:09:40.814034
Duration: 32.034 ms
Changes:
----------
ID: mariadb-service
Function: service.running
Name: mariadb
Result: True
Comment: Service mariadb has been enabled, and is running
Started: 09:09:40.846290
Duration: 4801.984 ms
Changes:
----------
mariadb:
True

Summary for linux-node2

  • salt缓存
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[root@linux-node1 salt]# cd /var/cache/salt/minion/
[root@linux-node1 minion]# tree
.
├── accumulator
├── extmods
├── files
│   └── base
│   ├── lamp.sls
│   ├── top.sls
│   └── web
│   └── apache.sls
├── highstate.cache.p
├── module_refresh
├── proc
└── sls.p

状态间关系

file.recurse 管理多个配置文件

  • 功能: 通过主目录上的子目录递归,并将所述子目录复制到指定的路径
1
2
3
4
5
httpd管理多个配置文件:
1. 管理conf.d/*.conf
2. 先看Include目录
[root@linux-node2 etc]# vim /etc/httpd/conf/httpd.conf
Include conf.modules.d/*.conf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
[root@linux-node1 files]# pwd
/srv/salt/base/web/files

[root@linux-node1 files]# mkdir -p apache-conf.d

[root@linux-node1 files]# cd apache-conf.d/

[root@linux-node1 apache-conf.d]# cp /etc/httpd/conf.d/* ./
[root@linux-node1 apache-conf.d]# touch leo.conf
[root@linux-node1 apache-conf.d]# tree
.
├── autoindex.conf
├── leo.conf
├── php.conf
├── README
├── userdir.conf
└── welcome.conf

0 directories, 6 files
  • 添加管理语句
1
2
3
4
5
6
7
8
9
10
[root@linux-node1 web]# vim lamp.sls 
apache-conf:
file.recurse:
- name: /etc/httpd/conf.d
- source: salt://web/files/apache-conf.d

/etc/profile:
file.append:
- text:
- "#Redis_PATH=''"

watch 和 watch_in 处理状态之间的关系

  • 功能 如果我的配置文件变更,服务就自动reload
1
2
• watch     # 我关注某个状态
• watch_in # 我被某个状态关注
1
2
3
4
# file 是要监控的状态模块  apache-conf 是状态的ID
# apache-config 文件 更新就重启
# 增加了 reload: True watch会执行reload
# 服务不支持reload 比如mysql 那就不要加,mysql动态改参数 set
1
2
3
4
5
6
7
httpd-service:
service.running:
- name: httpd
- enable: True
- reload: True
- watch:
- file: apache-config
  • 文件的状态被关注
  1. wacth # 服务关注什么
  2. watch_in # 文件被什么所关注
  3. 目录有更新 就执行重启
1
2
3
4
5
6
apache-conf:
file.recurse:
- name: /etc/httpd/conf.d
- source: salt://web/files/apache-conf.d
- watch_in:
- service: httpd-service

require和 require_in依赖某个状态

  • 功能: 比如安装某个软件没有成功,就不往下走了
1
2
• require     # 我依赖某个状态
• require_in # 我被某个状态依赖
  • lamp-install 如果安装不成功,就不会向下执行
1
2
3
4
5
6
7
8
9
apache-config:
file.managed:
- name: /etc/httpd/conf/httpd.conf
- source: salt://web/files/httpd.conf
- user: root
- group: root
- mode: 644
- require:
- pkg: lamp-install

unless 状态判断

添加info.php页面

1
2
3
4
5
6
7
8
9
10
[root@linux-node2 conf]# cd /var/www/html/
[root@linux-node2 html]# mkdir admin
[root@linux-node2 html]# cd admin/
[root@linux-node2 admin]# vim info.php
<?php
phpinfo();
?>

# 访问
http://10.0.0.251/admin/info.php

访问admin的时候输入用户名和密码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
[root@linux-node2 admin]# vim /etc/httpd/conf/httpd.conf 

<Directory "/var/www">
AllowOverride None
# Allow open access:
Require all granted
</Directory>

<Directory "/var/www/html/admin">
Options Indexes FollowSymLinks
AllowOverride All
Order allow,deny
Allow from all
AuthName "sys"
AuthType Basic
AuthUserFile /etc/httpd/conf/httppwd_file
require user admin
</Directory>

[root@linux-node2 admin]# systemctl restart httpd

# 访问
http://10.0.0.251/admin/info.php

修改状态文件

1
2
3
4
5
6
7
8
9
10
11
12
[root@linux-node1 web]# vim /srv/salt/base/web/files/httpd.conf

<Directory "/var/www/html/admin">
Options Indexes FollowSymLinks
AllowOverride All
Order allow,deny
Allow from all
AuthName "sys"
AuthType Basic
AuthUserFile /etc/httpd/conf/httppwd_file
require user admin
</Directory
1
2
3
4
5
# 保证要有用到的命令
[root@linux-node2 admin]# whereis htpasswd
htpasswd: /usr/bin/htpasswd /usr/share/man/man1/htpasswd.1.gz
[root@linux-node2 admin]# rpm -qf /usr/bin/htpasswd
httpd-tools-2.4.6-90.el7.centos.x86_64

状态判断 unless

1
2
3
# 很多命令只需要执行一次,unless 通过判断 0 和 1 
# 包httpd-tools 被下面的cmd.run使用,如果包不安装成功,下面的命令也不执行,因为apache-auth只有一个 cmd
# unless 如果条件为真0,那么cmd.run就不执行
1
2
3
4
5
6
7
8
apache-auth:
pkg.installed:
- name: httpd-tools
- require_in:
- cmd: apache-auth
cmd.run:
- name: /usr/bin/htpasswd -bc /etc/httpd/conf/httppwd_file admin admin
- unless: test -f /etc/httpd/conf/httppwd_file
1
2
3
4
5
6
7
# 执行测试
[root@linux-node1 web]# salt 'linux-node2' state.sls web.lamp test=True
[root@linux-node1 web]# salt 'linux-node2' state.sls web.lamp

#访问:
http://10.0.0.251/admin/info.php
admin/admin

lamp.sls 最终版

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@linux-node1 web]# vim lamp.sls 

lamp-install:
pkg.installed:
- pkgs:
- httpd
- php
- php-pdo
- php-mysql
- php-cli
- php-common
- mariadb
- mariadb-server

apache-config:
file.managed:
- name: /etc/httpd/conf/httpd.conf
- source: salt://web/files/httpd.conf
- user: root
- group: root
- mode: 644
- require:
- pkg: lamp-install

apache-conf:
file.recurse:
- name: /etc/httpd/conf.d
- source: salt://web/files/apache-conf.d
- watch_in:
- service: httpd-service

apache-auth:
pkg.installed:
- name: httpd-tools
- require_in:
- cmd: apache-auth
cmd.run:
- name: /usr/bin/htpasswd -bc /etc/httpd/conf/httppwd_file admin admin
- unless: test -f /etc/httpd/conf/httppwd_file

/etc/profile:
file.append:
- text:
- "#Redis_PATH=''"

php-config:
file.managed:
- name: /etc/php.ini
- source: salt://web/files/php.ini
- user: root
- group: root
- mode: 644

mysql-config:
file.managed:
- name: /etc/my.cnf
- source: salt://web/files/my.cnf
- user: root
- group: root
- mode: 644

httpd-service:
service.running:
- name: httpd
- enable: True
- reload: True
- watch:
- file: apache-config

mariadb-service:
service.running:
- name: mariadb
- enable: True

源码安装 Tomcat和 JDK

  • 需求:判断minion有没有安装jdk和tomcat,没有就分别源码安装,并以普通用户启动。

上传软件包

1
2
3
4
5
6
7
8
[root@linux-node1 tools]# pwd
/srv/salt/base/web/tools
[root@linux-node1 tools]# tree
.
├── apache-tomcat-8.0.27.tar.gz
└── jdk-8u60-linux-x64.tar.gz

0 directories, 2 files
1
2
3
4
5
# 安装执行步骤
将安装包传递到指定的目录
解压
添加环境变量
启动服务

编写 tomcat.sls

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@linux-node1 web]# mkdir tools
[root@linux-node1 web]# vim tomcat.sls

jdk-install:
file.managed:
- name: /data/tools/jdk-8u60-linux-x64.tar.gz
- source: salt://web/tools/jdk-8u60-linux-x64.tar.gz
- user: root
- group: root
- made: 755
cmd.run:
- name: cd /data/tools/ && tar -zxf jdk-8u60-linux-x64.tar.gz && chown -R root:root jdk1.8.0_60 && mv jdk1.8.0_60 /data/ && ln -s /data/jdk1.8.0_60 /data/jdk
- require:
- file: jdk-install
- unless: test -L /data/jdk && test -d /data/jdk1.8.0_60

jdk-config:
file.append:
- name: /etc/profile
- text:
- '#JDK-ENV:'
- JAVA_HOME=/data/jdk
- PATH=$JAVA_HOME/bin:$JAVA_HOME/jre/bin:$PATH
- CLASSPATH=.$CLASSPATH:$JAVA_HOME/lib:$JAVA_HOME/jre/lib:$JAVA_HOME/lib/tools.jar
- export PATH JAVA_HOME CLASSPATH
cmd.run:
- name: source /etc/profile
- require:
- file: jdk-config
- unless: source /etc/profile && java -version

tomcat-install:
file.managed:
- name: /data/tools/apache-tomcat-8.0.27.tar.gz
- source: salt://web/tools/apache-tomcat-8.0.27.tar.gz
- user: root
- group: root
- made: 755
cmd.run:
- name: cd /data/tools/ && tar -zxf apache-tomcat-8.0.27.tar.gz && chown -R root:root apache-tomcat-8.0.27 && mv apache-tomcat-8.0.27 /data/ && ln -s /data/apache-tomcat-8.0.27 /data/tomcat
- require:
- file: tomcat-install
- unless: test -L /data/tomcat && test -d /data/apache-tomcat-8.0.27

tomcat-start:
cmd.run:
- name: source /etc/profile && /bin/bash /data/tomcat/bin/startup.sh
- require:
- file: tomcat-install
- unless: ps -ef | grep tomcat|grep -v 'grep'

grains 和 pillar 数据收集

grains 收集静态数据

Grains是saltstack的组件,用于收集salt-minion在启动时候的信息,又称为静态信息。
Grains是服务器的一系列粒子信息,也就是服务器的一系列物理,软件环境信息。
在执行salt的sls时候可以根据Grains信息的不同对服务器进行匹配分组,例如可以根据系统是centos服务器跟系统是redhat环境的安装不同的软件包。

  • 功能:
  1. 负责minion第一次启动的时候采集的静态数据,可以用在salt的模块和其他组件中。每次的minion启动(重启)的时候都会采集。
  2. 收集资产信息,信息查询
  3. 静态数据,当Minion启动的时候收集的MInion本地的相关信息。(包含操作系统版本、内核版本、CPU、内存、硬盘、设备型号等)
    备注:不重启minion,这些信息数据是不会改变的。
1
2
3
Grains可以在state系统中使用,用于配置管理模块
Grains可以target中使用,在用来匹配Minion,比如匹配操作系统使用-G选项
Grains可以用于信息查询,Grains保存着收集到的客户端的详细信息

目标选择

1
2
3
4
5
6
7
8
9
# grains 匹配所有CentOS的机器 执行test.ping 
[root@linux-node1 ~]# salt -G 'os:CentOS' test.ping

# grains
[root@linux-node1 ~]# salt -G 'os:CentOS' cmd.run "date"
linux-node1:
Wed Oct 2 21:31:14 CST 2019
linux-node2:
Wed Oct 2 20:59:05 CST 2019

信息采集

1
2
3
4
salt 'linux-node2' grains.ls      # 列出ID为linux-node2的主机,grains的所有key
salt 'linux-node2' grains.items # 列出主机的详细信息,可用于资产管理
salt '*' grains.item os # 列出所有主机的系统版本
salt '*' grains.item fqdn_ip4 # 列出所有主机的IP地址
1
2
3
4
5
6
7
8
9
10
11
12
13
# 需要配置好 vim /etc/hosts 主机名与IP解析
cat /etc/salt/minion_id
cat /etc/hosts

[root@linux-node1 ~]# salt '*' grains.item fqdn_ip4
linux-node1:
----------
fqdn_ip4:
- 10.0.0.250
linux-node2:
----------
fqdn_ip4:
- 10.0.0.251

jinja2 模板

1
2
3
4
5
文档:http://docs.jinkan.org/docs/jinja2/
Jinja2的应用场景:针对不同的操作系统安装软件,针对不同的cpu数量、内存等动态生成软件的配置文件,都需要Jinja2以及Grains和pillar的辅助
Jinja2是一个强大的python模板引擎,他的设计思想来源于Django的模板引擎,并扩展了其语法和一系列强大的功能。其中最显著的一个是增加了沙箱执行功能和可选的自动转义功能,这对大多应用的安全性来说是非常重要的。
jinja模板包含 变量 或 表达式,两种分隔符: {% ... %} 和 {{ ... }} 。前者用于执行诸如 for 循环 或赋值的语句,后者把表达式的结果打印到模板上。
salt中如何使用jinja2:https://docs.saltstack.com/en/latest/topics/jinja/index.html

使用 jinja2 和 grains

  • 修改配置文件httpd 本机IP:PORT
1
2
3
4
5
6
7
8
9
10
11
12
13
14
[root@linux-node1 web]# vim lamp.sls 
apache-config:
file.managed:
- name: /etc/httpd/conf/httpd.conf
- source: salt://web/files/httpd.conf
- user: root
- group: root
- mode: 644
- template: jinja
- defaults:
PORT: 9090
IPADDR: {{ grains['fqdn_ip4'][0] }}
- require:
- pkg: lamp-install
1
2
3
4
[root@linux-node1 web]# vim files/httpd.conf
/80
#Listen 12.34.56.78:80
Listen {{ IPADDR }}:{{ PORT }}
1
2
3
[root@linux-node1 web]# salt 'linux-node2' state.sls web.lamp
# 验证访问:
http://10.0.0.251:9090/

日常管理

生产建议

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
1. 不建议使用salt的FILE模块进行代码部署
1. 命令编排的状态管理:
压缩包, file.managed
cmd.run 执行部署

2. 配置管理,不建议使用salt管理项目的配置文件
1. 分层管理,salt只管理应用服务,例如Nginx Tomcat Apache
2. 开发的配置文件 不管

3. 如果你有固定的文件服务器,可以使用 source: salt:// http:// ftp://

4. SLS版本化
1. 创建一个git项目
2. 找一个测试环境,编写SLS, 测试git commit && git push到版本仓库
3. 生产环境git pull 测试,全部执行
4. 保留操作记录
5. 完整可控:谁 什么时间 干了什么 输出是什么

5. 使用Master Job Cache 保存job的输出到SQL
1. 保存在
[root@linux-node1 web]# cd /var/cache/salt/master/jobs/
2. 保存时长:
***** 默认24小时
vim /etc/salt/master
Set the number of hours to keep old job information in the job cache:
#keep_jobs: 24

include

  • 功能:有时候我们写了很多的sls文件,这些文件可以被复用

备份

1
[root@linux-node1 salt]# zip -r base.zip base/

复制lamp中安装部分,写到httpd.sls里面

1
2
3
4
5
6
7
8
9
10
11
12
13
[root@linux-node1 web]# vim httpd.sls

lamp-install:
pkg.installed:
- pkgs:
- httpd
- php
- php-pdo
- php-mysql
- php-cli
- php-common
- mariadb
- mariadb-server
1
2
3
4
5
6
# 修改lamp.sls,引入
[root@linux-node1 web]# vim lamp.sls

include:
- web.httpd
...
1
2
# 执行
[root@linux-node1 web]# salt 'linux-node2' state.sls web.lamp test=True

常用命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 查看状态
salt-run manage.status

# 查看版本
salt-run manage.versions

# 测试
salt '*' state.sls web.tomcat test=true

# 修改minion_id
1. 停止minion服务
2. salt-key -d minion_id 删除 minion
3. rm -f /etc/salt/minion_id
4. rm -rf /etc/salt/pki
5. 修改配置文件ID
6. 启动minio

无 master 架构

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
1. salt本地管理

2. masterless架构
1. 没有master,相当于单机使用
2. salt 本地来执行

3. 在node1测试
1. 修改配置文件
[root@CentOS7 ~]# vim /etc/salt/minion
/file_client
#file_client: remote 修改成
file_client: local

2.把file_root 加进来到node1的minion配置
file_roots:
base:
- /srv/salt/base
dev:
- /srv/salt/dev
test:
- /srv/salt/test
prod:
- /srv/salt/prod

3. 关闭minion服务
[root@linux-node1 web]# systemctl stop salt-minion

4. 执行状态 salt-call
[root@linux-node1 web]# salt-call --local state.sls web.tomcat
# --local 在本地

5. 用于单台服务器安装软件执行
1. 网络不允许上外网,只能本地安装
2. 安装saltstack
3. 把状态文件解压
4. 执行命令
5. 查看安装状态

日志入库 job cache

1
2
job cache:
https://docs.saltstack.com/en/latest/ref/returners/all/salt.returners.mysql.html#module-salt.returners.mysql

安装mysql,建库建表

1
2
3
4
5
6
7
8
9
10
[root@linux-node1 base]# yum -y install mariadb mariadb-server mariadb-client
[root@linux-node1 base]# systemctl start mariadb
[root@linux-node1 base]# systemctl enable mariadb

# 初始化
[root@linux-node1 base]# mysql_secure_installation

# 创建用户
MariaDB [(none)]> grant all on salt.* to salt@10.0.0.250 identified by 'salt';
MariaDB [(none)]> flush privileges;
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
# 建库建表语句

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;
CREATE INDEX jid ON jids(jid) USING BTREE;

--
-- 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,
`alter_time` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
KEY `id` (`id`),
KEY `jid` (`jid`),
KEY `fun` (`fun`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

--
-- Table structure for table `salt_events`
--

DROP TABLE IF EXISTS `salt_events`;
CREATE TABLE `salt_events` (
`id` BIGINT NOT NULL AUTO_INCREMENT,
`tag` varchar(255) NOT NULL,
`data` mediumtext NOT NULL,
`alter_time` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
`master_id` varchar(255) NOT NULL,
PRIMARY KEY (`id`),
KEY `tag` (`tag`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
1
2
3
4
5
6
7
8
9
10
11
12
[root@linux-node1 base]# mysql -h 10.0.0.250 -usalt -psalt
MariaDB [(none)]> use salt

MariaDB [salt]> show tables;
+----------------+
| Tables_in_salt |
+----------------+
| jids |
| salt_events |
| salt_returns |
+----------------+
3 rows in set (0.00 sec)

安装 MySQL-python

1
[root@linux-node1 base]# yum install -y MySQL-python

配置 master

1
2
3
4
5
6
7
8
9
[root@linux-node1 base]# vim /etc/salt/master
# 在文档最底下添加

master_job_cache: mysql
mysql.host: '10.0.0.250'
mysql.user: 'salt'
mysql.pass: 'salt'
mysql.db: 'salt'
mysql.port: 3306
1
2
# 重启服务
[root@linux-node1 base]# systemctl restart salt-master

执行 test.ping 查看cache 是否入库

1
2
3
4
5
6
7
8
9
[root@linux-node1 base]# salt '*' test.ping
linux-node1:
True
linux-node2:
True

[root@linux-node1 base]# mysql -h 10.0.0.250 -usalt -psalt
MariaDB [(none)]> use salt
MariaDB [salt]> select * from salt_returns\G;
1
2
3
4
5
# 显示 jid 执行
[root@linux-node1 base]# salt '*' cmd.run 'w' -v
Executing job with jid 20191006000128231437

MariaDB [salt]> select * from salt_returns where jid = '20191006000128231437'\G;

kill salt 正在执行的任务

1
2
https://www.cnblogs.com/shhnwangjian/p/6048891.html
https://docs.saltstack.com/en/latest/ref/modules/all/salt.modules.saltutil.html#module-salt.modules.saltutil
1
2
3
4
5
6
7
8
salt '*' saltutil.running  # 查看正在运行的任务,找到jid
salt '*' saltutil.kill_job jid # 根据jid杀掉任务
salt '*' saltutil.clear_cache # 清除minion缓存

备注:

1)正在执行的salt任务,job id会存在minion端的/var/cache/salt/minion/proc目录下
2)正在执行的salt任务,根据上面master cache的配置,Job的路径/var/cache/salt/master/jobs目录下

二次开发建议

1
2
3
1. master job cache 将所有的job输出保存到mysql
2. 如果做管理平台,可以将user_id 和 jid 关联
3. 使用List做目标选择

案例实战 zabbix-agent

定义安装目录

1
[root@linux-node1 base]# mkdir -p  init zabbix logstash

init epel源

创建目录获取yum文件

1
2
[root@linux-node1 base]# mkdir -p /srv/salt/base/init/files
[root@linux-node1 files]# wget http://mirrors.aliyun.com/repo/epel-7.repo

编写 yum-repo.sls

1
2
3
4
5
6
7
8
9
[root@linux-node1 init]# vim yum-repo.sls

epel-7.repo:
file.managed:
- name: /etc/yum.repos.d/epel-7.repo:
- source: salt://init/files/epel-7.repo
- user: root
- group: root
- mode: 644

zabbix-agent

模拟安装

1
2
3
[root@linux-node1 files]# yum list|grep zabbix
[root@linux-node1 files]# yum list|grep zabbix30-agent
[root@linux-node1 files]# yum install -y zabbix30-agent

模板文件

1
2
3
4
5
6
[root@linux-node1 file]# mkdir -p /srv/salt/base/zabbix/file
[root@linux-node1 file]# cp /etc/zabbix/zabbix_agentd.conf ./

[root@linux-node1 file]# vim zabbix_agentd.conf
Server={{ SERVER_IP }}
Hostname={{ AGENT_HOSTNAME }}

测试获取主机名

1
2
3
4
5
6
7
8
9
[root@linux-node1 file]# salt '*' grains.item fqdn
linux-node1:
----------
fqdn:
linux-node1
linux-node2:
----------
fqdn:
linux-node2

编写 zabbix-agent.sls

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
[root@linux-node1 zabbix]# cd /srv/salt/base/zabbix/
[root@linux-node1 zabbix]# vim zabbix-agent.sls

include:
- init.yum-repo # 引入epel源

zabbix-agent:
pkg.installed:
- name: zabbix30-agent
- require:
- file: epel-7.repo # 依赖

file.managed:
- name: /etc/zabbix_agentd.conf
- source: salt://zabbix/files/zabbix_agentd.conf
- user: root
- group: root
- mode: 644
- require:
- pkg: zabbix-agent
- template: jinja
- defaults:
SERVER_IP: 10.0.0.250
AGENT_HOSTNAME: {{ grains['fqdn'] }}
- require:
- pkg: zabbix-agent # 依赖,pkg安装后才能执行

service.running:
- name: zabbix-agent
- enable: True
- watch:
- pkg: zabbix-agent
- file: zabbix-agent # 文件有变化就重启

zabbix_agent.conf.d:
file.directory:
- name: /etc/zabbix_agent.conf.d
- watch_in:
- service: zabbix-agent # 目录有变化了就重启
- require:
- file: zabbix-agent # 依赖,需要安装和文件都执行才能执行
- pkg: zabbix-agent
1
2
3
[root@linux-node1 zabbix]# salt 'linux-node2' state.sls zabbix.zabbix-agent test=True
[root@linux-node1 zabbix]# salt 'linux-node2' state.sls zabbix.zabbix-agent
[root@linux-node1 zabbix]# salt 'linux-node2' cmd.run 'netstat -tnlp'

编译安装 redis

创建目录

1
2
3
4
5
6
7
8
9
10
11
12
[root@linux-node1 redis]# mkdir -p /srv/salt/prod/modules/{apache,haproxy,keepalived,mysql,redis}
[root@linux-node1 prod]# tree
.
└── modules
├── apache
├── haproxy
├── keepalived
├── mysql
└── redis
├── files
│   └── redis-4.0.14.tar.gz
└── redis-install.sls

编辑基础安装文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[root@linux-node1 redis]# vim redis-install.sls 

redis-source.install:
file.managed:
- name: /data/tools/redis-4.0.14.tar.gz
- source: salt://modules/redis/files/redis-4.0.14.tar.gz
- user: root
- group: root
- mode: 644
cmd.run:
- name: cd /data/tools/ && tar xzf redis-4.0.14.tar.gz && cd redis-4.0.14 && make >>/dev/null && make install >>/dev/null && mv /data/tools/redis-4.0.14 /data/redis
- require:
- file: redis-source.install
- unless: test -d /data/redis || test -d /data/redis_7006

redis安装

  1. 根据需求进行安装,可以使单机、主从也可以是集群
  2. 只需要导入基础的安装,再进行相应的配置启动就可以了
  3. 实现创建好目录和基础配置文件,做好模板
1
2
3
[root@linux-node1 redis]# mkdir -p /srv/salt/prod/redis/files
# 清理注释并改名
[root@linux-node1 files]# egrep -v '#|^$' /root/redis.conf >/srv/salt/prod/redis/files/redis-7006.conf
1
2
3
4
5
6
7
8
9
10
11
# 模板 比如单机安装的时候我们选择7006为端口
[root@linux-node1 files]# vim redis-7006.conf

bind 0.0.0.0
port {{ PORT }}
daemonize yes
pidfile /data/redis_{{ PORT }}/redis_{{ PORT }}.pid
logfile /data/redis_{{ PORT }}/logs/redis_{{ PORT }}.log
dbfilename dump_{{ PORT }}.rdb
dir /data/redis_{{ PORT }}/data
requirepass 123456
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
[root@linux-node1 redis]# vim redis-server.sls 

include:
- modules.redis.redis-install

redis-init:
cmd.run:
- name: cd /data && mv redis redis_7006 && mkdir -p /data/redis_7006/{conf,logs,data}
- unless: test -d /data/redis_7006
- require:
- cmd: redis-source.install

redis-server:
file.managed:
- name: /data/redis_7006/conf/redis-7006.conf
- source: salt://redis/files/redis-7006.conf
- user: root
- group: root
- mode: 755
- template: jinja
- defaults:
PORT: 7006
cmd.run:
- name: redis-server /data/redis_7006/conf/redis-7006.conf
- require:
- file: redis-server
- unless: ps -ef | grep redis|grep -v 'grep'
1
2
3
# 测试执行
[root@linux-node1 prod]# salt 'linux-node2' state.sls redis.redis-server saltenv=prod test=True
[root@linux-node1 prod]# salt 'linux-node2' state.sls redis.redis-server saltenv=prod

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[root@linux-node1 prod]# tree
.
├── modules # 基础软件安装模块
│   ├── apache
│   ├── haproxy
│   ├── keepalived
│   ├── mysql
│   └── redis
│   ├── files
│   │   └── redis-4.0.14.tar.gz
│   └── redis-install.sls # 只有安装软件,也可以加上源码安装
└── redis # 需求模块
├── files
│   └── redis-7006.conf
└── redis-server.sls # inclued 安装即可 配置文件 启动

参考学习

1
2
https://github.com/unixhot
https://github.com/unixhot/saltbook-code/tree/master/salt/pro

salt-ssh

1
2
3
4
1.salt-ssh 是 0.17.0 新引入的一个功能,不需要minion对客户端进行管理,也不需要master。
2.salt-ssh 支持salt大部分的功能:如 grains、modules、state 等
3.salt-ssh 没有使用ZeroMQ的通信架构,执行是串行模式
类似 paramiko、pssh、ansible 这类的工具
1
2
3
没有minion如何使用salt,通过salt-ssh
实际上就是把salt基础的 放在客户端的/tmp 然后在本地执行,执行完成后删除
写个脚本 发到客户端 执行 将结果返回
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
salt-ssh需要一个名单系统来确定哪些执行目标,Salt的0.17.0版本中salt-ssh引入roster系统
roster系统编译成了一个数据结构,包含了targets,这些targets是一个目标系统主机列表和或如连接到这些targets

# target的信息

host: # 远端主机的ip地址或者dns域名

user: # 登录的用户

passwd: # 用户密码,如果不使用此选项,则默认使用秘钥方式

# 可选的部分

port: # ssh端口

sudo: # 可以通过sudo

tty: # 如果设置了sudo,设置这个参数为true

priv: # ssh秘钥的文件路径

timeout: # 当建立链接时等待响应时间的秒数

minion_opts: # minion的位置路径

thin_dir: # target系统的存储目录,默认是/tmp/salt-<hash>

cmd_umask: # 使用salt-call命令的umask值

安装

1
2
3
4
# 没有minion如何使用salt,通过salt-ssh,客户端关闭minion
systemctl stop salt-minion
# 安装salt-ssh,master也是要有的,客户端需要支持ssh,python也要统一版本,生产 = python虚拟环境
yum install -y salt-ssh
1
2
3
4
5
6
7
8
9
10
11
12
# 定义配置主机: salt-ssh是串行,没有C/S 快
liunx-node1:
host: 10.0.0.251
user: root
password: 222222
port: 22

CentOS7:
host: 10.0.0.252
user: root
password: 222222
port: 2

执行

1
2
3
[root@linux-node1 salt]# salt-ssh '*' test.ping -i 
[root@linux-node1 salt]# salt-ssh '*' -r 'w'
[root@linux-node1 salt]# man salt-ss

总结

1
2
3
4
5
6
7
8
9
10
11
1.salt-ssh 是在salt基础上打了一个python包上传到客户端的默认tmp目录下

在客户端上面解压并执行返回结果,最后删除tmp上传的临时文件

2.salt-minion方法是salt-mater先执行语法验证,验证通过后发送到minion

minion收到Msater的状态文件默认保存在/var/cache/salt/minion

注意:也有时候salt-master语法验证通过,在minion上可能因为环境问题会执行失败

3.salt-ssh和salt-minion可以共存,salt-minion不依赖于ssh服务

salt-api

  • 使用条件:1)https调用,或者需要生成证书 2)配置文件 3)使用PAM验证 4)启动salt-api
    1
    2
    https://www.unixhot.com/docs/saltstack/topics/api.html
    https://www.unixhot.com/docs/saltstack/ref/netapi/all/salt.netapi.rest_cherrypy.html#a-rest-api-for-salt

安装

1
2
3
[root@linux-node1 salt]# yum install -y salt-api
[root@linux-node1 salt]# rpm -qa|grep cherry
python-cherrypy-3.2.2-4.el7.noarch

生成证书

1
2
3
4
[root@linux-node1 salt]# yum install pyOpenSSL -y
[root@linux-node1 salt]# salt-call --local tls.create_self_signed_cert
[ERROR ] You should upgrade pyOpenSSL to at least 0.14.1 to enable the use of X509 extensions
local: Created Private Key: "/etc/pki/tls/certs/localhost.key." Created Certificate: "/etc/pki/tls/certs/localhost.crt."

编辑配置文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
[root@linux-node1 salt]# vim master 
# Include a config file from some other path:
include: master.d/*.conf

[root@linux-node1 salt]# mkdir master.d
[root@linux-node1 master.d]# vim api.conf
rest_cherrypy:
host: 10.0.0.251
port: 8000
ssl_crt: /etc/pki/tls/certs/localhost.crt
ssl_key: /etc/pki/tls/certs/localhost.key

[root@linux-node1 redis-cluster]# useradd -M -s /sbin/nologin saltapi
[root@linux-node1 redis-cluster]# echo "saltapi" | passwd saltapi --stdin
[root@linux-node1 master.d]# vim auth.con
external_auth:
pam:
saltapi:
- .*
- '@wheel'
- '@runner'
- '@jobs
1
2
3
4
5
[root@linux-node1 master.d]# systemctl restart salt-master
[root@linux-node1 master.d]# systemctl start salt-api

[root@linux-node1 master.d]# netstat -tnlp|grep 8000
tcp 0 0 10.0.0.251:8000 0.0.0.0:* LISTEN 6866/python
1
2
3
4
5
curl -sSk https://10.0.0.251:8000/login \
-H 'Accept: application/x-yaml' \
-d username='saltapi' \
-d password='saltapi' \
-d eauth='pam'
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[root@linux-node1 master.d]# curl -sSk https://10.0.0.251:8000/login \
> -H 'Accept: application/x-yaml' \
> -d username='saltapi' \
> -d password='saltapi' \
> -d eauth='pam'
return:
- eauth: pam
expire: 1570315348.575254
perms:
- .*
- '@wheel'
- '@runner'
- '@jobs'
start: 1570272148.575253
token: 596b2306cc374d7c2f228bee381cfa80031d2fd6
user: saltapi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
[root@linux-node1 master.d]# systemctl restart salt-minion

curl -sSk https://10.0.0.251:8000 \
-H 'Accept: application/x-yaml' \
-H 'X-Auth-Token: 596b2306cc374d7c2f228bee381cfa80031d2fd6'\
-d client=local \
-d tgt='*' \
-d fun=test.ping

[root@linux-node1 master.d]# curl -sSk https://10.0.0.251:8000 \
> -H 'Accept: application/x-yaml' \
> -H 'X-Auth-Token: 596b2306cc374d7c2f228bee381cfa80031d2fd6'\
> -d client=local \
> -d tgt='*' \
> -d fun=test.ping
return:
- CentOS7: true
linux-node1.example.com: true

Master高可用

多master

1
https://www.unixhot.com/docs/saltstack/topics/tutorials/multimaster.html
1
2
3
4
5
6
7
8
master 配置文件相同
master file_roots 一样
同步master的公钥和私钥
minion 配置文件都是双机
systemctl restart salt-minion
node2 做认证 salt-key -A
别忘记安装MySQL-python 还有 mysql的登录授权给node2
grant all on salt.* to salt@10.0.0.252 identified by 'salt'