一、安装
SaltStack基于Master-Minion架构,采用消息队列ZeroMQ在Master和Minion之间传递消息。Master在4505端口发送消息,所有的Minion都会连接到Master的4505端口接收消息。当Master发送消息时,所有Minion都会收到Master发送的消息,然后Minion根据自身的信息判断是否匹配Master指定的Minion信息,匹配到则作出回应,不匹配则不作回应,Master在4506端口接收Minion的响应消息。
在主控端安装salt-master(CentOS7系统):
# yum -y install https://repo.saltstack.com/yum/redhat/salt-repo-latest-2.el7.noarch.rpm
# yum -y install salt-master
salt-master基础配置:
# egrep -v '^$|^#' /etc/salt/master
default_include: master.d/*.conf
interface: 0.0.0.0
timeout: 5
file_roots: #用来存放状态管理文件
base:
- /salt/
启动salt-master:
# systemctl enable salt-master
# systemctl start salt-master
在被控端安装salt-minion(CentOS7系统):
# yum -y install https://repo.saltstack.com/yum/redhat/salt-repo-latest-2.el7.noarch.rpm
# yum -y install salt-minion
salt-minion基础配置:
# egrep -v '^$|^#' /etc/salt/minion
master: 192.168.18.131 #Master地址
id: server01 #自定义的唯一标识一个Minion的ID号
启动salt-minion:
# systemctl enable salt-minion
# systemctl start salt-minion
二、认证
Master和Minion启动后,都会生成一组密钥对,存放在“/etc/salt/pki”目录下。Minion启动后,会将自己的公钥(保存在minion.pub文件中)连同ID发送给配置文件中“master”配置项指定的Master。Master会将Minion发来的未接收的公钥先保存在“/etc/salt/pki/master/minions_pre/”目录下,以Minion的ID命名的文件中:
# ls /etc/salt/pki/master/minions_pre/
server01 server02
使用salt-key
命令来管理这些公钥:
salt-key -l "pre"
:列出所有未接收的Key;salt-key -l "accept"
:列出所有已经接收的Key;salt-key -L
:列出各种类型的所有Key;salt-key -a "server01"
:接收“server01”发来的Key;salt-key -A
:接收所有Minion发来的Key‘’;salt-key -r "server01"
:拒绝接收“server01”发来的Key;salt-key -R
:拒绝所有Minion发来的Key;salt-key -d "server01"
:删除“server01”的Key;salt-key -D
:删除所有类型的所有Key。
Master接收Minion发来的公钥后,会将接收的Minion的公钥保存在“/etc/salt/pki/master/minions”目录下,以Minion的ID命名的文件中:
# ls /etc/salt/pki/master/minions
server01 server02
同时Master会将自己的公钥也发送给所有已经接收公钥的Minion,Minion将接收到的Master的公钥保存在“/etc/salt/pki/minion/minion_master.pub”文件中。
Master接收所有的Key之后,测试Master和Minion之间是否能够正常通信,使用以下命令向所有Minion发送一个消息:
# salt '*' test.ping
命令中的'*'
代表匹配所有Minion,单引号''
起到转义的作用,也可以将''
替换为“\”等。
对所有的Minion执行一条Shell命令:
# salt '*' cmd.run "date"
使用cmd.run
可以执行所有Shell命令,对命令中包含特殊字符的,需要转义后才能执行成功。
三、YAML语法
来自百度百科(YAML)中的一段:
house:
family:
name: Doe
parents:
- John
- Jane
注意:
- YAML使用缩进和冒号表示层级关系;
- SaltStack严格使用两个空格表示缩进;
- 冒号之后一定有一个空格,以冒号结尾的行除外;
- 对只有一个值的键值对,可以将键和值写在一行,如“name: Doe”;
- 对有多个值的键值对,用减号“-”来列出多个值;
- 减号“-”之后也要有一个空格。
四、目标匹配
目标匹配,即Master需要对哪些Minion发送消息。
- 默认类型(glob):
# salt '*' test.ping
- 基于正则表达式匹配(pcre):
# salt -E '^server0[1-2]$' test.ping
- 列表匹配(list):
# salt -L 'server01,server02' test.ping
- 根据IP匹配:
# salt -S '192.168.18.131' test.ping
# salt --ipcidr '192.168.18.0/24' test.ping
- 根据Grains信息匹配:
# salt -G 'os:centos' test.ping
- 根据Pillar信息匹配:
# salt -I 'my_var:my_val' test.ping
- 混合匹配:
# salt -C 'G@os:centos and E@^server0[1-2]$' test.ping
- 分组匹配(nodegroup):
使用分组匹配时,需要先在“/etc/salt/master.d/”目录下定义分组配置:
# cat /etc/salt/master.d/server.conf #文件名和路径必须以Master配置文件中“default_include”配置项定义为准;
nodegroups: #固定写法,遵循YAML语法
server: 'L@server01,server02,server03' #将分组名作为键,以列表形式匹配指定Minion
# salt -N 'server' test.ping #对“server”分组执行命令
五、状态管理
5.1、状态管理文件路径
状态管理文件的路径,在Master配置文件中定义:
file_roots: #用来存放状态管理文件
base:
- /salt/
5.2、编写状态管理文件
以安装“httpd”为例,编写状态管理文件:
# mkdir -p /salt/web/files
# mv httpd.conf /salt/web/files/ #将自定义的httpd配置文件放到files目录下
# cat /salt/web/apache.sls #文件后缀通常是“.sls”
apache-install: #每个状态都应该有一个唯一的ID
pkg.installed: #软件包管理模块,用于安装软件包
- names: #安装的软件包的名称
- httpd
- httpd-tools
apache-config: #唯一的状态ID
file.managed: #文件管理模块
- name: /etc/httpd/httpd.conf #文件在Minion上的路径和名称
- source: salt://web/files/httpd.conf #文件在Master上的路径和名称。“salt://”代表“file_roots”配置项指定的路径
- user: root #文件属主
- group: root #文件属组
- mode: 644 #文件权限
apache-service: #唯一的状态ID
service.running: #服务运行管理模块
- name: httpd #服务名称
- enable: True #是否添加到开机自启动
5.3、运行状态管理
对Minion “server01”运行指定的状态管理配置:
# salt 'server01' state.sls web.apache test=true
- state.sls:用于运行状态管理文件
- web:状态管理文件相对于“file_roots”配置项指定路径的相对路径,路径中的“/”用“.”代替;
- apache:是文件“apache.sls”的前缀名。
- test=true:试运行,并没有在Minion上真正执行,可以在真正运行之前检查状态和配置是否正确。
5.4、状态间关系
SaltStack允许一个状态依赖于其它状态,依赖关系包含以下几种:
- require:本状态依赖于其它某个状态
例如,当httpd服务正常安装后,才推送httpd配置文件:
apache-install:
pkg.installed:
- name: httpd
apache-config:
file.managed:
- name: /etc/httpd/conf/httpd.conf
- source: salt://web/files/httpd.conf
- user: root
- group: root
- mode: 644
- require:
- pkg: apache-install
- require_in:被某个状态依赖
例如,将httpd服务的安装声明为被推送httpd配置文件所依赖:
apache-install:
pkg.installed:
- name: httpd
- require_in:
- file: apache-config
- watch:关注某个状态
例如,让httpd服务的运行状态关注httpd配置文件:
apache-service:
service.running:
- name: httpd
- enable: True
- reload: True
- watch:
- file: apache-config
- watch_in:被某个状态关注
例如,让httpd配置文件被httpd服务的运行状态所关注:
apache-config:
file.managed:
- name: /etc/httpd/conf/httpd.conf
- source: salt://web/files/httpd.conf
- user: root
- group: root
- mode: 644
- watch_in:
- service: apache-service
5.5、状态判断
unless
用来判断给定的条件是否成立,不成立时才执行状态。
例如,当判断到“/data”目录不存在时,才新建该目录:
# cat /salt/web/datadir.sls
data-dir:
file.directory:
- name: /data
- user: root
- group: root
- mode: 755
- unless: test -d /data
# salt 'server01' state.sls web.datadir
5.6、include
使用include
将多个状态配置集中在一个配置文件中执行:
# cat /salt/web/init.sls
include:
- web.apache
- web.mysql
- web.php
- web.zabbix-agent
当执行salt '*' state.sls web
时相当于执行了salt '*' state.sls web.init
。
更多状态管理模块,参考:all-salt-state
六、Jinja模板
通常情况,我们会根据不同的主机对服务做不同的配置,比如Apache在不同的主机上监听的地址不同。使用Jinja模板可以将这些信息声明为变量,然后根据主机的信息为变量设置不同的值,
6.1、简单的例子
以Apache监听的IP地址为例,首先修改“/salt/web/files/httpd.conf”配置文件:
# vim /salt/web/files/httpd.conf
Listen {{ ip }}:{{ port }}
在状态管理文件中引用该文件:
# vim /salt/web/apache.sls
……
apache-config:
file.managed:
- name: /etc/httpd/httpd.conf
- source: salt://web/files/httpd.conf
- user: root
- group: root
- mode: 644
- template: jinja
- defaults:
ip: {{ grains['fqdn_ip4'][0] }}
port: 8080
6.2、Jinja语法
6.2.1、基本语法
包含三种基本语法:
- 控制结构:{% %};
- 变量取值:{{ }};
- 注释:{# #};
6.2.2、变量
Jinja识别所有的Python数据类型,包括列表、字典、对象等。
取字典中的值:{{ mydict['key'] }}
取列表中指定偏移量的值:{{ mylist[3] }}
将变量的值作为偏移量,取列表中的值:{{ mylist[myintvar] }}
从对象的方法中取值:{{ myobj.method() }}
6.2.3、过滤器
变量可以通过“过滤器”修改,过滤器与变量用管道(|)分隔。多个过滤器可以链式调用,前一个过滤器的输出会作为后一个过滤器的输入。
{{ "Hello World" | replace("Hello", "Goodbye") }} -> Goodbye World
{{ "Hello World" | replace("Hello", "Goodbye") | upper }} -> GOODBYE WORLD
{{ 43.5 | round }} -> 44.0
{{ 43.5 | round | int }} -> 44
6.2.4、控制结构
if else
结构:
{% if kenny.sick %}
Kenny is sick.
{% elif kenny.dead %}
You killed Kenny! You bastard!!!
{% else %}
Kenny looks okay ---so far
{% endif %}
for
循环:
{% for user in users %}
{{ user.username }}
{% endfor %}
6.3、使用
批量添加用户:
{% set users = ['name1,name2'] %}
{% for user in users %}
{{ user }}:
user.present:
- shell: /bin/bash
- home: /home/{{ user }}
- password: ‘$1$Jane$A0GJ5mLtd4Ze3gm/0MYcB0’
group.present:
- name: {{ user }}
{% endfor %}
加密密码可以使用以下命令生成:
# echo "password" | openssl passwd -stdin -1 -salt 'username'
七、远程执行
SaltStack提供了超级模块cmd.run
,使用它可以对Minion执行所有Shell命令,但是也提供了丰富的远程执行模块,以下命令用于获取所有远程执行模块及其帮助信息:
# salt 'server01' sys.list_modules #列出所有远程执行模块
# salt 'server01' sys.list_functions file #列出“file”模块的所有方法
# salt 'server01' sys.doc file.access #查看“file.access”方法的帮助信息
八、Job管理
SaltStack每次执行任务,都会产生一个以时间标记的“jid”,用于唯一地表示一个任务。
8.1、使用salt-run管理Job
- 列出所有已经执行过的所有Job的信息:
salt-run jobs.list_jobs
; - 列出已经执行过的指定Jid的信息:
salt-run jobs.list_job 'jid'
; - 查看正在执行的Job的信息:
salt-run jobs.lookup_jid 'jid'
;
8.2、使用saltutil模块管理Job
- 查看正在执行的Job的信息:
salt 'server01' saltutil.find_job 'jid'
; - kill掉正在运行的指定的Job:
salt 'server01' saltutil.kill_job 'jid'
。
九、数据信息
9.1、Grains
Grains用于在Minion启动时收集保存在Minion上的静态数据。可以被用于:在状态管理中用于在配置文件中获取Minion信息;在远程执行时匹配相应的Minion;用来查询Minion的信息。
相关命令:
- 查看Minion所有的Grains信息:
salt 'server01' grains.ls
; - 以键值对形式列出所有Grains:
salt 'server01' grains.items
; - 查看某个Grains的值:
salt 'server01' grains.get ip_interfaces:ens33
; - 刷新Grains:
salt 'server01' saltutil.sync_grains
;
通过Minion配置文件自定义Grains:
# vim /etc/salt/minion #修改Minion配置文件
grains:
roles:
- webserver
# systemctl restart salt-minion #重启salt-minion
# salt 'server03' grains.get roles #在Master上获取信息
通过Python脚本自定义Grains:
# mkdir /salt/_grains #在Master的“file_roots”路径下新建“_grains”目录,用来存放Python脚本
# vim /salt/_grains/logtime.py #在脚本中定义Grains信息键值对
#!/usr/bin/env python
from datetime import date
def logtime():
now = date.today()
format_date = now.isoformat()
logtime = {'logtime': format_date}
return logtime
# salt 'server01' saltutil.sync_grains #将键值对同步到指定Minion
# salt 'server01' grains.get logtime #获取Grains信息
两种自定义Grains方式的差异:
- 通过配置文件定义时,需要修改每个Minion的配置文件,并且需要重启才能生效;
- 通过脚本定义时,只需要编写好脚本,即可通过"
saltutil.sync_grains
"方法同步到所有Minion,并且不需要重启Minion。
9.2、Pillar
Pillar是跟Grains一样的数据结构,只是Grains描述的是Minion的静态信息,保存在Minion本地;Pillar则在Master端定义,用来描述可变信息。
一般Pillar可以这样使用,在状态管理文件中,通过Pillar定义变量,然后在执行状态管理时为其赋值,比如向Minion推送指定目录下的指定文件。现在使用Pillar推送Apache配置文件:
# cat /salt/web/apache-config.sls
apache-root:
file.directory:
- name: /etc/{{ pillar['dir'] }}
- unless: test -d /etc/{{ pillar['dir'] }}
apache-config:
file.managed:
- name: /etc/{{ pillar['dir'] }}/{{ pillar['config'] }}
- source: salt://{{ pillar['webdir'] }}/files/{{ pillar['config'] }}
- require:
- file: apache-root
# salt 'server02' state.sls web.apache-config pillar="{'webdir': 'web', 'dir': 'httpd', 'config': 'httpd.conf'}"
在“apache-config.sls”文件中,首先通过“apache-root”状态判断相关配置文件的上一级目录是否存在,不存在时创建;
在“apache-config”状态中,通过“name”定义配置文件在Minion上的路径,通过“pillar[‘dir’] ”声明配置文件所在目录,“pillar[‘config’]”声明配置文件名称;通过“source”定义配置文件在Master上的存储路径;
在执行该状态时,通过pillar
为状态文件中的变量赋值。
十、salt-ssh
SaltStack使用“salt-ssh”实现无agent管理。需要先安装它:
# yum -y install salt-ssh
编辑使用salt-ssh管理的主机:
# cat /etc/salt/roster
server01: #主机ID
host: 192.168.18.131 #主机IP地址
user: root #主机上的SSH用户
passwd: 123123 #SSH用户密码
port: 22 #SSH端口
server02:
host: 192.168.18.132
user: root
passwd: 123123
port: 22
server03:
host: 192.168.18.133
user: root
passwd: 123123
port: 22
向所有主机发送一条测试命令,使用“-i”选项可以忽略在第一次SSH连接时的提示信息:
# salt-ssh '*' test.ping -i
向所有主机执行一条Shell命令:
# salt-ssh '*' -r "date"
向所有主机执行状态管理:
# salt-ssh 'server01' state.sls web.apache -v