自动化运维工具——Salt(saltstack)实践及应用

cuixiaogang

前记

本文记录了Salt的实战及相关经验,需要提前掌握Salt的基础概念等知识点,可以参考《自动化运维工具——Salt(saltstack)基础概念及安装部署

环境相关配置

nodegroups配置

nodegroups被称为“逻辑分组”,支持用户对所有的minion进行分组管理

为什么需要nodegroups

举个例子,我有100台服务器,这些服务器上部署的环境如下:

  • 20台WEB服务器
  • 10台Mysql服务器
  • 5台Redis服务器
  • 65台文件存储服务器

现在我想给20台服务器应用配置:

1
salt 'web-server-01' 'web-server-02' ... 'web-server-20' state.apply nginx

当然,我们可以使用正则来匹配所有的minion

1
salt -E 'web-service-\\.*' state.apply nginx

但是如果我们使用了nodegroups,就会更加方便(示例):

1
2
nodegroups:
web-service: 'E@web-service-\.*'
1
salt -N 'web-service' state.apply nginx

配置的使用

  • 配置文件地址:通用场景下,我们会把nodegroups的配置内容放在/etc/salt/master.d/nodegroups.conf文件中,当然也可以放在其他目录下,这取决于/etc/salt/master配置文件中的includ配置项

master的include配置项

  • 配置格式(示例):yaml格式
1
2
3
4
5
6
7
nodegroups:
# 正则模式
scandb-shcdt: 'E@scandb.*\.safe\.shcdt\.testdomain\.net'
CloudSafeLine-1: 'E@scandb(0[3-9]|1[0-2])\.safe\.shcdt\.testdomain\.net'

# 列表模式
PkgAssemble: 'L@scandb19.safe.lycc.testdomain.net,scandb20.safe.lycc.testdomain.net,scandb21.safe.lycc.testdomain.net'

Pillar配置

Pillar是SaltStack中一个非常核心且重要的组件,它用于存储和管理敏感数据,并将这些数据安全地分发给指定的Minion。

可以将Pillar理解为一个给特定服务器定制的、加密的 “配置字典” 或 “密码箱”。在State中配置模板时,可以使用{{ pillar['db_credentials']['password'] }}替换掉当前Minion中的变量

适用场景

  • 安全敏感数据存储:Pillar 数据在传输到 Minion 之前是加密的,确保了数据在网络传输中的安全性。比如服务器密码、SSH密钥、AWS/Azure等云服务的API密钥、数据库凭证等
  • 精细化的数据分发:通过Pillar的top.sls文件,可以精确控制 “哪个Pillar数据块” 下发给 “哪些 Minion”。比如所有webserver组的Minion可以获取apache的配置数据;所有dbserver组的Minion可以获取mysql的密码和配置。
  • 层级化和动态化:Pillar 数据是层级化的(YAML 格式),易于组织和管理。
  • 作为 State 文件的 “变量” 源:在 Salt 的 State 文件(.sls 文件)中,你可以方便地引用 Pillar 数据,从而使你的配置管理更加灵活和通用。

如何配置

  • 配置文件位置:通用场景下,我们把/srv/pillar作为Pillar的配置根目录,这取决与你的/etc/salt/master配置

master中的Pillar配置根目录项

  • Pillar配置如下(示例):
1
2
3
4
5
6
/srv/pillar
|- top.sls
|- idc.sls
|- scan
|- scan_frontend.sls
|- scan_unit_centos.sls
  • top.sls文件内容(示例)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
base:
# nodegroup匹配
'CloudSafeLine-1':
- match: nodegroup
- idc
- scan.scan_frontend
# 精确匹配(支持通配)
'scanunit???.shcdt.testdomain.net':
- idc
- scan.scan_unit_centos
# list匹配
'monitor_etcd_10.161.160.70,monitor_etcd_10.161.180.10':
- match: list
- idc
# pcre匹配
'kaba\d{3}v\.scanunit\.lycc\.qihoo\.net':
- match: pcre
- idc
  • idc.sls文件内容(示例)
1
2
3
idc: shcdt
grp: group101
dlc_repo: 192.168.1.115
  • scan/scan_frontend.sls配置内容(示例)
1
2
3
frontend:
monitor_host: scanmon.group101.testdomain.net
logsrv: audit.group10.testdomain.net

详细说明(重点)

  • top.sls中的base,表示的是Pillar的环境,这个环境通常是base,这取决于你的/etc/salt/master配置。在使用salt命令时,加入参数-e dev/prod,来指定应用的环境。

Pillar默认环境配置

  • top.sls的配置中,支持nodegroup、pcre、list、主机名(默认,支持通配符)匹配Minion

  • top.sls中的每一个Minion(组),都可以存在多个配置项(配置文件),这些配置项支持多级目录模式(以.进行分割)

Pillar规则的优先级

  • 环境之间的优先级:base与dev/prod着两个环境不同,base环境中的配置总是被定义,但会被当前使用的环境的配置所覆盖
  • 同一环境内的匹配规则优先级:所有匹配规则都会生效,但是越靠后的优先级越高(冲突时)
  • 同一个匹配规则内的SLS文件优先级:加载顺序从上到下,越靠后的优先级越高(冲突时)

State配置

State是SaltStack中用于定义和强制执行系统 “应有状态”的核心组件。你可以把它理解为一份“系统配置说明书”或“烹饪食谱”。

State是用来对Minion做详细的环境定义的,它可以配置某个或某组Minion拥有那些程序、目录、文件、定时任务、环境变量等等

如何配置

  • 先配置/srv/salt/top.sls,当然,也可以修改这个配置文件的位置,这取决于/etc/salt/master中的配置项

state的file_roots配置项

  • 配置内容如下(示例):
1
2
3
4
5
6
7
8
9
10
11
12
online:
'scandb-shcdt':
- match: nodegroup
- init.environment
- init.directory
'CloudSafeLine-1':
- match: nodegroup
- DownScanClient
- KafkaScanQueryUniq
- NewScanClient
- scan_frontend
- scan_dispatcher
  • 上面的配置内容含义如下:

    • 在online环境下,存在如下配置,会覆盖base环境的内容(当前base无配置项)。
    • 匹配scandb-shcdt的nodegroup这些Minion,使其执行online/init/environment.slsonline/init/directory.sls这两个配置项
    • 匹配CloudSafeLine-1的nodegroup这些Minion,使其执行online/DownScanClient.slsonline/KafkaScanQueryUniq.slsonline/NewScanClient.slsonline/scan_frontend.slsonline/scan_dispatcher.sls这五个配置项
  • online/init/environment.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
# 上传文件到/etc/cron.hourly/ntpdate.cron
# 源文件根目录/srv/salt/online,可在/etc/salt/master中配置
# 源文件地址/srv/salt/online/init/ShellScripts/ntpdate.cron
/etc/cron.hourly/ntpdate.cron:
file.managed:
- source: salt://init/ShellScripts/ntpdate.cron
- user: root
- group: root
- mode: 755

# 依旧是上传文件
# 注意,这里使用了Pillar配置,也就是说/srv/salt/online/init/Configs/DLC.repo文件中,应该存在pillar变量
/etc/yum.repos.d/DLC.repo:
file.managed:
- source: salt://init/Configs/DLC.repo
- template: jinja
- user: root
- group: root
- mode: 644

# 安装某个软件/程序
nmon:
pkg.installed

# 对Minion环境进行判断,如果系统级别为6.2,则执行下面的环境
# 看情况应该是6.2版本的系统不支持原生的lockf程序
{% if grains['osrelease'] == '6.2' %}

Test-lockf:
pkg.installed

{% endif %}

# 引入其他/srv/salt/online/init/中的其他配置文件
include:
- init.environment_tuning_system
- init.environment_centos6
- init.environment_centos7
- init.environment_chk_worker_live
  • salt://init/Configs/DLC.repo中的配置(Pillar示例)
1
2
3
4
5
[DLC]
name=CentOS-$releasever - DLC
# 这里使用了pillar变量
baseurl=http://{{pillar['dlc_repo']}}:8360/repo/$releasever
gpgcheck=0
  • online/init/directory.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
# 创建目录,用户及组为cloud,权限为755,recurse表示递归创建
/home/s/bin:
file.directory:
- user: cloud
- group: cloud
- dir_mode: 755
- file_mode: 755
- makedirs: True
- recurse:
- mode

# 定时任务,每个5分钟执行一次这个命令
/home/s/apps/CloudSafeLine/clear.sh >/dev/null 2>&1:
cron.present:
- identifier: CLEAN_CloudSafeLine
- user: cloud
- minute: '5'

# 定时任务,每分钟清理一次文件
find /home/s/var/log/ -type f -mtime +1 -name "scan*" | xargs rm -f >/dev/null 2>&1:
cron.present:
- identifier: CLEAN_VAR_LOG
- user: cloud
- minute: '1'
- hour: '0'
  • State是Salt中最复杂且最核心的配置,详细的配置项可以参考《官网手册

相关命令

salt-key

管理Minion的命令,用于接受、拒绝、删除和列出 Minion 的认证密钥。

1
salt-key -L

上述命令会列出所有已知的Minion及其状态,主要包含三部分的列表:

  • Accepted Keys:这些Minion已经被Master认证的,通常显示为绿色,Master可以向这些Minion发送命令并接收结果
  • Denied Keys:这些Minion已经被Master拒绝的,通常显示为红色,这些Minion无法与Master通信
  • Unaccepted Keys:这些Minion还未被Master认证(待审批状态),通常显示为黄色或蓝色,这些 Minion 暂时无法被管理,等待管理员决定是接受还是拒绝。

salt-key -L示例

常用命令

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
# 列出所有未认证的Minion
salt-key -l un
# 列出所有已认证的Minion
salt-key -l acc
# 列出所有被拒绝的Minion
salt-key -l den
# 列出所有被吊销的Minion
salt-key -l rej
# 列出所有Minion,等同于salt-key -L
salt-key -l all

# 接受单个 Minion
sudo salt-key -a web-staging-01
# 接受所有未认证的 Minion
sudo salt-key -A

# 拒绝单个 Minion
sudo salt-key -r new-db-server
# 拒绝所有未认证的 Minion
sudo salt-key -R

# 删除单个 Minion 的密钥(例如,当它下线或重装系统后)
sudo salt-key -d compromised-minion
# 删除所有 Minion 的密钥(谨慎使用!)
sudo salt-key -D

salt

远程执行命令。用于从Master向Minion发送指令并执行。

1
salt [options] '<target>' <function> [arguments]
  • :目标匹配表达式
    • 默认:精确匹配,支持通配符
    • -E <pcre>:正则匹配,salt -E '^web-prod-\d+$' test.ping
    • -G <grain_key:grain_value>:环境匹配,salt -G 'os:Ubuntu' pkg.installed name=nginx
    • -L <list>:列表匹配,salt -L 'web-01,db-01' cmd.run 'uptime'
    • -N <nodegroup>:Nodegroup 匹配,salt -N webservers state.apply nginx
    • -C <cond1> and <cond2> not...:复合匹配,salt -C 'G@os:Ubuntu and E@^web-.*' test.ping
  • :执行函数:
    • test: 用于测试和诊断。
      • test.ping: 检查 Minion 是否在线且响应。
      • test.version: 获取 Minion 的 Salt 版本。
    • cmd: 用于在 Minion 上执行 shell 命令。
      • cmd.run: 执行一条命令并返回其标准输出。
      • cmd.script: 在 Minion 上下载并执行一个脚本。
    • pkg: 用于管理软件包。
      • pkg.installed: 确保一个或多个软件包被安装。
      • pkg.removed: 确保一个或多个软件包被卸载。
      • pkg.latest_version: 获取一个软件包的最新版本。
    • file: 用于管理文件。
      • file.managed: 确保一个文件存在且内容、权限等正确(从 Master 或 URL 源)。
      • file.directory: 确保一个目录存在。
      • file.remove: 确保一个文件或目录被删除。
      • file.get_contents: 获取一个文件的内容。
    • service: 用于管理系统服务。
      • service.running: 确保一个服务正在运行。
      • service.dead: 确保一个服务停止运行。
      • service.enabled: 确保一个服务在系统启动时自动运行。
    • state: 用于执行 State 管理。
      • state.apply : 应用指定的 State。
      • state.highstate: 执行 top.sls 文件中定义的所有 State。
    • grains: 用于管理 Grains。
      • grains.items: 列出 Minion 的所有 Grains。
      • grains.setval : 在 Minion 上设置一个自定义 Grain。
    • pillar: 用于管理 Pillar。
      • pillar.items: 列出 Minion 的所有 Pillar 数据。
      • saltutil.refresh_pillar: 刷新 Minion 的 Pillar 数据。
  • [arguments]: 函数参数,这是传递给 的参数。
    • –out= 或 -o : 指定输出格式。
      • salt '*' test.ping --out=json
      • salt '*' test.ping --out=yaml
      • salt '*' test.ping --out=table (表格形式,易读)
    • –async:异步执行命令。Master 发送任务后立即返回一个 Job ID,而不会等待 Minion 执行完成。
    • –verbose 或 -v: 显示更详细的输出。
    • –timeout= 或 -t : 指定命令超时时间,默认为 5 秒。对于执行时间长的命令很有用。

常用命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 检查所有 Minion 是否在线
salt '*' test.ping
# 在所有生产环境的 web 服务器上查看磁盘使用情况
salt -N webservers cmd.run 'df -h'
salt -N 'CloudSafeLine-1' cmd.run 'df -h | grep -E -e "/$"'
# 在所有 CentOS 服务器上安装最新版的 Git
salt -G 'os:CentOS' pkg.installed name=git refresh=True
# 应用配置文件
salt -l debug CloudSafeLine-1 state.apply
# 执行某个脚本
salt -l debug -N CloudSafeLine-2 cmd.run "/home/s/apps/CloudSafeLine/DataDistributer/bin/start.sh DataDistribute_feedback 3" runas="cloud"
# 查看相关日志
salt -l debug -N CloudSafeLine-1 cmd.run "tail /home/s/apps/CloudSafeLine/DownScanClient/logs/scan.info.log.2025-09-25" runas="cloud"
# 查看相关进程
salt 'mse02*v.*' cmd.run 'ps -ucloud -lfww'
# 以 JSON 格式输出所有 Minion 的操作系统和版本
salt '*' grains.item os osrelease --out=json
# 查询Minion的Pillar变量。
salt 'web-prod-01' pillar.items

salt-run

在Master上运行的、用于管理和编排整个Salt环境的命令

它和salt命令有本质区别:

  • salt命令: 在远程Minion上执行函数。
  • salt-run命令:在Master上执行函数。
1
salt-run <runner_function> [arguments]

常用命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 列出最近 24 小时内的所有任务
salt-run jobs.list_jobs

# 查看 jid 为 20231026100000123456 的任务结果
# 结合salt ... --async来使用更好
salt-run jobs.lookup_jid 20231026100000123456

# 执行 /srv/salt/orchestrate/deploy.sls 这个编排文件
salt-run state.orchestrate orchestrate.deploy

# 显示所有Minion的在线状态
salt-run manage.status
# 列出所有在线的Minion
salt-run manage.up
#列出所有离线的Minion
salt-run manage.down

# 刷新所有Minion的Pillar
salt-run pillar.refresh_pillar '*'
# 只刷新web-server-01的Pillar
salt-run pillar.refresh_pillar 'web-server-01'

salt-cp

将文件或目录从Master复制到Minion中

1
2
3
4
5
6
7
salt-cp [options] '<target>' SOURCE DEST

# 举例说明

salt-cp 'web-*' /srv/salt/files/nginx.conf /tmp/
salt-cp 'web-*' /tmp/logs/ /var/log/old_logs/
salt-cp 'web-*' /srv/scripts/*.sh /usr/local/bin/

注意:参数-r不是递归COPY的含义,目录可以直接COPY。-r参数表示的是在文件成功复制到Minion后,删除Master上的源文件。请谨慎使用!!!

salt-call

与其他的salt命令不同,salt-call是在Minion上执行的核心命令。它的主要目的是在Minion本地调用Salt的执行模块函数,并将结果直接显示在当前终端。通常,我们使用它来测试State与Pillar的配置是否正常。

1
salt-call [options] <function> [arguments]

常用命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 查看所有Pillar数据
salt-call pillar.items

# 如果Pillar数据未更新,先刷新再查看
salt-call --refresh-pillar pillar.items

# 如果仍然有问题,开启debug模式查看详细日志
salt-call pillar.items -l debug

# 在当前Minion上发布相关配置
salt-call -l debug state.highstate

# 查询当前Minion的版本
salt-call -l debug test.version