saltstack采用C/S结构的方式来进行配置管理,运行速度快、部署轻松,几分钟内便可运行起来,而且服务器之间能够做到秒级通讯,容易批量管理上万台服务器,显著降低人力与运维成本
话不多说,开始进入正题!
- 一种基于C/S架构的服务器基础架构集中化管理平台,管理端称为master,客户端称为minion
- 具备配置管理、远程执行、监控等功能
- 基于python语言开发
- 结合轻量级的消息队列软件ZeroMQ与Python第三方模块(Pyzmq、PyCrypto、Pyjinjia2、 python-msgpack 和 PyYAML 等)构建
1. 部署简单方便
2. 主从集中化管理
3. 配置简单、功能强大、扩展性强
4. 主控端(master)和被控端(minion)基于证书认证,安全可靠
5. 支持API自定义模块,可通过Python扩展
- local:本地单点(不建议这么做,不然就没意义了)
- Master/Minion:通过server/client的方式进行管理,效率很高
- Salt SSH:通过SSH方式进行管理(类似于ansible),效率相对来说比较低
对比上面的运行模式,我们可以得出saltstack一般都是采用Master/Minion来进行自动化运维管理的,下面便是Master/Minion的架构图
minion:客户端安装组件,配置好之后会主动去连接master,从master端得到资源状态信息,并同步资源管理信息
master:服务端安装组件,运行在主服务器上,负责salt命令运行和资源的管理
- master与minion之间通过Zero进行消息传递,使用ZeroMQ进行消息传递,以及Zero-MQ的发布订阅模式,连接方式包括tcp、ipc
- master将要执行的操作或命令发送给minion,minion从消息总线上收到要进行的操作或要处理的命令,之后交给minion_handle_aes处理
- 之后minion_handle_aes发起一个本地线程去调用cmdmod去执行操作或命令,线程执行完毕后调用minion.return_pub方法,将执行结果通过消息总线返回给master
- master接收到客户端返回的结果,调用master._handle_aes方法,将结果写进文件中
- salt.client.LocalClient.cmd_cli通过轮询获取执行结果,将结果输出到终端
saltstack与ansible都作为自动化运维工具,能够对目标主机实现配置管理批量操作等功能,满足企业的自动化运维管理,那么他们之间有什么异同之处呢?
相同点:
\1. 都是基于python开发,可以部署到不同的系统环境中
\2. 具有较好的二次开发性,便于实现个性定制
\3. ansible的playbook和saltstack的state都是遵循yaml格式
\4. 执行返回结果都是json格式,容易理解
不同点:
从响应速度来看:
saltstack的master与minion之间是通过ZeroMQ来传输数据,而ansible是通过标准SSH进行数据传输,saltstack的响应速度要比ansible的要快
从安全性来讲:
ansible与saltstack都需要和远程主机进行连接,所以最大的问题就是MITM攻击(通过伪装成master主机和远程主机进行通信,从而进行攻击)
saltstack使用ZeroMQ进行数据传输,ZeroMQ本身数据传输不支持加密,saltstack可以通过使用AES数据加密方法来对数据进行加密传输,但minion以守护进程的方式运行在远程主机,容易暴露
ansible则使用标准SSH进行连接,不需要在远程主机上启动守护进程,而且标准SSH数据传输就是加密传输,安全方面ansible要更胜一筹
从成本来讲:
saltstack需要在master和minion主机启动守护进程,需要检测守护进程的运行状态,增加了运维成本
ansible和远程主机之间都是通过标准SSH进行连接的,远程主机只需要运行SSH进程就可以进行操作,而SSH是机房主机中都会安装和启动的进程,运维成本低于saltstack,使用起来要比saltstack简单的多
从语法来讲:
saltstack的state和ansible的playbook都遵循YAML格式,但是Ansible的Playbook语法要比SaltStack的State语法具有更好的可读性
前面我们说过,在saltstack中有两种角色——master(主控端)和minion(被控端),master来管理minion
下面我们来看下master和minion之间是怎么通信的
master启动后默认监听4505和4506两个端口
4505端口为saltstack的消息发布系统端口;4506端口为 saltstack minion与master 通信的端口
查看4505的端口状态我们会发现所有的minion在4505端口持续保持在ESTABLISHED状态
我们先来看一下本次实验的架构图
192.168.244.141作为主控端master
192.168.244.128/129都是被控端minion
我们先分别在三台服务器上安装依赖包
#安装saltstack存储库和密钥
rpm --import https://repo.saltproject.io/py3/redhat/7/x86_64/3002/SALTSTACK-GPG-KEY.pub
#配置镜像源
touch /etc/yum.repos.d/salt.repo
curl -fsSL https://repo.saltproject.io/py3/redhat/7/x86_64/3002.repo | tee /etc/yum.repos.d/salt.repo
#清缓存
yum clean expire-cache
然后我们根据不同的角色来安装不同组件
#master
[root@master ~]# yum install salt-master -y
#minion
[root@minion1 ~]# yum install salt-minion -y
[root@minion2 ~]# yum install salt-minion -y
安装完毕后开启并设置自启动
[root@master ~]#systemctl enable salt-master && systemctl start salt-master
[root@minion1 ~]#systemctl enable salt-minion && systemctl start salt-minion
[root@minion2 ~]#systemctl enable salt-minion && systemctl start salt-minion
修改master配置文件
master配置文件路径:vim /etc/salt/master
[root@master ~]# vim /etc/salt/master
[root@master ~]# grep -Ev "^$|#" /etc/salt/master
file_root:
base:
- /home/salt
pillar_roots:
base:
- /home/salt/pillar
order_masters: True
auto_accept: True
##file_roots:主目录
##pillar_roots:pillar组件主目录
##order_masters:允许开启多层master
##auto_accept:自动认证
[root@master ~]#systemctl restart salt-master
修改minion配置文件
minion配置文件路径:vim /etc/salt/minion
我只展示操作minion1的过程,minion2同理的
[root@minion1 ~]# vim /etc/salt/minion
[root@minion1 ~]# grep -Ev "^$|#" /etc/salt/minion
master: 192.168.244.141
id: 192.168.244.129
user: root
#重启服务
[root@minion1 ~]# systemctl restart salt-minion
# minion的识别ID,可以是IP,域名,或是可以通过DNS解析的字符串
id: 192.168.244.128
# salt运行的用户权限
user: root
# master的识别ID,可以是IP,域名,或是可以通过DNS解析的字符串
master : 192.168.244.141
# master通讯端口
master_port: 4506
# 备份模式,minion是本地备份,当进行文件管理时的文件备份模式
backup_mode: minion
# 执行salt-call时候的输出方式
output: nested
# minion等待master接受认证的时间
acceptance_wait_time: 10
# 失败重连次数,0表示无限次,非零会不断尝试到设置值后停止尝试
acceptance_wait_time_max: 0
# 重新认证延迟时间,可以避免因为master的key改变导致minion需要重新认证的syn风暴
random_reauth_delay: 60
# 日志文件位置
log_file: /var/logs/salt_minion.log
# 文件路径基本位置
file_roots:
base:
- /etc/salt/minion/file
# pillar基本位置
pillar_roots:
base:
- /data/salt/minion/pillar
minion在第一次启动时,会在/etc/salt/pki/minion/下自动生成minion.pem(private key)和 minion.pub(public key),然后将minion.pub发送给master
我们在master端来进行key认证,使用salt-key命令
[root@master ~]# salt-key
Accepted Keys: #可以看到master已经检测到minion,且已认证key
192.168.244.128
192.168.244.129
Denied Keys:
Unaccepted Keys:
Rejected Keys:
#如果没有认证,手动输入认证一下
[root@master ~]# salt-key -a id
认证成功之后我们来验证一下
[root@master ~]# salt '192.168.244.128' test.ping
192.168.244.128:
True #返回结果表示成功
[root@master ~]# salt '192.168.244.129' test.ping
192.168.244.129:
True
首先介绍了saltstack是什么,以及它与ansible之间的相似之处和不同之处
还介绍了saltstack中master和minion之间是怎么实现通信的
最后还通过在三台虚拟机上部署saltstack组件,让大家印象更深刻
用来执行salt命令,通常在master端运行。
salt [option] '' [arguments]
例如:
salt 'minion1' cmd.run '192.168.244.128'
'minion1' 是指在那些minion上操作;
cmd是一个执行模块;test是模块下的函数;
'192.168.244.128'是test函数的参数,有的函数需要参数,有的不需要
#查看帮助文档
salt -d
salt '*' sys.doc
salt 'x' sys.doc test
#查看service相关模块命令
salt -d | grep service
#获取主机所有服务
salt '*' service.get_all
#重载sshd服务
salt '*' service.reload sshd
#显示软件包版本列表
salt '*' pkg.list_pkgs
#显示软件包版本信息
salt '*' pkg.version python
#安装软件包
salt '*' pkg.install httpd
#查看mysql服务状态
salt 'node1.com' service.status mysql
#启动mysql服务
salt 'node1.com' service.start mysql
#与上面一样查看服务
salt 'node1.com' cmd.run 'service mysql status'
#模块列表
salt '*' sys.list_modules
#把salt-master端相应的文件,分发文件到minion端
salt '*' cp.get_file salt://ceshi/b /tmp/test
#把salt-master端相应的目录,分发文件到minion端
salt '*' cp.get_dir salt://zabbix /tmp
#把salt-master端对应文件拷贝到minion端相应目录下
salt '*' file.copy /tmp/zabbix.sls /tmp/sls
#远程命令执行测试
salt '*' cmd.run 'uptime'
#查看grains分类
salt '*' grains.ls
#查看grains所有信息
salt '*' grains.items
#查看grains某个信息
salt '*' grains.item osrelease
saltstack提供了Runners的功能,使用salt-run来运行,可以非常方便地在Master端执行相关的模块,获取minion端状态。salt-run下的很多模块我们用不到,多数我们可以通过salt命令就已经完成工作需要
常用的runner有manage
#查看存活的minion
salt-run manage.up
#查看死掉的minion
salt-run manage.down
#查看down掉的minion,并将其删除
salt-run manage.down removekeys=True
#查看minion的相关状态
salt-run manage.status
#查看slat的所有master和minion的版本信息
salt-run manage.versions
用于密钥管理,来决定master与minion之间的通信,通常在master端执行
在minion执行,minion执行自己可以执行的模块,而不是通过master下发job
salt-call [options] [arguments]
##自己执行test.ping命令
salt-call test.ping
##自己执行cmd.run函数
salt-call cmd.run 'ifconfig'
通过salt-cp可以将master上的文件下发到minion上
salt-cp [options] '' SOURCE DEST
salt-cp '*' testfile.html /tmp
#把master上的index.html分发到test minion上
salt-cp 'test*' index.html /tmp/a.html
#把master上的hosts文件分发到所有主机
salt-cp '*' /etc/hosts /etc/hosts
在生产环境中我们可能要管理上百台服务器,有些服务器用来做数据库,有些服务器用来实现web服务,有些做负载均衡…
我们如果想对web服务器做批量操作的话,而web服务器又有几十台,我们是不可能将这几十台服务器的ip地址全都敲进命令里的,这样会大大降低运维效率
我们可以对这些服务器做分组,用来做负载均衡的分成一组、做web服务的分成一组,那么我们操作时只需要指定组名就可以了
在saltstack里我们一般用nodegroups来实现分组管理
Nodegroups
我们通过创建nodegroups配置文件来实现分组管理,配置文件的路径为
/etc/salt/master.d/nodegroups.conf
对目标服务器分组有以下七种方式,这七种方式的标示符分别为
G -- 针对 Grains 做单个匹配,例如:G@os:Ubuntu
E -- 针对 minion 针对正则表达式做匹配,例如:E@web\d+.(dev|qa|prod).loc
P -- 针对 Grains 做正则表达式匹配,例如:P@os:(RedHat|Fedora|CentOS)
L -- 针对 minion 做列表匹配,例如:[email protected],minion3.domain.com orbl*.domain.com
使用 L 列表的方式,必须把 minion 列出来,或者是列出几台后,在后面接 or 或者 and 表达式, or 或者 and 后面接的表达式后面可以使用正则表达式。
I -- 针对 Pillar 做单个匹配,例如:I@pdata:foobar
S -- 针对子网或是 IP 做匹配,例如:[email protected]/24 or [email protected]
R -- 针对客户端范围做匹配,例如:R@%foo.bar
N -- 针对 nodegroup 做匹配
如果说我有多个分组,可以按照下列格式进行配置
[root@master ~]#vim /etc/salt/master.d/nodegroups.conf
nodegroups:
group1: '[email protected],192.168.244.130'
group2: '[email protected]'
group3: '[email protected]/24'
group4: '[email protected][2-3]'
[root@master ~]#salt -N group1 test.ping
案例:
[root@master ~]# vim /etc/salt/master.d/nodegroup.conf
nodegroups:
web: '[email protected],192.168.244.129'
[root@master ~]# salt -N web test.ping
192.168.244.129:
True
192.168.244.128:
True
或者通过E匹配模式来做分组管理
[root@master ~]# vim /etc/salt/master.d/nodegroup.conf
nodegroups:
group1: '[email protected][8-9]'
[root@master ~]# salt -N group1 test.ping
192.168.244.129:
True
192.168.244.128:
True
SLS(Salt State文件)是Salt State系统的核心。SLS描述了系统的目标状态,SLS文件由格式简单的数据构成,经常被称作配置管理
SLS文件以“.sls”后缀结尾,但在调用时不需要写后缀
SLS配置文件采用YAML的格式编写
下面是YAML格式的一些要求
基本格式例子
http-install:
pkg:
- installed
#第一行被称为标签定义,在这里被定义为安装包的名
#第二行被称为状态定义,在这里定义使用module
#第三行被称为函数定义,在这里定义使用调用函数
[root@master ~]#vim /srv/salt/apache.sls
http-install: # ID声明 也是软件包名称 自定义
pkg.installed: # 模块以及函数声明
- pkgs:
- httpd # 参数声明
指定主机执行:
[root@master ~]#salt server5 state.sls apache 文件后缀不用添加
SLS配置文件在master上,默认路径是在/srv/salt/下面,使用子目录来管理是个很好的选择,init.sls在一个子目录里面表示引导文件,也就表示子目录本身,所 以 apache/init.sls 就是表示 apache
例如文件树如下所示:
[root@master ~]#tree /srv/salt/apache
| --install.sls
|
|--_modules
#第一种写法
[root@master ~]# salt “*” state.sls apache/install
#第二种写法
[root@master ~]# mv install.sls init.sls
[root@master ~]# salt “*” state.sls apache
#同时存在apache/apache.sls 和 apache/init.sls,则 apache/init.sls 被忽略,apache.sls将被用来表
示 apache
/srv/salt/apache
| --install.sls
|
| --apache.sls
salt “*” state.sls apache #优先读取apache.sls此文件
用户管理
useradd:
user.present:
-name: admin
- shell: /bin/bash
- home: /home/admin
- uid: 888
userdel:
user.absent:
- name: admin
- purge: True #purge类似userdel -r
- force: True #force为用户在线也强制删除
文件管理
fileup:
file.managed:
- source: salt://nginx/nginx-xxx.xxx.tar.gz
- user: root
- group:root
- mode: 755
- backup:minion
- template:jinja
fileadd:
file.append:
- text:
- "exportJAVA_HOME=/usr/local/jdk1.6.0_13"
- "exportPATH=$JAVA_HOME/bin:$JAVA_HOME/jre/bin:$PATH"
- "exportCLASSPATH=$JAVA_HOME/lib/:$JAVA_HOME/jre/lib:$CLASSPATH"
目录管理
dircover:
file.recurse:
-source: salt://nginx/conf
-user: root
-group: root
-file_mode: 644
-dir_mode: 755
diradd:
file.directory:
- name: /tmp/dir
- user: web
- group: web
- file_mode:644
- dir_mode:755
- makedirs:True
- include_empty: True
- template:jinja
- backup:minion
包管理
installpkgs:
pkg.installed:
- pkgs:
- httpd
- telnet
include:
- web.apache
- require:
- pkg: nginx-install
在某个state变化时运行此模块,文中的配置,相关文件变化后,立即执行相应操作
- watch:
- file: /etc/nginx/nginx.conf
- file: /etc/nginx/fastcgi.conf
- pkg: nginx
优先级比require和watch低,有order指定的state比没有order指定的优先级高,假如一个state模块内 安装多个服务,或者其他依赖关系,可以使用。如果想让某个state最后执行,可以使用last
nginx:
pkg.installed:
- order:1
top.sls 是配置管理的入口文件,一切都是从这里开始,在master主机上默认路径为/srv/salt/目录
top.sls 默认从 base 标签开始解析执行,下一级是操作的目标,可以通过正则,grain模块,或分组名,来进行匹配,再下一级是要执行的state文件,不包换扩展名
一般对minion进行初始化操作时用top.sls比较多
通过正则进行匹配的示例
[root@master ~]# vim /srv/salt/top.sls
base:
'*':
- tengine
[root@master ~]# salt '*' state.highstate
通过分组名进行匹配的示例(必须要有 - match: nodegroup)
base:
group1:
- match: nodegroup
- web
通过grain模块匹配的示例(必须要有- match: grain)
base:
'os:Fedora':
- match: grain
- web
init.sls在一个子目录里面表示引导文件,我们可以在init.sls里面通过include模块来决定sls文件执行顺序
include:
- tengine.make
- tengine.install
文件树如下
[root@master ~]# tree /srv/salt/tengine
| --top.sls
| --init.sls
| --install.sls
| --make.sls
| --files
| --tengine-2.3.1.tar.gz
top.sls
base:
'*':
- tengine
init.sls
include:
- tengine.make
- tengine.install
make.sls
pkg-init:
pkg.installed:
- pkgs:
- automake
- gcc-c++
- zlib-devel
- openssl-devel
- pcre-devel
install.sls
include:
- tengine.make
tengine_source:
file.managed:
- name: /tmp/tengine-2.3.1.tar.gz
- unless: test -e /tmp/tengine-2.3.1.tar.gz
- source: salt://tengine/files/tengine-2.3.1.tar.gz
extract_tengine:
cmd.run:
- cwd: /tmp
- names:
- tar zxf tengine-2.3.1.tar.gz
- unless:
- test -d tengine-2.3.1
- require:
- file: tengine_source
tengine_compile:
cmd.run:
- cwd: /tmp/tengine-2.3.1
- names:
- ./configure --prefix=/usr/local/tengine && make && make install
- require:
- cmd: extract_tengine
- unless: test -d /usr/local/tengine
执行命令
salt '192.168.244.128' state.highstate
介绍了saltstack的一些基础命令,如何实现分组管理以及SLS相关内容
Grains是saltstack的一个组件,存放在minion端
当minion启动时会把收集到的数据静态存放在Grains中,只有minion重启时才会进行数据的更新
列出minion1所有的静态数据key
salt 'minion1' grains.list
列出node1所有的静态数据key与value
salt 'minion1' grains.items
列出所有minion的OS
salt '*' grains.item os
对匹配到的minion执行操作
salt -G 'os:CentOS' cmd.run ‘echo haha’
我们可以在/etc/salt/grains中定义
[root@minion1 ~]#vim /etc/salt/grains
role: nginx
env: test
myname: edison
也可以在/etc/salt/minion中定义,但是要满足YAML格式
[root@minion1 ~]#vim /etc/salt/minion
grains:
role:
- nginx
env:
- test
myname:
- edison
我们可以定制Grains来用于分组管理
写一个python脚本,在/srv/salt/下创建一个_grains的目录,然后在这个目录中创建**.py**文件
[root@minion1 ~]# mkdir /srv/salt/_grains
[root@minion1 ~]# vim /srv/salt/_grains/test.py
#!/usr/bin/env python
def my_grains():
grains = {}
grains['os'] = 'Redhat'
grains['name'] = 'Python'
return grains
然后在master端获取Grains
#列出多个
[root@master ~]# salt '192.168.244.129' grains.item role env myname
#列出一个
[root@master ~]# salt '192.168.244.129' grains.get myname
Grains在远程执行命令时很方便,我们可以按照Grains的一些指标来操作 比如把所有的web服务器的grains的role设置为nginx,这样我们就可以批量对nginx服务器进行操作
[root@minion1 ~]# vim /srv/salt/_grains/test.py
#!/usr/bin/env python
def my_grains():
grains = {}
grains['os'] = 'Redhat'
grains['role'] = 'nginx'
return grains
[root@master ~]# salt -G role:nginx cmd.run 'hostname'
[root@master ~]# salt -G os:Redhat cmd.run 'hostname'
系统自带——>grains文件写的——>minion配置文件写的——>自己写的
##每次修改数据都需要重启服务或刷新grains操作才会生效,这也印证了是静态数据
[root@master ~]# salt '*' saltutil.sync_grains ##用于刷新grains的数据
Pillar和Grains不同,Pillar是在master上定义的,并且是针对minion而去定义的信息,不需要到minion上进行操作
像一些重要的数据密码都可以存储在pillar上,pillar存储的是动态信息
pillar是存储在master端,缓存在minion端,存储的是minion的一些配置信息
查看minion的pillar信息
salt '*' pillar.items
查看某个pillar值
salt '*' pillar.item #只能看到顶级的
salt '*' pillar.get : #可以取到更小粒度的
刷新pillar
salt '*' saltutil.refresh_pillar
先在master端修改配置文件,打开pillar组件目录
[root@master ~]# vim /etc/salt/master
//找到如下内容,去掉注释
pillar_roots:
base:
- /srv/pillar
自定义配置文件
[root@master ~]# vim /srv/pillar/test.sls
conf: /etc/test.conf | myname: tpp
入口文件
[root@master ~]# vim /srv/pillar/top.sls
base:
'slaver.test.com':
- test
配置好后重启
[root@master ~]# systemctl restart salt-master
更改完配置文件后,我们可以通过·刷新pillar配置来获取新的动态
[root@master ~]# salt '*' saltutil.refresh_pillar
验证
[root@master ~]# salt 'slaver.test.com' pillar.items
[root@master ~]# salt 'slaver.test.com' pillar.item conf
[root@master ~]# salt 'slaver.test.com' pillar.item mynam
pillar同样可以用来作为salt的匹配对象
[root@master ~]# salt -I 'conf:/etc/123.conf' test.ping
[root@master ~]# salt -I 'conf:/etc/123.conf' cmd.run 'w'
案例一:通过yum方式安装apache
[root@master ~]# vim /etc/salt/master //打开如下内容的注释,添加主目录
file_roots:
base:
- /srv/salt
pillar_roots:
base:
- /srv/pillar
[root@master ~]# mkdir /srv/salt
[root@master ~]# vim /srv/salt/top.sls
base:
'slaver.test.com': #如果换成*,表示在所有minion执行apache模块
- apache
[root@master ~]# vim /srv/salt/apache.sls
apache-service: #自定义标签名
pkg.installed: #函数以及方法
- name: #如果只有一个服务,写成-name: httpd 一行即可
- httpd
- httpd-devel
service.running:
- name: httpd
- enable: True
[root@master ~]# salt 'slaver.test.com' state.highstate
案例二:目录管理
[root@master ~]# vim /srv/salt/editdir.sls
edit-dir:
file.recurse:
- name: /tmp/testdir
- source: salt://test1
- user: root
- file_mode: 644
- dir_mode: 755
- mkdir: True
- clean: True
#clean: True master处删除文件或目录,目标也会跟着删除,否则不会删除。可以默认设置为 False
[root@master ~]# mkdir -p /srv/salt/test1
[root@master ~]# vim /srv/salt/test1/1.txt
hello world
[root@master ~]# salt 'slaver.test.com' state.sls editdir
在master新建 my_dir 目录以及 test_dir.add 文件,删除 1.txt 文件
[root@master ~]# mkdir /srv/salt/test1/my_dir
[root@master ~]# touch /srv/salt/test1/my_dir/2.txt
[root@master ~]# touch /srv/salt/test1/testdir.add
[root@master ~]# rm -rf /srv/salt/test1/1.txt
[root@master ~]# salt 'slaver.test.com' state.sls editdir
成功在minion /tmp/testdir/ 目录下创建了my_dir目录和test_dir.add文件,并删除了1.txt文件
值得注意的是要成功创建 my_dir 目录,前提是 master端的my_dir 目录下要有文件,比如这里的2.txt 文件,如若没有,客户端是不会创建 my_dir 目录的
案例三:远程执行
前面提到的远程执行命令 test.ping、cmd.run,直接敲在命令行不太规范和优雅,我们可以通过pillar实现远程执行命令
[root@master ~]# vim /srv/salt/cmdtest.sls
cmd-test:
cmd.run:
- onlyif: test -f /tmp/123.txt
- names:
- touch /tmp/cmdtest.txt
- mkdir /tmp/cmdtest
- user: root
#onlyif条件:如果/tmp/123.txt存在,执行后面的命令;unless与之相反
[root@master ~]# salt 'slaver.test.com' state.sls cmdtest
案例四:任务计划cron
[root@master ~]# vim /srv/salt/crontest.sls
cron-test:
cron.present: #cron.absent是删除cron
- name: /bin/touch /tmp/111.txt #创建111.txt
- user: root
- minute: '*'
- hour: 20
- daymonth: 1-10
- month: '3,5'
- dayweek: '*'
# *需要用单引号引起来。当然我们还可以使用 file.managed 模块来管理 cron,因为系统的 cron都是以配置文件的形式存在的
[root@master ~]# salt "slaver.test.com" state.sls crontest
今天来学习一下如何通过编写 Saltstack 状态脚本来实现自动化批量部署Nginx、Redis
能力有限,内容为自身所学认知之文,不敢苟才,希望能够给有兴趣者一丁点帮助启发即可
我们现在 salt-master 的家目录下创建一个 Redis 目录,用来存放相关文件
mkdir /home/salt/redis/files -pv
创建好之后,根据自己需要将定制的redis的配置文件和注册服务文件放在files目录下
[root@server1 ~]# ll /home/salt/redis/files/
redis.conf
redis-server.service
redis-6.2.6.tar.gz
开始编写sls脚本
vim /home/salt/redis/install.sls
我们这次安装redis的版本为 6.2.6 版本
{% set VERSION = '6.2.6' %}
创建redis存放数据目录、日志目录、配置文件目录
redisdata_dir:
file.directory:
- name: /var/lib/redis
- user: root
- group: root
- makedirs: True
- unless:
- test -e /var/lib/redis
redislog_dir:
file.directory:
- name: /var/log/redis
- user: root
- group: root
- makedirs: True
- require:
- file: redisdata_dir
- unless:
- test -e /var/log/redis
redisconf_dir:
file.directory:
- name: /etc/redis
- user: root
- group: root
- makedirs: True
- require:
- file: redislog_dir
- unless:
- test -e /etc/redis
接着我们将 redis 压缩包分发到每台minion上
PS:redis的工作目录在 /opt/redis-6.2.6/ 下
redis_source:
file.managed:
- name: /opt/redis-{{VERSION}}.tar.gz
- source: salt://redis/files/redis-{{VERSION}}.tar.gz
- require:
- file: redisconf_dir
- unless:
- test -e /opt/redis-{{VERSION}}.tar.gz
然后解压缩
redis_extract:
cmd.run:
- cwd: /opt
- names:
- tar zxf redis- {{VERSION}}.tar.gz
- require:
- file: redis_source
- unless:
- test -e /opt/redis-{{VERSION}}
编译安装redis
redis_complie:
cmd.run:
- cwd: /opt/redis-{{VERSION}}
- names:
- make clean && make > /dev/null && make install > /dev/null
- require:
- cmd: redis_extract
- unless:
- test -e /usr/local/bin/redis-server
下发 Redis 服务配置文件并重新加载服务配置文件
redis_system:
file.managed:
- name: /usr/lib/systemd/system/redis-server.service
- source: salt://redis/files/redis-server.service
- require:
- cmd: redis_complie
- unless:
- test -e /usr/lib/systemd/system/redis-server.service
redis_service_reload:
cmd.run:
- names:
- systemctl daemon-reload
- require:
- file: redis_system
下发 Redis 配置文件
redis_conf:
file.managed:
- name: /etc/redis/redis.conf
- source: salt://redis/files/redis.conf
- require:
- cmd: redis_service_reload
- unless:
- test -e /etc/redis/redis.conf
启动Redis并加入到开机自启动中
redis_enable:
cmd.run:
- names:
- systemctl enable redis-server
- systemctl start redis-server
- unless:
- systemctl status redis-server
编写完之后我们在 master 上执行 salt 命令
salt ip地址 state.sls redis.install
完整脚本如下:
{% set VERSION = '6.2.6' %}
redisdata_dir:
file.directory:
- name: /var/lib/redis
- user: root
- group: root
- makedirs: True
- unless:
- test -e /var/lib/redis
redislog_dir:
file.directory:
- name: /var/log/redis
- user: root
- group: root
- makedirs: True
- require:
- file: redisdata_dir
- unless:
- test -e /var/log/redis
redisconf_dir:
file.directory:
- name: /etc/redis
- user: root
- group: root
- makedirs: True
- require:
- file: redislog_dir
- unless:
- test -e /etc/redis
redis_source:
file.managed:
- name: /opt/redis-{{VERSION}}.tar.gz
- source: salt://redis/files/redis-{{VERSION}}.tar.gz
- require:
- file: redisconf_dir
- unless:
- test -e /opt/redis-{{VERSION}}.tar.gz
redis_extract:
cmd.run:
- cwd: /opt
- names:
- tar zxf redis- {{VERSION}}.tar.gz
- require:
- file: redis_source
- unless:
- test -e /opt/redis-{{VERSION}}
redis_complie:
cmd.run:
- cwd: /opt/redis-{{VERSION}}
- names:
- make clean && make > /dev/null && make install > /dev/null
- require:
- cmd: redis_extract
- unless:
- test -e /usr/local/bin/redis-server
redis_system:
file.managed:
- name: /usr/lib/systemd/system/redis-server.service
- source: salt://redis/files/redis-server.service
- require:
- cmd: redis_complie
- unless:
- test -e /usr/lib/systemd/system/redis-server.service
redis_service_reload:
cmd.run:
- names:
- systemctl daemon-reload
- require:
- file: redis_system
redis_conf:
file.managed:
- name: /etc/redis/redis.conf
- source: salt://redis/files/redis.conf
- require:
- cmd: redis_service_reload
- unless:
- test -e /etc/redis/redis.conf
redis_enable:
cmd.run:
- names:
- systemctl enable redis-server
- systemctl start redis-server
- unless:
- systemctl status redis-server
我们在 salt-master 的家目录下创建 Nginx 目录来存放相关脚本文件
mkdir -pv /home/salt/nginx/files
创建好之后,根据自己需要将定制的 Nginx 的配置文件和注册服务文件放在files目录下
编写 init.sls 文件
vim /home/salt/nginx/init.sls
include:
- nginx.install
- nginx.conf
下面开始进行 Nginx 的安装,这里我写了两个脚本,分别对应Nginx的不同安装方式:
1、一个源码编译安装 Nginx
2、一个是 yum 安装 Nginx
首先编写安装脚本
vim /home/salt/nginx/install.sls
编译安装Nginx的话我们指定安装版本
{% set VERSION = '1.15.4' %}
创建Nginx工作目录、日志目录
data_dir:
file.directory:
- name: /var/lib/nginx
- user: root
- group: root
- makedirs: True
- unless:
- test -e /var/lib/nginx
log_dir:
file.directory:
- name: /var/log/nginx
- user: root
- group: root
- makedirs: True
- require:
- file: data_dir
- unless:
- test -e /var/log/nginx
下发 Nginx 压缩包到minio,接着进行解压缩
nginx_source:
file.managed:
- name: /opt/nginx-{{VERSION}}.tar.gz
- source: salt://nginx/nginx-{{VERSION}}.tar.gz
- require:
- file: log_dir
- unless:
- test -e /opt/nginx-{{VERSION}}.tar.gz
nginx_extract:
cmd.run:
- cwd: /opt
- names:
- tar zxf nginx- {{VERSION}}.tar.gz
- require:
- file: nginx_source
- unless:
- test -e /opt/nginx-{{VERSION}}
安装编译安装时所需要的工具包
nginx_pkg:
pkg.installed:
- pkgs:
- gcc
- openssl-devel
- pcre-devel
- zlib-devel
- require:
- file: nginx_extract
编译安装Nginx
指定Nginx的工作目录为:/opt/nginx
nginx_compile:
cmd.run:
- cwd: /opt/nginx-{{version}}
- names:
- ./configure --prefix=/opt/nginx --with-http_stub_status_module --with-file-aio --with-http_ssl_module && make && make install
- require:
- pkg: nginx_pkg
- unless: test -d /opt/nginx
接着编写配置下发脚本
vim /home/salt/nginx/conf.sls
创建Nginx配置文件目录软连接(个人习惯)
nginx_softlink:
cmd.run:
- name: ln -s /opt/nginx/conf/ /etc/nginx
下发Nginx配置文件
nginx_conf:
file.managed:
- name: /etc/nginx/nginx.conf
- source: salt://nginx/files/nginx.conf
- require:
- cmd: nginx_softlink
- unless:
- test -e /etc/nginx/nginx.conf
下发Nginx注册服务文件,并重新加载
nginx_system:
file.managed:
- name: /usr/lib/systemd/system/nginx.service
- source: salt://nginx/files/nginx.service
- require:
- file: nginx_conf
- unless:
- test -e /usr/lib/systemd/system/nginx.service
nginx_systemreload:
cmd.run:
- name:
- systemctl daemon-reload
- require:
- file: nginx_system
Nginx内核参数调优
nginx_kernel:
cmd.run:
- cwd: /etc/sysctl.conf
file.append:
- text:
- #set nginx kernel args
- net.ipv4.tcp_keepalive_time = 30
- net.ipv4.ip_local_port_range = 1024 65000
- net.ipv4.tcp_max_tw_buckets = 15000
- net.ipv4.tcp_tw_reuse = 1
- net.ipv4.tcp_tw_recycle = 0
- net.ipv4.tcp_fin_timeout = 30
- net.core.somaxconn = 65535
- net.core.netdev_max_backlog = 262144
- net.ipv4.tcp_max_orphans = 262144
- net.ipv4.tcp_max_syn_backlog = 262144
- net.ipv4.tcp_timestamps = 0
- net.ipv4.tcp_synack_retries = 1
- net.ipv4.tcp_syn_retries = 1
- unless: grep "#set nginx kernel args" /etc/sysctl.conf
cmd.run:
- name: /sbin/sysctl -p
启动 Nginx 并加入到开机自启动中
nginx_start:
cmd.run:
- name:
- systemctl start nginx
- systemctl enable nginx
- require:
- cmd: nginx_systemreload
- unless:
- systemctl status nginx
编写完之后我们在 master 上执行 salt 命令
salt ip地址 state.sls nginx.init
完整脚本如下:
install.sls
{% set VERSION = '1.15.4' %}
data_dir:
file.directory:
- name: /var/lib/nginx
- user: root
- group: root
- makedirs: True
- unless:
- test -e /var/lib/nginx
log_dir:
file.directory:
- name: /var/log/nginx
- user: root
- group: root
- makedirs: True
- require:
- file: data_dir
- unless:
- test -e /var/log/nginx
nginx_source:
file.managed:
- name: /opt/nginx-{{VERSION}}.tar.gz
- source: salt://nginx/nginx-{{VERSION}}.tar.gz
- require:
- file: log_dir
- unless:
- test -e /opt/nginx-{{VERSION}}.tar.gz
nginx_extract:
cmd.run:
- cwd: /opt
- names:
- tar zxf nginx- {{VERSION}}.tar.gz
- require:
- file: nginx_source
- unless:
- test -e /opt/nginx-{{VERSION}}
nginx_pkg:
pkg.installed:
- pkgs:
- gcc
- openssl-devel
- pcre-devel
- zlib-devel
- require:
- file: nginx_extract
nginx_compile:
cmd.run:
- cwd: /opt/nginx-{{version}}
- names:
- ./configure --prefix=/opt/nginx --with-http_stub_status_module --with-file-aio --with-http_ssl_module && make && make install
- require:
- pkg: nginx_pkg
- unless: test -d /opt/nginx
conf.sls
nginx_softlink:
cmd.run:
- name: ln -s /opt/nginx/conf/ /etc/nginx
nginx_conf:
file.managed:
- name: /etc/nginx/nginx.conf
- source: salt://nginx/files/nginx.conf
- require:
- cmd: nginx_softlink
- unless:
- test -e /etc/nginx/nginx.conf
nginx_system:
file.managed:
- name: /usr/lib/systemd/system/nginx.service
- source: salt://nginx/files/nginx.service
- require:
- file: nginx_conf
- unless:
- test -e /usr/lib/systemd/system/nginx.service
nginx_systemreload:
cmd.run:
- name:
- systemctl daemon-reload
- require:
- file: nginx_system
nginx_kernel:
cmd.run:
- cwd: /etc/sysctl.conf
file.append:
- text:
- #set nginx kernel args
- net.ipv4.tcp_keepalive_time = 30
- net.ipv4.ip_local_port_range = 1024 65000
- net.ipv4.tcp_max_tw_buckets = 15000
- net.ipv4.tcp_tw_reuse = 1
- net.ipv4.tcp_tw_recycle = 0
- net.ipv4.tcp_fin_timeout = 30
- net.core.somaxconn = 65535
- net.core.netdev_max_backlog = 262144
- net.ipv4.tcp_max_orphans = 262144
- net.ipv4.tcp_max_syn_backlog = 262144
- net.ipv4.tcp_timestamps = 0
- net.ipv4.tcp_synack_retries = 1
- net.ipv4.tcp_syn_retries = 1
- unless: grep "#set nginx kernel args" /etc/sysctl.conf
cmd.run:
- name: /sbin/sysctl -p
nginx_start:
cmd.run:
- name:
- systemctl start nginx
- systemctl enable nginx
- require:
- cmd: nginx_systemreload
- unless:
- systemctl status nginx
编写 install.sls
vim /home/salt/nginx/install.sls
update_yum:
cmd.run:
- name: yum update -y
nginx_install:
pkg.installed:
- pkgs:
- epel-release
- nginx
- require:
- cmd: update_yum
- unless:
- systemctl status nginx
编写 conf.sls
vim /home/salt/nginx/conf.sls
yum 安装 Nginx配置目录在 /etc/nginx 下
下发 Nginx 配置文件
nginx_conf:
file.managed:
- name: /etc/nginx/nginx.conf
- source: salt://nginx/files/nginx.conf
- unless:
- test -e /etc/nginx/nginx.conf
Nginx 内核参数调优
nginx_kernel:
cmd.run:
- cwd: /etc/sysctl.conf
file.append:
- text:
- #set nginx kernel args
- net.ipv4.tcp_keepalive_time = 30
- net.ipv4.ip_local_port_range = 1024 65000
- net.ipv4.tcp_max_tw_buckets = 15000
- net.ipv4.tcp_tw_reuse = 1
- net.ipv4.tcp_tw_recycle = 0
- net.ipv4.tcp_fin_timeout = 30
- net.core.somaxconn = 65535
- net.core.netdev_max_backlog = 262144
- net.ipv4.tcp_max_orphans = 262144
- net.ipv4.tcp_max_syn_backlog = 262144
- net.ipv4.tcp_timestamps = 0
- net.ipv4.tcp_synack_retries = 1
- net.ipv4.tcp_syn_retries = 1
- unless: grep "#set nginx kernel args" /etc/sysctl.conf
cmd.run:
- name: /sbin/sysctl -p
启动 Nginx 并加入到开机自启动中
nginx_start:
cmd.run:
- name:
- systemctl start nginx
- systemctl enable nginx
- require:
- file: nginx_conf
- unless:
- systemctl status nginx
完整脚本如下:
install.sls
update_yum:
cmd.run:
- name: yum update -y
nginx_install:
pkg.installed:
- pkgs:
- epel-release
- nginx
- require:
- cmd: update_yum
- unless:
- systemctl status nginx
conf.sls
nginx_conf:
file.managed:
- name: /etc/nginx/nginx.conf
- source: salt://nginx/files/nginx.conf
- unless:
- test -e /etc/nginx/nginx.conf
nginx_kernel:
cmd.run:
- cwd: /etc/sysctl.conf
file.append:
- text:
- #set nginx kernel args
- net.ipv4.tcp_keepalive_time = 30
- net.ipv4.ip_local_port_range = 1024 65000
- net.ipv4.tcp_max_tw_buckets = 15000
- net.ipv4.tcp_tw_reuse = 1
- net.ipv4.tcp_tw_recycle = 0
- net.ipv4.tcp_fin_timeout = 30
- net.core.somaxconn = 65535
- net.core.netdev_max_backlog = 262144
- net.ipv4.tcp_max_orphans = 262144
- net.ipv4.tcp_max_syn_backlog = 262144
- net.ipv4.tcp_timestamps = 0
- net.ipv4.tcp_synack_retries = 1
- net.ipv4.tcp_syn_retries = 1
- unless: grep "#set nginx kernel args" /etc/sysctl.conf
cmd.run:
- name: /sbin/sysctl -p
nginx_start:
cmd.run:
- name:
- systemctl start nginx
- systemctl enable nginx
- require:
- file: nginx_conf
- unless:
- systemctl status nginx
ckets = 15000
- net.ipv4.tcp_tw_reuse = 1
- net.ipv4.tcp_tw_recycle = 0
- net.ipv4.tcp_fin_timeout = 30
- net.core.somaxconn = 65535
- net.core.netdev_max_backlog = 262144
- net.ipv4.tcp_max_orphans = 262144
- net.ipv4.tcp_max_syn_backlog = 262144
- net.ipv4.tcp_timestamps = 0
- net.ipv4.tcp_synack_retries = 1
- net.ipv4.tcp_syn_retries = 1
- unless: grep "#set nginx kernel args" /etc/sysctl.conf
cmd.run:
- name: /sbin/sysctl -p
启动 Nginx 并加入到开机自启动中
nginx_start:
cmd.run:
- name:
- systemctl start nginx
- systemctl enable nginx
- require:
- file: nginx_conf
- unless:
- systemctl status nginx
完整脚本如下:
install.sls
update_yum:
cmd.run:
- name: yum update -y
nginx_install:
pkg.installed:
- pkgs:
- epel-release
- nginx
- require:
- cmd: update_yum
- unless:
- systemctl status nginx
conf.sls
nginx_conf:
file.managed:
- name: /etc/nginx/nginx.conf
- source: salt://nginx/files/nginx.conf
- unless:
- test -e /etc/nginx/nginx.conf
nginx_kernel:
cmd.run:
- cwd: /etc/sysctl.conf
file.append:
- text:
- #set nginx kernel args
- net.ipv4.tcp_keepalive_time = 30
- net.ipv4.ip_local_port_range = 1024 65000
- net.ipv4.tcp_max_tw_buckets = 15000
- net.ipv4.tcp_tw_reuse = 1
- net.ipv4.tcp_tw_recycle = 0
- net.ipv4.tcp_fin_timeout = 30
- net.core.somaxconn = 65535
- net.core.netdev_max_backlog = 262144
- net.ipv4.tcp_max_orphans = 262144
- net.ipv4.tcp_max_syn_backlog = 262144
- net.ipv4.tcp_timestamps = 0
- net.ipv4.tcp_synack_retries = 1
- net.ipv4.tcp_syn_retries = 1
- unless: grep "#set nginx kernel args" /etc/sysctl.conf
cmd.run:
- name: /sbin/sysctl -p
nginx_start:
cmd.run:
- name:
- systemctl start nginx
- systemctl enable nginx
- require:
- file: nginx_conf
- unless:
- systemctl status nginx