一、SaltStack介绍
SaltStack是一种新的基础设施管理方法开发软件,简单易部署,可伸缩的足以管理成千上万的服务器,和足够快的速度控制,与他们交流,以毫秒为单位。SaltStack提供了一个动态基础设施通信总线用于编排,远程执行、配置管理等等。SaltStack项目于2011年启动,年增长速度较快,五年期固定基础设施编制和配置管理的开源项目。SaltStack社区致力于保持盐项目集中、友好、健康、开放。 简单来说它的两大基础功能就是:配置管理、远程命令执行。剩下就是根据你的需求自由组合,实现更复杂的功能和系统管理。
Salt是一种和以往不同的基础设施管理方法,它是建立在大规模系统高速通讯能力可以大幅提升的想法上。这种方法使得Salt成为一个强大的能够解决基础设施中许多特定问题的多任务系统。远程执行引擎是Salt的核心,它能够为多组系统创建高速、安全的双向通讯网络。基于这个通讯系统,Salt提供了一个非常快速、灵活并且容易使用的配置管理系统,称之为"Salt States"。
1.1 自动化运维工具
常用的自动化运维工具有:
- puppet
- ansible
- saltstack
此三款属同类工具,皆可用来提高运维管理的效率,但它们又各有优势,目前主流的自动化运维工具是ansible和saltstack。其中ansible无需安装客户端,这是其最大的优势,而saltstack则需要安装客户端工具,类似zabbix的agent。应用场景方面,ansible常用于小型企业,而saltstack则常用于中大型企业,因为ansible无法并行执行而saltstack可以并行。但不论其特点如何,本质上均属同类,所以只需要掌握一种即可轻松胜任运维工作。 可以将SaltStack理解为神笔马良的那只笔!
- puppet
特点: puppet与其他手工操作工具有一个最大的区别是 puppet的配置具有稳定性,因此你可以多次执行puppet,一旦你更新了你的配置文件,puppet就会根据配置文件来更改你的机器配置,通常每30分钟检查一次. puppet会让你的系统状态同配置文件所要求的状态保持一致. 比如你配置文件里面要求ssh服务必须开启. 假如不小心ssh服务被关闭了,那么下一次执行puppet的时候,puppet会发现这个异常,然后会开启 ssh 服务. 以使系统状态和配置文件保持一致.puppet就象一个魔术师,会让你的混乱的系统收敛到puppet配置文件所想要的状态.
- ansible
ansible是基于 paramiko 开发的,并且基于模块化工作,本身没有批量部署的能力。真正具有批量部署的是ansible所运行的模块, ansible只是提供一种框架。ansible不需要在远程主机上安装client/agents,因为它们是基于ssh来和远 程主机通讯的。ansible目前已经已经被红帽官方收购,是自动化运维工具中大家认可度最高的,并且上手容易,学习简单。是每位运维工程师必须掌握的技能之一\ ansible 特点 部署简单,只需在主控端部署Ansible环境,被控端无需做任何操作; 默认使用SSH协议对设备进行管理; 有大量常规运维操作模块,可实现日常绝大部分操作; 配置简单、功能强大、扩展性强; 支持API及自定义模块,可通过Python轻松扩展; 通过Playbooks来定制强大的配置、状态管理; 轻量级,无需在客户端安装agent,更新时,只需在操作机上进行一次更新即可; 提供一个功能强大、操作性强的Web管理界面和REST API接口——AWX平台
- saltstack
基于python开发的C/S架构配置管理工具 底层使用ZeroMQ消息队列pub/sub方式通信 使用SSL证书签发的方式进行认证管理,传输采用AES加密
此三款属同类工具,皆可用来提高运维管理的效率,但它们又各有优势,目前主流的自动化运维工具是ansible和saltstack。其中ansible无需安装客户端,这是其最大的优势,而saltstack则需要安装客户端工具,类似zabbix的agent。应用场景方面,ansible常用于小型企业,而saltstack则常用于中大型企业,因为ansible无法并行执行而saltstack可以并行。但不论其特点如何,本质上均属同类,所以只需要掌握一种即可轻松胜任运维工作。
1.1.1 选择Saltstack的原因
目前市场上主流的开源自动化配置公里工具有puppet、ansible、saltstack。为什么选择saltstack呢?
对比图:
对于puppet由于不支持二次开发,后续一些需求将无法满足,而且puppet有其复杂的、有将近10000行代码的代码库。而使用saltstack和ansible,用1000行左右的代码就能复制puppet的架构。
现在脱颖而出的是saltstack和ansible,再来看一下两者的比较:
一、易用性:
saltstack负载的文档结构和密集的文字,使得其学习曲线更为陡峭。虽然ansible的文档对初学者而言更简单易读,但随着项目规模的增大,saltstack的文档对开发者的帮助更大。深入分析配置文件(ansible中称为playbooks,saltstack称为stat definitions)突显了二者的区别。Saltstack保持了输入、输出、配置文件的一致性,所有文件均使用YAML格式,而ansible则使用不同的文件格式(INI、YAML)。循环和条件的实现方式也不同。ansible将逻辑部分内嵌在DSL中,而saltstack使用Jinja(一个python模板引擎)。
二、成熟度:
在成熟度方面,ansible和saltstack都能提供所有必要的性能和足够的成熟度。不过saltstack有更丰富的特性:可以以不同的文件格式输出到不同的位置;可以从不同的来源加载pillars(其本质是一种数据结构);如果以代理模式运行,可以通过reactor系统触发本地事件。
三:性能:
性能方面,saltstack速度更快,尤其是在no-change运行模式下:
在相同的应用场景下saltstack的运行速度远远快于ansible。
四、技术支持
在开发社区,saltstack更为友好,开发者数量也更多。
基于以上原因所以才选择saltstack。
1.1.2 saltstack的深入理解
SaltStack采用C/S模式,server端就是salt的master,client端就是minion,minion与master之间通过ZeroMQ消息队列通信minion上线后先与master端联系,把自己的pub key发过去,这时master端通过salt-key –L命令就会看到minion的key,接受该minion-key后,也就是master与minion已经互信master可以发送任何指令让minion执行了,salt有很多可执行模块,比如说cmd模块,在安装minion的时候已经自带了,它们通常位于你的python库中
这些模块是python写成的文件,里面会有好多函数,如cmd.run,当我们执行下图命令的时候
Master下发任务匹配到的minion上去,minion执行模块函数,并返回结果。Master监听4505和4506端口,4505对应的是ZMQ的PUB system,用来发送消息,4506对应的是REP system是来接受消息的。
系统架构图
一个基本的salt配置方式是一个master指挥一群minion,为了不再有假设使用任何单一拓扑结构,另外当minion数量达到2000以上以后salt的执行速度就会降低,在新的saltstack版本中有一个salt-syndic,主控master可以控制一群master,通过syndic将操作命令传输给受控master,受控master来完成对自己旗下minion的管理,并将结果传回主控master,从而实现了主控master对所有minion的间接管理。
目前采用的架构图如下:
1.2 saltstack的特点
- 基于python开发的C/S架构配置管理工具
- 底层使用ZeroMQ消息队列pub/sub方式通信
- 使用SSL证书签发的方式进行认证管理,传输采用AES加密
SaltStack特性
(1)、部署简单、方便; (2)、支持大部分UNIX/Linux及Windows环境; (3)、主从集中化管理; (4)、配置简单、功能强大、扩展性强; (5)、主控端(master)和被控端(minion)基于证书认证,安全可靠; (6)、支持API及自定义模块,可通过Python轻松扩展。
1.3 saltstack服务架构
在saltstack架构中服务器端叫Master,客户端叫Minion。
在Master和Minion端都是以守护进程的模式运行,一直监听配置文件里面定义的ret_port(接受minion请求)和publish_port(发布消息)的端口。
当Minion运行时会自动连接到配置文件里面定义的Master地址ret_port端口进行连接认证。
saltstack除了传统的C/S架构外,其实还有一种叫做masterless的架构,其不需要单独安装一台 master 服务器,只需要在每台机器上安装 Minion端,然后采用本机只负责对本机的配置管理机制服务的模式。
SaltStack的结构 saltstack采用C/S(客户端和server端)架构,salt-master为server端,salt-minion为客户端
a)Master与Minion认证 (1)、minion在第一次启动时,会在/etc/salt/pki/minion/(该路径在/etc/salt/minion里面设置)下自动生成minion.pem(private key)和 minion.pub(public key),然后将 minion.pub发送给master。
(2)、master在接收到minion的public key后,通过salt-key命令accept minion public key,这样在master的/etc/salt/pki/master/minions下的将会存放以minion id命名的 public key,然后master就能对minion发送指令了。
b)Master与minion链接 (1)、SaltStack master启动后默认监听4505和4506两个端口。4505(publish_port)为saltstack的消息发布系统,4506(ret_port)为saltstack客户端与服务端通信的端口。如果使用lsof 查看4505端口,会发现所有的minion在4505端口持续保持在ESTABLISHED状态。
1.4 SaltStack通讯机制
SaltStack采用C/S模式,minion与master之间通过**ZeroMQ消息队列【轻量级】**通信,默认监听端口是4505端口
Salt Master运行的第二个网络服务就是**ZeroMQ REP【请求响应】**系统,默认监听4506端口
master端口:4505
minion端口:4506
altStack的master端监听4505和4506端口。其中4505为Salt的消息发布系统,4506为Salt客户端与服务端通信的端口;\ Salt客户端程序不监听端口,客户端启动后,会主动连接master端注册,然后一直保持TCP连接;\ master通过该TCP连接对客户端进行控制,若断开,master也便无法控制客户端,但是当客户端检测到断开后会定期连接master端
1.5 ZeroMQ
ZeroMQ是一种基于消息队列的多线程网络库,其对套接字类型、连接处理、帧、甚至路由的底层细节进行抽象,提供跨越多种传输协议的套接字。
ZeroMQ是网络通信中新的一层,介于应用层和传输层之间,其是一个可伸缩层,可并行运行,分散在分布式系统间
1.6 传统运维与自动化运维区别
1.6.1 传统运维
- 传统运维效率低下且繁琐,大多工作人工完成,很容易出错
- 传统运维工作繁琐,很容易出错
- 传统运维每日重复做相同的事情
- 传统运维没有标准化的流程
- 传统运维的脚本繁多,不方便管理
1.6.2 自动化运维
Puppet:基于rubby开放,C/S架构,支持多平台,可管理配置文件、用户、cron任务、软件包、系统服务等。分为社区版和企业版,其中企业版支持图形化配置;【官网:https://puppet.com】\ \ SaltStack:基于Python开发,C/S架构,支持多平台,比Puppet清量,在远程执行命令时非常快捷,配置和使用比puppet容易,能实现puppet几乎所有的功能;【官网:https://saltstack.com】\ \ Ansible:更加简洁的自动化运维工具,不需要在客户端上安装客户端软件,基于Python开发的。可以实现批量操作系统配置、批量程序的部署、批量执行命令。【Ansible中文文档:http://www.ansible.com.cn】
1.7 SaltStack四大功能与四大运行方式
SaltStack有四大功能,分别是:
远程执行 配置管理/状态管理 云管理(cloud) 事件驱动
SaltStack可以通过远程执行实现批量管理,并且通过描述状态来达到实现某些功能的目的。
SaltStack四大运行方式:
local本地运行 Master/Minion传统方式 Syndic分布式 Salt ssh
二、SaltStack组件介绍
组件 | 功能 |
---|---|
Salt Master | 用于将命令和配置发送到在受管系统上运行的Salt minion |
Salt Minions | 从Salt master接收命令和配置 |
Execution Modules | 从命令行针对一个或多个受管系统执行的临时命令。对…有用: 1. 实时监控,状态和库存 2. 一次性命令和脚本 3. 部署关键更新 |
Formulas (States) | 系统配置的声明性或命令式表示 |
Grains | Grains是有关底层受管系统的静态信息,包括操作系统,内存和许多其他系统属性 |
Pillar | 用户定义的变量。这些安全变量被定义并存储在Salt Master中, 然后使用目标“分配”给一个或多个Minion。 Pillar数据存储诸如端口,文件路径,配置参数和密码之类的值 |
Top File | 将Formulas (States)和Salt Pillar数据与Salt minions匹配 |
Runners | 在Salt master上执行的模块,用于执行支持任务。Salt runners报告作业状态,连接状态,从外部API读取数据,查询连接的Salt minions等 |
Returners | 将Salt minions返回的数据发送到另一个系统,例如数据库。Salt Returners可以在Salt minion或Salt master上运行 |
Reactor | 在SaltStack环境中发生事件时触发反应 |
Salt Cloud / Salt Virt | 在云提供商/虚拟机管理程序上提供系统,并立即将其置于管理之下 |
Salt SSH | 在没有Salt minion的系统上通过SSH运行Salt命令 |
2.1 SaltStack Master
中央管理系统(服务端):用来发送命令和配置到SaltStack Minion上运行
2.2 SaltStack Minion
接受管理系统(客户端):用来接收来自SaltStack Master命令和配置
2.3 Salt具体步骤
1、SaltStack的master与minion之间通过ZeroMQ来进行消息传递,使用了ZeroMQ的发布-订阅模式,连接方式包括:TCP、IPC。\ 2、Salt命令其中以ls为例。将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执行结果,将结果输出到终端。
2.4 saltstack配置文件
saltstack的配置文件在/etc/salt目录
saltstack配置文件说明:
配置文件 | 说明 |
---|---|
/etc/salt/master | 主控端(控制端)配置文件 |
/etc/salt/minion | 受控端配置文件 |
配置文件/etc/salt/master默认的配置就可以很好的工作,故无需修改此配置文件
配置文件/etc/salt/minion常用配置参数
- master:设置主控端的IP
- id:设置受控端本机的唯一标识符,可以是ip也可以是主机名或自取某有意义的单词
在日常使用过程中,经常需要调整或修改Master节点的配置文件,SaltStack大部分配置都已经指定了默认值,只需根据自己的实际需求进行修改即可。下面的几个参数是比较重要的
max_open_files:可根据Master将Minion数量进行适当的调整 timeout:可根据Master和Minion的网络状况适当调整 auto_accept和autosign_file:在大规模部署Minion时可设置自动签证 master_tops和所有以external开头的参数:这些参数是SaltStack与外部系统进行整合的相关配置参数
三、SaltStack安装及部署
3.1 环境规划
系统版本: CentOS7.9.2009
主机类型 | IP | 要安装的应用 |
---|---|---|
控制机 | 10.0.0.20 | salt salt-cloud salt-master salt-minion salt-ssh salt-syndic salt-api |
被控机 | 10.0.0.21 | salt-minion |
被控机 | 10.0.0.22 | salt-minion |
3.2 配置yum仓库
所有节点都要配置
官方中文文档网站:http://docs.saltstack.cn/
官方安装配置教程: http://docs.saltstack.cn/topics/installation/rhel.html
配置YUM仓库【可以使用官网镜像,但较慢,这里我使用阿里云镜像仓库】
- 配置官网镜像仓库:
yum install -y https://repo.saltstack.com/yum/redhat/salt-repo-latest.el7.noarch.rpm
或者
yum install -y https://repo.saltstack.com/py3/redhat/salt-py3-repo-3001.el7.noarch.rpm
- 配置阿里云镜像仓库:
yum install -y https://mirrors.aliyun.com/saltstack/yum/redhat/salt-repo-latest-2.el7.noarch.rpm
# 补充: 配置Redhat8/CentOS8 仓库
#导入key,配置salt仓库
rpm --import https://repo.saltproject.io/py3/redhat/8/x86_64/latest/SALTSTACK-GPG-KEY.pub
curl -fsSL https://repo.saltproject.io/py3/redhat/8/x86_64/latest.repo | tee /etc/yum.repos.d/salt.repo
# 教程链接 https://mirrors.aliyun.com/saltstack/#rhel
3.3 主控端部署
#清除缓存
[root@master ~]# yum clean expire-cache
# 安装saltstack主控端
[root@master ~]# yum -y install salt salt-cloud salt-master salt-minion salt-ssh salt-syndic salt-api
# 修改主控端的minion配置文件 修改 #id和#master:salt 这两行 (注意书写规范:每个冒号后面都要跟一个空格)
# #master:salt 指向管理端地址,这里是指向salt-master服务器,可以是IP、域名或主机名
# #id minion主机标识必须唯一
[root@master ~]# sed -i 's/^#master: salt/master: 10.0.0.20/g' /etc/salt/minion #注意master:后的空格
[root@master ~]# sed -n '/^master:/p' /etc/salt/minion
master: 10.0.0.20
[root@master ~]# sed -i 's/^#id:/id: master/g' /etc/salt/minion #注意id:后的空格
[root@master ~]# sed -n '/^id:/p' /etc/salt/minion
id: master
# 启动salt-master与salt-minion
[root@master ~]# systemctl enable --now salt-master
[root@master ~]# systemctl enable --now salt-minion
#4505和4506都是salt-master的端口号,4505是publish_port 4506是ret_port
[root@master ~]# netstat -tlnp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 1024/sshd
tcp 0 0 0.0.0.0:4505 0.0.0.0:* LISTEN 1286/python3
tcp 0 0 0.0.0.0:4506 0.0.0.0:* LISTEN 1298/python3
3.4 被控制端安装、配置salt-minion
所有salt-minion节点都要操作
[root@node1 ~]# yum install -y salt-minion
[root@node1 ~]# sed -i 's/^#master: salt/master: 10.0.0.20/g' /etc/salt/minion #注意master:后有空格
[root@node1 ~]# sed -n '/^master:/p' /etc/salt/minion
master: 10.0.0.20
[root@node1 ~]# sed -i 's/^#id:/id: master/g' /etc/salt/minion #注意id:后的空格
[root@node1 ~]# sed -n '/^id:/p' /etc/salt/minion
id: node1
# 启动salt-minion
[root@node1 ~]# systemctl enable --now salt-minion
[root@node1 ~]# systemctl status salt-minion
● salt-minion.service - The Salt Minion
Loaded: loaded (/usr/lib/systemd/system/salt-minion.service; enabled; vendor preset: disabled)
Active: active (running) since 三 2021-08-18 09:46:58 CST; 2h 5min ago
# node2 被控端部署同上
3.5 salt-minion与salt-master认证过程
- minion在第一次启动时,会在/etc/salt/pki/minion/下自动生成一对密钥,然后将公钥发给master
- master收到minion的公钥后,通过salt-key命令接受该公钥。此时master的/etc/salt/pki/master/minions目录将会存放以minion id命名的公钥,然后master就能对minion发送控制指令了
master 秘钥对默认存储在/etc/salt/pki/master/master.pub /etc/salt/pki/master/master.pem master 端认证的公钥存储在:/etc/salt/pki/master/minions/ minion 秘钥对默认存储在/etc/salt/pki/minion/minion.pub /etc/salt/pki/minion/minion.pem minion 存放的master公钥/etc/salt/pki/minion/minion_master.pub minion_id 默认存储在/etc/salt/minion_id\ \若想修改minion名称,需删除原来的minion_id,重启重新生成一个minion_id**
# salt-key常用选项
-L 列出所有公钥信息
-a minion 接受指定minion等待认证的key
-A 接受所有minion等待认证的key
-r minion 拒绝指定minion等待认证的key
-R 拒绝所有minion等待认证的key
-f minion 显示指定key的指纹信息
-F 显示所有key的指纹信息
-d minion 删除指定minion的key
-D 删除所有minion的key
-y 自动回答yes
# 查看当前证书情况
[root@master ~]# salt-key -L
Accepted Keys:
Denied Keys:
Unaccepted Keys:
master
node1
node2
Rejected Keys:
# 接受指定minion的新证书
[root@master ~]# salt-key -a -y 'master'
The following keys are going to be accepted:
Unaccepted Keys:
master
Key for minion master accepted.
# 接受所有minion的新证书
[root@master ~]# salt-key -y -A
The following keys are going to be accepted:
Unaccepted Keys:
node1
node2
Key for minion minion accepted.
[root@master ~]# salt-key -L
Accepted Keys:
master
node1
node2
Denied Keys:
Unaccepted Keys:
Rejected Keys:
3.6 测试saltstack远程执行
# 测试所有受控端主机是否存活
# '*'表示所有目标机器 test.ping 只是模块里的一个功能,用来测试连通性
[root@master ~]# salt "*" test.ping
node1:
True
node2:
True
master:
True
# 测试指定受控端主机是否存活
[root@master ~]# salt "node1" test.ping
node1:
True
# 万能模块cmd.run 执行命令
[root@master ~]# salt 'node1' cmd.run 'hostname'
node1:
node1
# salt '*' cmd.run 'uptime'
# salt '*' cmd.run 'w'
命令: salt
目标: '*'
模块: cmd.run
返回: 执行后返回结果 Returnners
3.7 salt命令使用
# 语法:salt [options] '<target>' <function> [arguments]
# Salt命令主要由三个主要部分构成:salt '<target>' <function> [arguments]
target:指定哪些minion,默认的规则是使用glob匹配minion id # salt '*' test.ping
Targets也可以使用正则表达式 # salt -E 'server[1-3]' test.ping
Targets也可以指定列表 # salt -L 'server2,server3' test.ping
funcation:module提供的功能,Salt内置了大量有效的functions
arguments:通过空格来界定参数
# 常用的options
--version 查看saltstack的版本号
--versions-report 查看saltstack以及依赖包的版本号
-h 查看帮助信息
-c CONFIG_DIR 指定配置文件目录(默认为/etc/salt/)
-t TIMEOUT 指定超时时间(默认是5s)
--async 异步执行
-v verbose模式,详细显示执行过程
--username=USERNAME 指定外部认证用户名
--password=PASSWORD 指定外部认证密码
--log-file=LOG_FILE 指定日志记录文件
# 常用target参数
-E 正则匹配
-L 列表匹配
-S CIDR匹配网段
-G grains匹配
--grain-pcre grains加正则匹配
-N 组匹配
-R 范围匹配
-C 综合匹配(指定多个匹配)
-I pillar值匹配
# 示例
[root@master ~]# salt -E 'master*' test.ping
master:
True
[root@master ~]# salt -L master,node1 test.ping
node1:
True
master:
True
[root@master ~]# salt -S '10.0.0.21' test.ping
node1:
True
[root@master ~]# salt -S '10.0.0.0/8' test.ping
master:
True
node1:
True
node2:
True
# 【 匹配minion主机 与minion ID有关】
1 通配符
salt '*' test.ping
salt 'node*' test.ping
2 主机ID
salt 'node1' test.ping
salt -L 'master,node1,node2' test.ping
3 正则表达式
salt 'node[1|2]' test.ping
salt 'node[1-2]' test.ping
salt 'node[!2]' test.ping
salt -E 'node1|node2' test.ping
salt -E 'node(1|2)' test.ping
# 【与minion ID无关,通过grains或者pillar匹配目标主机】
常用命令如下:
# 1.测试连通
salt '*' test.ping
# '*'表示所有目标机器 test.ping 只是模块里的一个功能,用来测试连通性
# 2.常用命令结构
salt [options] ‘<目标机>’ <功能> [arguments]
# 例如:
#对机器node1使用w命令
test 'node1' cmd.run 'w'
# 3.常用命令
# salt-run
# 该命令执行runner(salt带的或者自定义的,runner以后会讲),通常在master端执行,比如经常用到的manage
salt-run [options] [runner.func]
salt-run manage.status ##查看所有minion状态
salt-run manage.down ##查看所有没在线minion
salt-run manged.up ##查看所有在线minion
# 4 安装软件
salt 'node1' pkg.install httpd
# 卸载软件
salt 'node1' pkg.remove httpd
# 5 测试
salt '*' test.echo 'hello'
salt '*' network.ping baidu.com # 使用ping命令测试到某主机的连通性
salt '*' network.connect baidu.com 80 # #测试minion至某一台服务器的网络是否连通
salt '*' network.get_hostname # 获取主机名
salt '*' network.active_tcp # 返回所有活动的tcp连接
salt '*' network.ip_addrs # 返回一个IPv4的地址列表
alt '*' network.get_fqdn # 查看主机的fqdn(完全限定域名)
# salt-key
# 密钥管理,通常在master端执行
salt-key [options]
salt-key -L ##查看所有minion-key
salt-key -a <key-name> ##接受某个minion-key
salt-key -d <key-name> ##删除某个minion-key
salt-key -A ##接受所有的minion-key
salt-key -D ##删除所有的minion-key
# salt-call
# 该命令通常在minion上执行,minion自己执行可执行模块,不是通过master下发job
salt-call [options] <function> [arguments]
salt-call test.ping ##自己执行test.ping命令
salt-call cmd.run 'ifconfig' ##自己执行cmd.run函数
# salt-cp
# 分发文件到minion上,不支持目录分发,通常在master运行
salt-cp [options] '<target>' SOURCE DEST
salt-cp '*' testfile.html /tmp
salt-cp 'node*' /opt/index.html /tmp/a.html
# 常用模块命令
salt '*' network.active_tcp # 查看tcp连接情况
salt '*' network.get_hostname # 查看主机名
salt '*' service.available sshd # 查看ssh服务是否可达
salt '*' service.get_all # 查看所有启动的服务
salt '*' service.status nginx # 查看指定服务是否在线
salt '*' state.show_top # 查看top_file情况
salt '*' state.single pkg.installed name=lsof # 安装lsof
# 查看模块文档
salt '*' sys.doc pkg #查看pkg模块文档
# salt内置的执行模块列表
http://docs.saltstack.cn/ref/modules/all/index.html
四、state.sls介绍及使用
state.sls SLS(代表SaLt State文件)是Salt State系统的核心。SLS描述了系统的目标状态,由格式简单的数据构成。这经常被称作配置管理。首先,在master上面定义salt的主目录,默认是在/srv/salt/下面。
sls文件命名:
sls文件以”.sls”后缀结尾,但在调用时是不需要写后缀的。
使用子目录来做组织是个很好的选择。
init.sls 在一个子目录里面表示引导文件,也就表示子目录本身, 所以``apache/init.sls`` 就是表示``apache``. 如果同时存在apache.sls 和 apache/init.sls,则 apache/init.sls 被忽略,apache.sls将被用来表示apache.
# 编辑master节点配置文件 vim /etc/salt/master
# 修改配置如下 注意空格缩进
file_roots:
base:
- /srv/salt
# 重启salt-master
systemctl restart salt-master
# 创建目录
mkdir -p /srv/salt
# cd /srv/salt/
4.1 yaml语法
由于SaltStack也是用python编写,默认的SLS文件的renderer是YAML rendere,因此也要使用yaml语法。
YAML是一个由很多强大特性的标记性语言。Salt使用了一个YAML的小型子集,用来映射常用的数据结构,像列表和字典。YAML renderer的工作就是将YAML数据格式的结构编译成为Python数据结构给Salt使用。
掌握三个规则即可使用YAML语法书写SLS文件
4.1.1 三个规则
- 规则一:缩进
YAML使用一个固定的缩进风格表示数据结构的层结构关系。Salt需要每个缩进级别由 两个空格 组成,若要使用Tab,先修改.vimrc来设置Tab的缩进格数。
- 规则二:冒号
Python的字典当然理所当然是简单的键值对。其他语言的用户应该知道这个数据类型叫哈希表或者关联数组。 字典的keys在YAML中的表现形式是一个以冒号结尾的字符串。Values的表现形式冒号下面的每一行,用一个空格隔开:\ my_key: my_value 在Python中,上面的将映射为: {'my_key': 'my_value'}\ 注解: 上面的语法是有效的YAML,但是在SLS文件罕见,因为通常情况下,一个key的value不是单一的,而是一个 列表 的values。 在Python中,上面的将映射为:{'my_key': 'my_value'} 字典可以被嵌套: first_level_dict_key: second_level_dict_key: value_in_second_level_dict 在Python中: { 'first_level_dict_key': { 'second_level_dict_key': 'value_in_second_level_dict' } }
- 规则三:短横杠
表示列表项:一个短横杠加一个空格,多项则使用同样缩进级别来作为同一列表的一部分
- list_value_one
- list_value_two
做键值对的value
my_dictionary:
- list_value_one
- list_value_two
在Python中,上面的映射关系可以书写为:
{'my_dictionary': ['list_value_one', 'list_value_two']}
4.2 编写sls文件
# 切换目录
# cd /srv/salt
常用模块
4.2.1 用户管理
# 1 添加用户 vim create_user.sls
# 创建用户
add-test-user: # 项目id,最好能见名知意,--推荐此方式写sls文件,让ID声明有意义
user.present: # 模块和方法
- name: test # 用户名
- home: /home/test # 用户的家目录
- shell: /bin/bash # 指定用的shell
- uid: 1001 # 用户UID
- gid: 1001 # 用户组GID
# 写法二
test: # 这里项目id就是用户名
user.present: # 模块和方法
- home: /home/test # 用户的家目录
- shell: /bin/bash # 指定用的shell
- uid: 1001 # 用户UID
- gid: 1001 # 用户组GID
# 命令行 salt '*' user.add name <uid> <gid> <groups> <home> <shell>
# 执行远程命令
[root@master /srv/salt]# salt 'node1' state.sls create_user
node1:
----------
ID: add-test-user
Function: user.present
Name: test
Result: True
Comment: New user test created
Started: 16:04:58.123286
Duration: 257.96 ms
Changes:
----------
fullname:
gid:
1001
groups:
- test
home:
/home/test
homephone:
name:
test
other:
passwd:
x
roomnumber:
shell:
/bin/bash
uid:
1001
workphone:
Summary for node3
------------
Succeeded: 1 (changed=1)
Failed: 0
------------
Total states run: 1
Total run time: 257.960 ms
# 2 删除用户 vim delete_user.sls
del_test:
user.absent:
- name: test
- purge: True
- force: True
#purge类似userdel -r force为用户在线也强制删除
[root@master /srv/salt 16:20:14]# salt 'node1' state.sls del_user
node1:
----------
ID: del_test
Function: user.absent
Name: test
Result: True
Comment: Removed user test
Started: 16:20:30.003342
Duration: 103.256 ms
Changes:
----------
test:
removed
test group:
removed
Summary for node3
------------
Succeeded: 1 (changed=1)
Failed: 0
------------
Total states run: 1
Total run time: 103.256 ms
# 查看user模块文档 salt '*' sys.doc user
4.2.2 包管理
# yum安装包 vim install_nginx.sls
# 安装单个包 方式1
nginx: # ID声明就是安装包的名称
pkg.installed # 状态声明
# 安装单个包 方式2
install-only-nginx: # ID声明
pkg.installed: # 状态声明
- name: nginx # 选项声明
salt 'node1' state.sls install_nginx
# 安装多个包 vim lnmp.sls
# 安装多个包 方式1
lnmp_config:
pkg.installed:
- pkgs:
- nginx
- mariadb
- mariadb-server
- python3
# 安装多个包 # 方式2
lnmp_config:
pkg.installed:
- names:
- nginx
- mariadb
- mariadb-server
- python3
salt 'node3' state.sls lnmp
4.2.3 服务状态管理
# 启动服务 设置开机启动
# vim start-nginx.sls
nginx:
pkg.installed
start-nginx:
service.running:
- name: nginx
# 设置开机启动
- enable: True
# 设置重新载入,当文件发生变化时,如果不设置reload,则会重启
- reload: True
# 监控服务是否安装
- watch:
- pkg: nginx
salt 'node1' state.sls start_nginx
# 示例2 安装多个服务并同时启动
# vim more-services.sls
install-services:
pkg.installed:
- pkgs:
- nginx
- mariadb
- mariadb-server
- redis
start-services:
service.running:
- names:
- nginx
- mariadb
- redis
# 设置开机启动
- enable: True
# 设置重新载入,当文件发生变化时,如果不设置reload,则会重启
- reload: True
# 监控服务是否安装
- watch:
- pkg: install-services
4.2.4 目录管理
# 创建目录 vim createdir.sls
create_testdir:
file.directory:
- name: /opt/salt_test
- user: root
- group: root
- file_mode: 644
- dir_mode: 755
- makedirs: True
- include_empty: True
- backup: minion
salt 'node1' state.sls createdir
4.2.5 逻辑关系
在/srv/salt/目录下创建webs目录
将前面创建的sls文件移动到webs目录中
webs/
├── append_java_config.sls
├── createdir.sls
├── create_user.sls
├── del_user.sls
├── install_nginx.sls
├── lnmp.sls
└── manage_nginx_conf.sls
# 1 继承(include) vim test_include.sls
include:
# 目录名.sls文件名(不带后缀)
- webs.install_nginx
- webs.createdir
- webs.lnmp
- webs.manage_nginx_conf
# include应用场景说明,例如部署lnmp/lamp时,把初始化系统,安装软件,修改配置等环节标准化,做成初始化系统模块,安装软件模块等,实现在其它项目中复用,这样就不用每次部署新环境时都要写重复sls文件内容
salt 'node1' state.sls test_include
# 2 依赖(require) 依赖某个state,在运行此state前,先运行依赖的state,依赖可以有多个
# vim test_require.sls
test_require:
pkg.installed:
- pkgs:
- nginx
- mariadb
- mariadb-server
- python3
setconfigfiles:
file.managed:
- name: /opt/nginx.conf
- source: salt://files/nginx.conf
- user: root
- group: root
- mode: 644
- backup: minion
- template: jinja
# 定义jinja模板引用的变量
- defaults:
port: 90
worker_connections: 10241
# 依赖nginx安装成功
- require:
- test_require
salt 'node1' state.sls test_require
# 3 监控(watch) 在某个state变化时运行此模块,文中的配置,相关文件变化后,立即执行相应操作
# vim test_watch.sls
install_lnmp:
pkg.installed:
- pkgs:
- nginx
- mariadb
- mariadb-server
- python3
setconfigfiles:
file.managed:
- name: /opt/nginx.conf
- source: salt://files/nginx.conf
- user: root
- group: root
- mode: 644
- backup: minion
- template: jinja
# 定义jinja模板引用的变量
- defaults:
port: 90
worker_connections: 10241
# 依赖nginx安装成功
- require:
- install_lnmp
show_files:
cmd.run:
- name: cat /opt/nginx.conf
- watch:
- pkg: install_lnmp
- file: setconfigfiles
salt 'node1' state.sls test_watch
# 4 顺序/优先级(order)
优先级比require和watch低,有order指定的state比没有order指定的优先级高,假如一个state模块内安装多个服务,或者其他依赖关系,可以使用。如果想让某个state最后执行,可以使用last。
# vim test_order.sls
nginx:
pkg.installed:
- order: 4
install-mariadb:
pkg.installed:
- order: 3
- pkgs:
- mariadb
- mariadb-server
lsof:
pkg.installed:
- order: 1
nginx-conf:
file.managed:
- order: 2
- name: /opt/nginx.conf
- source: salt://files/nginx.conf
- user: root
- group: root
- mode: 644
- template: jinja
- backup: minion
- defaults:
port: 90
worker_connections: 10241
python3:
pkg.installed:
- order: last
salt 'node1' state.sls test_order
# 说明,个人感觉优先级基本没啥用,只有极少数的情况能用到
4.2.6 文件管理
# 上传文件到一个目录 vim manage_nginx_conf.sls
nginxconf:
file.managed:
- name: /opt/nginx.conf
# salt:// 当前环境的根目录
- source: salt://files/nginx.conf
- user: root
- group: root
- mode: 644
# 执行命令应用
salt 'node1' state.sls manage_nginx_conf
# 本例使用了jinja模板及定义变量
nginxconf:
file.managed:
- name: /opt/nginx.conf
# salt:// 当前环境的根目录
- source: salt://files/nginx.conf
- user: root
- group: root
- mode: 644
- backup: minion
- template: jinja
# 定义jinja模板引用的变量
- defaults:
port: 80
worker_connections: 10240
# nginx.conf文件修改
events {
# worker_connections 1024; 修改为:
worker_connections {{ worker_connections }};
}
server {
# listen 80; # 修改为:
listen {{ port }};
salt 'node1' state.sls manage_nginx_conf
# 上传文件到多个目录
vim upload_more.sls
upload-file:
file.managed:
- names:
- /etc/hosts
- /tmp/hosts
# salt:// 当前环境的根目录
- source: salt://conf/hosts
- user: root
- group: root
- mode: 644
# 上传文件前检查特定文件是否存在,同时检查依赖
# vim test_upload_and_require.sls
yum_epel_release:
pkg.installed:
# 通过URL安装包
- sources:
- epel-release: https://mirrors.aliyun.com/epel/epel-release-latest-7.noarch.rpm
/etc/hosts:
file.managed:
# salt:// 当前环境的根目录
- source: salt://conf/hosts
- backup: minion
- user: root
- group: root
- mode: 644
# 检查/etc/hosts文件是否存在,结果为false才会执行
- unless: test -f /etc/hosts
# 检查依赖的服务是否已安装
- require:
- pkg: yum_epel_release
追加文件内容
# 追加配置示例1 vim append_java_config.sls
append_config:
file.append:
# 追加配置的文件名
- name: /etc/profile
# 需要追加的内容
- text:
- "export JAVA_HOME=/usr/local/java8"
- "export PATH=$JAVA_HOME/bin:$PATH"
salt 'node1' state.sls append_java_config
扩展示例
# 优化系统配置 示例2
# 给历史记录加时间和执行用户
/etc/profile:
file.append:
- text:
- export HISTTIMEFORMAT="%F %T `whoami` "
# 优化内核配置 示例3
# 优化内核参数
# ipv4连接对外服务端口范围
net.ipv4.ip_local_port_range:
sysctl.present:
- value: 10000 65000
# 最大打开文件数量
fs.file-max:
sysctl.present:
- value: 2000000
# 开启ipv4转发
net.ipv4.ip_forward:
sysctl.present:
- value: 1
# 不适用交换分区
vm.swappiness:
sysctl.present:
- value: 0
# sls文件中使用变量 示例4
# vim user_vars.sls
# 定义变量
{% set web1 = "nginx" %}
{% set database1 = "mariadb" %}
{% set database2 = "mariadb-server" %}
{% set database3 = "redis" %}
{% set conf1 = "salt://conf/nginx.conf" %}
install-services:
pkg.installed:
- pkgs:
# 引用变量
- {{ web1 }}
- {{ database1 }}
- {{ database2 }}
- {{ database3 }}
cpoy-nginx-conf:
file.managed:
- name: /etc/nginx/nginx.conf
- source: {{ conf1 }}
- backup: minion
- user: nginx
- group: nginx
- mode: 644
- template: jinja
# 定义金甲模板中需要的变量
- defaults:
port: 8090
worker_connections: 10249
# 需要的依赖
- require:
- pkg: install-services
start-services:
service.running:
- names:
- nginx
- mariadb
- redis
- enable: True
- reload: True
- require:
- file: cpoy-nginx-conf
- pkg: install-services
# 开启测试 测试是否有语法问题或者错误
salt 'node1' state.sls usr_vars test=True
# 测试无误后再执行
salt 'node1' state.sls usr_vars
4.2.7 批量执行
准备Top文件
# top.sls必须在/etc/salt/mater文件中定义的salt根路径中 如下配置
file_roots:
base:
- /srv/salt/
# 创建并编辑top.sls
vim /srv/salt/top.sls
base:
# base环境下的所有主机都执行
'*':
- webs.usr_vars
# 指定node1执行
'node1':
- webs.lnmp
- webs.create_user
- webs.del_user
# 本例只配置了base环境,实际生产环境应加上类似于下面的配置
###################################
devp:
# devp环境下的所有主机都执行
'*':
- webs.usr_vars
prod:
# prod环境下的所有主机都执行
'*':
- webs.usr_vars
test:
# test环境下的所有主机都执行
'*':
- webs.usr_vars
webs/
├── append_java_config.sls
├── createdir.sls
├── create_user.sls
├── del_user.sls
├── install_nginx.sls
├── lnmp.sls
├── manage_nginx_conf.sls
├── start_nginx.sls
├── test_file_and_require.sls
├── test_include.sls
├── test_order.sls
├── test_require.sls
├── test_watch.sls
└── usr_vars.sls
# 测试top.sls
salt 'node*' state.highstate test=True
# 执行
salt 'node*' state.highstate
以上是通过saltstack内置模块实现用户管理,文件管理,软件安装等操作,介绍的 比较简单,详细了解需要看官方文档
官方文档地址: http://docs.saltstack.cn/
下面介绍自定义模块
五、saltstack自定义模块
# master节点
# 确保master配置文件/etc/salt/master中的base环境已开启
file_roots:
base:
- /srv/salt
# 重启 systemctl restart salt-master # 本例前面已经配置过
# 切换目录
cd /srv/salt
# 创建文件夹
mkdir _modules # 名字必须是_modules,官方规定的
# 进入_modules目录
cd _modules
# 开始编写python文件,因为saltstack是python开发的,所以自定义的模块文件必须.py结尾的python文件
# 示例1 mymodules.py
def w():
shellcmd = "w"
return __salt__['cmd.run'](shellcmd)
def df():
shellcmd = "df -hT"
return __salt__['cmd.run'](shellcmd)
def top():
shellcmd = "top"
return __salt__['cmd.run'](shellcmd)
def ls():
shellcmd = "ls /"
return __salt__['cmd.run'](shellcmd)
def hostname():
shellcmd = "hostname"
return __salt__['cmd.run'](shellcmd)
def install_nginx():
shellcmd = "yum install -y nginx"
return __salt__['cmd.run'](shellcmd)
def start_nginx():
shellcmd = "nginx"
return __salt__['cmd.run'](shellcmd)
# 同步模块到所有节点,也可以同步到某个节点
salt '*' saltutil.sync_modules
####如果自定义模块文档发生变化,必须先同步然后再执行,否则执行的还是修改之前的内容####
# 调用模块
# 语法格式
# salt 命令 '*' 目标主机(这里是全部主机) mymodules上面.py文件名 w 函数名
salt '*' mymodules.w
salt 'node1' mymodules.df
salt 'node1' mymodules.hostname
salt 'node1' mymodules.install_nginx
salt 'node1' mymodules.start_nginx
六、grains与pillar
6.1 grains
6.1.1 grains简介
Grains是SaltStack的一个组件,它存放在SaltStack的minion端
当salt-minion启动时会把收集到的数据静态存放在Grains当中,只有当minion重启时才会进行数据的更新。由于grains是静态数据,因此不推荐经常修改~
Salt提供了一个接口来获取有关底层系统的信息。这被称为grains接口,因为它向salt呈现了信息的颗粒。收集操作系统、域名、IP地址、内核、操作系统类型、内存和许多其他系统属性的粒度。 grains接口可用于Salt模块和组件,以便在正确的系统上自动使用正确的Salt minion命令。 grains数据是相对静态的,但是如果系统信息发生变化(例如,网络设置更改),或者如果为自定义grains指定了新值,则需要将grains数据刷新。 注意 Grains解析为小写字母。例如,FOO和foo的目标是相同的颗粒。
应用场景:
- 信息查询,可用作CMDB
- 在target中使用,匹配minion
- 在state系统中使用,配置管理模块
6.1.2 信息查询
用于查询minion端的IP、FQDN等信息
- 默认可用的grains
salt '*' grains.ls # 获取所有grains的key-只显示key
salt '*' grains.items # 获取所有的grains键值对 key:value
salt '*' grains.item osrelease # 获取某个grain
salt '*' grains.item username
salt '*' grains.item fqdn_ip4
salt '*' grains.item os
salt '*' saltutil.sync_grains # 同步grains配置到所有minion-此命令可无需重启salt-minion刷新grains数据
salt 'node1' grains.list 列出node1所有的静态数据键
salt 'node1' grains.items 列出node1所有的静态数据键与值
salt '*' grains.item os 列出所有机器的os
-G 用于对匹配到的进行操作 (目标选择)
# -G使用grains匹配目标
salt -G 'os:CentOS' cmd.run 'echo "hello world"'
# 自定义grains的3种方式
# 1.直接在/etc/salt/minion中定义---【node节点操作】
grains:
roles:
- webserver
- python3
# salt '*' saltutil.sync_grains 同步grains
# salt -G 'roles:python3' cmd.run 'echo "hello world"'
# ------------------------------------------------------
# 2./etc/salt/grains---【node节点操作】
# vim /etc/salt/grains
webhost: nginx
database1: mariadb
database2: mariadb-server
database3: redis
dev-tools: python3
# salt '*' saltutil.sync_grains 同步grains
# salt -G 'webhost:nginx' cmd.run 'echo "hello world"'
# salt -G 'dev-tools:python3' cmd.run 'echo "hello world"'
# -----------------------------------------------------
# 开发grains 即自定义grains---【master节点操作】
# 3.用python 写一个python脚本,返回一个字典就可以了
# 在 /srv/salt/ 下创建一个 _grains 的目录,然后在目录中创建一个.py文件
#!/usr/bin/python3
def my_grains():
mygrains = {"webmaster": "nginx", "web-slave": "httpd"}
mygrains['database'] = "mysql"
mygrains['cache'] = "redis"
mygrains['devp-tool'] = 'python3'
return mygrains
# salt '*' saltutil.sync_grains 同步grains
# salt '*' grains.items # 查看所有grains
# salt '*' grains.item webmaster # 查看指定grain
# salt -G 'webmaster:nginx' cmd.run 'echo "hello world"' # 引用grains选择目标
# grains的优先级
1.系统自带
2.grains文件写的
3.minion配置文件写的
4.自己写的
# 每次修改数据都需要重启服务或刷新grains操作才会生效,这也印证了是静态数据
# 命令 salt ‘*’ saltutil.sync_grains 用于刷新grains的数据
6.1.3 grains匹配运用
6.1.3.1 在target中匹配minion
# 在前面实验的基础上执行以下命令
salt -G 'os:CentOS' cmd.run 'echo "hello world"'
salt -G 'webhost:nginx' cmd.run 'echo "hello world"'
salt -G 'dev-tools:python3' cmd.run 'echo "hello world"'
6.1.3.2 在top.sls文件中匹配
vim /srv/salt/top.sls
base:
'*':
- webs.install_nginx
'webhost:nginx':
# 根据grains匹配
- match: grain
- webs.install_nginx
salt '*' state.highstate test=True # 测试
salt '*' state.highstate # 执行
6.2 pillar
6.2.1 pillar简介
- pillar和grains一样也是一个数据系统,两个区别是应用场景不同
- pillar是将信息动态的存放在master端,主要存放私密、敏感信息(如用户名密码等),而且可以指定某一个minion才可以看到对应的信息
- pillar更加适合在配置管理中运用
Pillar在salt中是非常重要的组成部分,利用它可以完成很强大的功能,它可以指定一些信息到指定的minion上。不像grains一样是分发到所有Minion上的,它保存的数据可以是动态的。Pillar以sls来写的,格式是键值对。
6.2.2 适用情景:
- 1.比较敏感的数据,比如密码,key等
- 2.特殊数据到特定Minion上
- 3.动态的内容
- 4.其他数据类型
6.2.3 pillar示例
# 1 查看Minion的Pillar信息
salt '*' pillar.items
# 2 查看某个Pillar值
salt '*' pillar.item <key> #只能看到顶级的
salt '*' pillar.get <key>:<key> #可以取到更小粒度的
# 3 编写pillar数据
# 指定pillar_roots,默认是/srv/pillar(可通过修改master配置文件修改),建立目录
# 开启pillar_roots
# vim /etc/salt/master
pillar_roots:
base:
- /srv/pillar
# 修改配置后重启服务 systemctl restart salt-master
# 4 创建目录
mkdir /srv/pillar
cd /srv/pillar
# 5 编辑一个pillar数据文件
# vim test_pillar.sls
name: 'salt'
users:
hadoop: 1010
redhat: 1011
ubuntu: 1012
# 6 建立top file指定minion到pillar数据文件
# vim /srv/pillar/top.sls
base:
'*':
- test_pillar
# 7 刷新pillar数据
salt '*' saltutil.refresh_pillar
#测试是否生效
salt '*' pillar.get name
salt '*' pillar.item name
# 8 在state中通过jinja使用pillar数据
# vim /srv/salt/users.sls
{% for user,uid in pillar.get('users', {}).items() %}
{{user}}:
user.present:
- uid: {{uid}}
{% endfor %}
# salt '*' state.sls users test=True
# 9 通过jinja模板配合grains指定pillar数据
# vim /srv/pillar/pkgs.sls
pkgs:
{% if grains['os_family'] == 'RedHat' %}
database: mariadb
database-server: mariadb-server
vim: vim
{% elif grains['os_family'] == 'Debian' %}
database: mysql
vim: vim
{% elif grains['os'] == 'CentOS' %}
database: mariadb-server
database-server: mariadb-server
vim: vim
{% endif %}
# 更新/srv/pillar/top.sls
base:
'*':
- test_pillar
'node2':
- pkgs
# 10 刷新pillar数据
salt '*' saltutil.refresh_pillar
#测试是否生效
salt '*' pillar.get database
salt '*' pillar.item database
# 11 目标选择测试
salt -I 'database:mariadb' test.ping
# 12 调用pillar数据
# vim /srv/salt/database.sls
install-database:
pkg.installed:
# 使用pillar选择目标数据
- names:
- {{ pillar['pkgs']['database'] }}
- {{ pillar['pkgs']['database-server'] }}
# 使用pillar选择目标主机执行
salt -I 'pkgs:database:mariadb' state.sls database test=True
salt -I 'pkgs:database:mariadb' state.sls database
七、jinja模板
7.1 Jinja模板简介
- Jinja是一种基于python的模板引擎,在SLS文件里可以直接使用jinja模板来做一些操作。 通过jinja模板可以为不同服务器定义各自的变量。
7.2 Jinja模板使用方式
7.2.1 控制结构包装条件
# vim /srv/salt/testjinjia.sls
install-pkgs:
pkg.installed:
- pkgs:
{% if grains['fqdn'] == 'node1' %}
- soft: nginx
- database1: mariadb
- database2: mariadb-server
{% elif grains['fqdn'] == 'node2' %}
- soft: wget
- websrv: net-tools
- database1: redis
{% else %}
- soft: tree
{% endif %}
salt '*' state.sls testjinja test=True
salt '*' state.sls testjinja
7.2.2 Jinja在普通文件的使用
- 复制一份nginx配置文件到salt目录files下
cp /etc/nginx/nginx.conf /srv/salt/files
- 修改模板文件(引用变量port)
server {
listen {{ port }}; # 修改80
# vim test_jinjia2.sls
nginx-conf-copy:
file.managed:
- name: /opt/nginx.conf
- source: salt://files/nginx.conf
- user: root
- group: root
- mode: 644
- backup: millon
- template: jinja
# 定义jinja模板中引用的变量
- defaults:
port: 81
salt '*' state.sls test_jinjia2 test=True
salt '*' state.sls test_jinjia2
7.2.3 import方式,可在state文件之间共享
- 定义变量文件
# vim /srv/salt/vars.sls
{% set port = 81 %}
{% set worker_connections = 20480 %}
- 导入
# vim /srv/salt/files/nginx.conf
{# 写在文件顶部 #}
{% from '../vars.sls' import port %}
{% from '../vars.sls' import worker_connections %}
此时注意:
nginx-conf-copy:
file.managed:
- name: /opt/nginx.conf
- source: salt://files/nginx.conf
- user: root
- group: root
- mode: 644
- backup: millon
# 因为jinja模板文件已经引入变量文件,这里配置必须删除或者注释掉,否则会冲突
# - template: jinja
# 定义jinja模板中引用的变量
# - defaults:
# port: 81
# worker_connections: 20480
salt 'node3' state.sls test_jinjia2 test=True
salt 'node3' state.sls test_jinjia2
八、Job管理
8.1 Job简介
- master在下发指令任务时,会附带上产生的jid
- minion在接收到指令开始执行时,会在本地的/var/cache/salt/minion/proc目录下产生该jid命名的文件,用于在执行过程中master查看当前任务的执行情况
- 指令执行完毕将结果传送给master后,删除该临时文件
8.2 Job cache
Job缓存默认保存24小时
vim /etc/salt/master
#keep_jobs: 24
master端Job缓存目录:/var/cache/salt/master/jobs
[root@master /srv/salt ]# ls /var/cache/salt/master/jobs
00 09 11 18 1f 28 2e 39 3f 48 4e 56 5b 66 6b 74 7a
8.3 Job持久化(存储到数据库)
可以从master存储到数据库也可以从minion存储,这里我们选择从master端存储
官方文档:http://docs.saltstack.cn/ref/returners/all/index.html
配置mysql作为返回器: http://docs.saltstack.cn/ref/returners/all/salt.returners.mysql.html#module-salt.returners.mysql
修改master端配置
vim /etc/salt/master
# 增加如下配置
master_job_cache: mysql
mysql.host: 'localhost'
mysql.user: 'salt'
mysql.pass: 'salt'
mysql.db: 'salt'
mysql.port: 3306
# 需要安装并配置mysql
重启salt-master服务
systemctl restart salt-master
安装数据库以及相关插件
yum install -y mariadb mariadb-server MySQL-python python36-mysql.x86_64
# MySQL-python python36-mysql插件必须安装,否则salt无法与mysql通信
启动数据库
systemctl start mariadb
# 这里为了方便未对数据库初始化
# 如需设置mysql密码等初始化配置使用如下命令:
# mysql_secure_installation
创建sql模板
# vim /srv/salt/returner-mysql.sql
CREATE DATABASE IF NOT EXISTS `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;
导入数据库
mysql -uroot -p < returner-mysql.sql
数据库授权
# 登陆数据库
MariaDB [(none)]> grant all on salt.* to salt@'%' identified by 'salt'; # 授权,若连不上把%换成localhost
Query OK, 0 rows affected (0.00 sec)
MariaDB [(none)]> flush privileges; # 刷新
Query OK, 0 rows affected (0.00 sec)
因为master和数据库在同一主机,所以授权本机就可以,如果从minion上传数据库,那也要进行相应的授权
查看数据库
MariaDB [salt]> select * from salt_returns
Empty set (0.00 sec)
MariaDB [salt]> select * from salt_events
Empty set (0.00 sec)
执行一次远程任务
salt '*' cmd.run 'hostname'
再次查看数据库
MariaDB [salt]> select * from salt_returns \G;
*************************** 1. row ***************************
fun: cmd.run
jid: 20210820090412144409
return: "master"
id: master
success: 1
full_ret: {"cmd": "_return", "id": "master", "success": true, "return": "master", "retcode": 0, "jid": "20210820090412144409", "fun": "cmd.run", "fun_args": ["hostname"], "_stamp": "2021-08-20T09:04:12.345698"}
alter_time: 2021-08-20 17:04:12
*************************** 2. row ***************************
fun: cmd.run
jid: 20210820090412144409
return: "node1"
id: node1
success: 1
full_ret: {"cmd": "_return", "id": "node1", "success": true, "return": "node1", "retcode": 0, "jid": "20210820090412144409", "fun": "cmd.run", "fun_args": ["hostname"], "_stamp": "2021-08-20T09:04:12.342927"}
alter_time: 2021-08-20 17:04:12
*************************** 3. row ***************************
fun: cmd.run
jid: 20210820090412144409
return: "node2"
id: node2
success: 1
full_ret: {"cmd": "_return", "id": "node2", "success": true, "return": "node2", "retcode": 0, "jid": "20210820090412144409", "fun": "cmd.run", "fun_args": ["hostname"], "_stamp": "2021-08-20T09:04:12.390078"}
alter_time: 2021-08-20 17:04:12
4 rows in set (0.00 sec)
salt '*' test.ping --return mysql # 指定返回器为mysql
8.4 Job管理
查看所有minion当前正在运行的jobs(在所有minions上运行saltutil.running)
salt '*' saltutil.running # 查看job及job_id
salt '*' saltutil.kill job_id # 停止指定job
salt-run jobs.active # 查看当前正在运行的job
salt-run jobs.list_jobs # 列出当前master jobs cache中所有job
salt-run manage.status
salt-run manage.up
salt-run manage.down
九、 Salt-ssh和Salt-syndic
9.1 Salt-ssh
9.1.1 Salt-ssh简介
- salt-ssh可以独立运行的,不需要minion端。
- salt-ssh 用的是sshpass进行密码交互的。
- 以串行模式工作,性能下降。
9.1.2 Salt-ssh安装与配置
- 安装salt-ssh
yum install -y salt-ssh
- 配置roster(相当于ansible的inventory清单)文件
# vim /etc/salt/roster
# Sample salt-ssh config file
#web1:
# host: 192.168.42.1 # The IP addr or DNS hostname
# user: fred # Remote executions will be executed as user fred
# passwd: foobarbaz # The password to use for login, if omitted, keys are used
# sudo: True # Whether to sudo to root, not enabled by default
#web2:
# host: 192.168.42.2
node1:
host: 10.0.0.21 # 主机名
user: root # 用户
port: 22 # 端口
# passwd: 123456 # 密码 考虑到安全一般不建议在配置文件配置密码
node2:
host: 10.0.0.22
user: root
port: 22
- 测试
# 如果没有配置密码,第一次连接需要手动输入密码,之后不用再输密码
[root@master ~ ]# salt-ssh '*' test.ping -i
node2:
True
node1:
True
9.2 Salt-syndic
9.2.1 Salt-syndic简介
- syndic其实就是个代理,隔离master与minion
- Syndic必须要运行在master上,再连接到另一个topmaster上
- Topmaster 下发的状态需要通过syndic来传递给下级master,minion传递给master的数据也是由syndic传递给topmaster。
- top master并不知道有多少个minion
- syndic与topmaster的file_roots和pillar_roots的目录要保持一致
9.2.2 Salt-syndic配置
配置顶级master
# salt-syndic
# 架构 简单理解就是salt-syndic所处的master节点之上还有master即master的master,这个master下发指令到salt-syndic
# 然后salt-syndic通知所处同级的salt-master下发指令到minion
->master1[salt-master + salt-syndic ] ->minion1,minion2,minion3.....
master[salt-master] ->master2[salt-master + salt-syndic ] ->minion1,minion2,minion3.....
->master2[salt-master + salt-syndic ] ->minion1,minion2,minion3.....
# 新部署一台机器 10.0.0.24
yum install -y salt-master # 仅安装salt-master
# 1 修改master配置文件,使其成为顶级master
# vim /etc/salt/master
# masters' syndic interfaces.
order_masters: True
# 重启服务
systectem start salt-master
配置下级master端
- 安装salt-syndic
yum install -y salt-syndic
- 修改master配置文件
# 可配置多个顶级master的ip,本例只配置1个
syndic_master:
- 10.0.0.24
# - 10.0.0.25
【补充】minion端配置多master如下
master:
- master1
- master2
- master3
- 重启服务
systemctl restart salt-master
systemctl start salt-syndic
顶级master端查看
salt-key -L
salt-key -A -y
- 测试
salt '*' test.ping
十、 salt-api
10.1 salt-api简介
SaltStack 官方提供有REST API格式的 salt-api 项目,将使Salt与第三方系统集成变得尤为简单。
官方提供了三种api模块:
rest_cherrpy
rest_tornado
rest_wsgi
官方链接:https://docs.saltstack.com/en/latest/ref/netapi/all/index.html#all-netapi-modules
中文链接: http://docs.saltstack.cn/ref/netapi/all/index.html#all-netapi-modules
10.2 salt-api配置
- 安装salt-api
yum install -y salt-api python-cherrypy
- 生成证书
cd /etc/pki/tls/private
openssl genrsa 2048 > localhost.key
cd /etc/pki/tls/certs
make testcert # 根据提示填写相关信息
- 创建用户认证文件
useradd -s /sbin/nologin saltapi
echo redhat | passwd --stdin saltapi
更改用户 saltapi 的密码 。
passwd:所有的身份验证令牌已经成功更新。
vim /etc/salt/master.d/auth.conf
external_auth:
pam:
saltapi:
- .*
- '@wheel'
- '@runner'
- '@jobs'
- 激活rest_cherrypy模块
vim /etc/salt/master.d/api.conf
rest_cherrypy:
host: 10.0.0.20
port: 8000
ssl_crt: /etc/pki/tls/certs/localhost.crt
ssl_key: /etc/pki/tls/private/localhost.key
- 打开include加载自配置文件
vim /etc/salt/master
# as the main master config file).
default_include: master.d/*.conf # 打开这行的主食
- 重启服务
systemctl restart salt-master
systemctl start salt-api
10.3 salt-api使用
- 获取认证token
curl -sSk https://10.0.0.20:8000/login \
-H 'Accept: application/x-yaml' \
-d username=saltapi \
-d password=redhat \
-d eauth=pam
# 执行结果
return:
- eauth: pam
expire: 1629729789.8010104
perms:
- .*
- '@wheel'
- '@runner'
- '@jobs'
start: 1629686589.8010097
token: ffa3d1fa269736a542e8a83a8cc32315a5eaa326
user: saltapi
- 推送任务
curl -sSk https://10.0.0.20:8000 \
-H 'Accept: application/x-yaml' \
-H 'X-Auth-Token: ffa3d1fa269736a542e8a83a8cc32315a5eaa326' \
-d client=local \
-d tgt='*' \
-d fun=test.ping
# 执行结果
return:
- master: true
node1: true
node2: true
node3: true
curl -sSk https://10.0.0.20:8000 \
-H 'Accept: application/x-yaml' \
-H 'X-Auth-Token: ffa3d1fa269736a542e8a83a8cc32315a5eaa326' \
-d client=local \
-d tgt='*' \
-d fun=network.get_fqdn
return:
- master: master
node1: node1
node2: node2
node3: syndic-master
11 saltstack综合模板集合
综合模板案例地址: https://github.com/saltstack-formulas/
结语: 限于水平,本文仅作为引导和入门,若需全面细致研究请阅读官方中文文档,地址如下: