恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
SaltStack实战指南:从Master/Minion架构到批量部署Nginx
首页
资讯中心
/
SaltStack实战指南:从Master/Minion架构到批量部署Nginx
SaltStack实战指南:从Master/Minion架构到批量部署Nginx
发布时间:2026/8/30 9:46:23
当你在业务中面对几十台、上百台服务器需要统一装软件、改配置、下文件时如果还是手动一台台登录操作效率通常很低也容易漏配或误配。SaltStack简称 Salt正是用来解决这类批量管理和自动化配置问题的工具。本文围绕 Salt 的核心架构、环境搭建、State 配置管理、Pillar 变量管理、实战部署 Nginx、常见排错与最佳实践展开适合运维初学者、后端开发以及需要批量管理服务器的技术人员。读完你不仅能搭建一套可用的 Salt 环境也能理解它的执行原理和工程落地思路。1. 背景与核心概念1.1 SaltStack 是什么SaltStack 是一个基于 Python 开发的开源配置管理与远程执行平台采用 C/S 架构。其中作为控制端的叫作 Master部署在管理机上被管理的服务器叫作 Minion部署到每一台需要被控制的机器上。Master 通过消息队列默认是 ZeroMQ向 Minion 下发指令Minion 执行完任务后再把结果返回给 Master。过去我们管理服务器时通常的流程是 SSH 登录到目标机器再执行命令、修改配置、重启服务。当服务器数量少时这种方式还能接受数量一旦增多重复操作、人为失误、环境差异等问题就会被放大。Salt 的设计目标就是把这些重复操作集中到统一的入口让运维人员用一条命令、一份配置就能批量完成操作同时还能保证多台机器最终状态一致。1.2 Salt 解决了什么问题Salt 主要解决以下几类问题批量执行命令例如一次性查看所有机器的磁盘空间、内存用量、进程状态。配置管理例如让所有生产环境的 Web 服务器统一安装 Nginx、统一写入指定配置文件、统一启动服务。文件分发把配置文件、脚本、压缩包等文件从 Master 下发到指定的 Minion。状态收敛当服务器配置漂移被手动修改后可以重新执行 State让系统回到期望状态。资产信息采集通过 Grain 和 Pillar 收集操作系统、CPU、内存、IP 等信息用于后续条件判断。也就是说Salt 既能做“一次性命令”也能做“持续状态保证”。这两点分别对应 Salt 的 execution modules执行模块和 state system状态系统。1.3 Master 与 Minion 架构Salt 的基本拓扑结构如下Master控制中心维护所有 Minion 的认证信息下发任务并收集结果。Minion被管理节点主动连接 Master认证通过后接收任务并执行。ZeroMQMaster 与 Minion 之间的消息通信层保证指令能快速下发。Salt Repeater/Proxy可选用于不适合直接安装 Minion 的网络设备等特殊环境。从通信方向来看Minion 启动后会主动去连接 Master 的 4505 端口用于消息发布和 4506 端口用于结果返回。这种设计的好处是即使 Minion 位于 NAT 后面只要它能访问到 Master 的端口就能完成注册和通信。可以用一个简单的比喻来理解Master 是“老师”Minion 是“学生”老师布置作业命令学生完成后提交作业返回结果而认证过程则相当于“花名册登记”。1.4 为什么选择 Salt 而不是 Ansible / Puppet很多读者会问既然 Ansible 也可以做批量和配置管理为什么还要学 Salt这个问题的答案取决于使用场景和个人偏好。Salt 采用代理模式Minion 常驻内存执行速度非常快适合大规模集群、需要高频操作的场景。Ansible 是无代理模式通过 SSH 执行胜在免安装、学习曲线较低适合几十台以内或对网络环境要求较高的场景。Puppet 也是老牌的配置管理工具但它的语法是自创的 DSL领域特定语言上手成本相对更高社区活跃度近年来不如 Salt。Salt 使用 YAML 描述状态配置配合 Python 模块可以非常灵活地扩展写起来更像写代码而不是写“天书式 DSL”。当然选型不能只看工具本身还要看团队的技术积累和业务规模。本文选择 Salt是因为它更适合从入门走向规模化而且它的 State 写法对初学者非常友好。2. 环境准备与版本说明2.1 实验环境规划在开始安装前先明确本文的实验环境。为了尽量贴合大多数人的学习场景我采用以下规划Master 节点一台 CentOS 7 或 Ubuntu 20.04 服务器负责管理所有 Minion。Minion 节点一台或多台 CentOS 7 或 Ubuntu 20.04 服务器作为被管理端。网络要求Master 与 Minion 之间能够互相访问 TCP 4505、4506 端口如果开了防火墙需要提前放通。Salt 版本以 Salt 3006.xSulfur或相近版本为例具体版本需要根据操作系统和软件源情况调整本文重点演示配置思路不强制指定唯一版本。如果你是在本机用虚拟机练习可以准备两台虚拟机一台叫 salt-master一台叫 salt-minion。生产环境建议 Master 单独部署不要直接放业务应用。2.2 安装 Master安装 Salt Master 之前需要先确认 Python 环境。Salt 3006 系列依赖 Python 3.9 以上版本所以操作系统自带 Python 版本不能太老。CentOS 7 默认 Python 版本较旧建议使用 Salt 官方仓库安装也可以直接使用系统软件源。以下是一个通用的安装流程# 以 CentOS 7 为例先安装 EPEL 和 SaltStack 官方仓库 sudo yum install -y https://repo.saltproject.io/salt/py3/redhat/7/x86_64/latest.repo sudo yum clean expire-cache sudo yum install -y salt-master如果是 Ubuntu# 以 Ubuntu 20.04 为例 sudo curl -fsSL https://packagecloud.io/saltproject/salt/gpg.key | sudo apt-key add - sudo add-apt-repository deb https://packagecloud.io/saltproject/salt/ubuntu/$(lsb_release -cs) main sudo apt-get update sudo apt-get install -y salt-master安装完成后启动 Master 服务sudo systemctl enable salt-master sudo systemctl start salt-master sudo systemctl status salt-master启动后可以用sudo ss -lntp | grep 4505或netstat -lntp | grep 4505查看端口监听情况能看到 4505 和 4506 都处于 LISTEN 状态说明 Master 基本正常。2.3 安装 MinionMinion 的安装方式和 Master 类似可以在目标机器上执行同样的仓库配置然后把包名换成 salt-minion# CentOS 7 sudo yum install -y salt-minion # Ubuntu sudo apt-get install -y salt-minion安装完成后需要修改 Minion 配置文件/etc/salt/minion指定 Master 的地址和 Minion 的唯一 ID。# 编辑 /etc/salt/minion 找到 master 行修改为你的 Master IP 或域名 sudo sed -i s/#master: salt/master: 192.168.10.10/ /etc/salt/minion也可以直接在配置文件中写多行Salt 会尝试逐个连接master: - 192.168.10.10 - 192.168.10.11如果不想用默认的主机名作为 Minion ID可以显式配置id: web-server-01配置完成后启动 Minionsudo systemctl enable salt-minion sudo systemctl start salt-minion启动后 Minion 会生成一对密钥公钥/私钥并把公钥发送给 Master 等待认证。2.4 快捷环境校验为了确认环境是否准备好可以在 Master 上执行以下命令查看所有待认证的 Minionsudo salt-key -L正常情况下会看到类似输出Accepted Keys: Denied Keys: Unaccepted Keys: web-server-01 Rejected Keys:如果 Unaccepted Keys 下能看到自己的 Minion ID说明 Minion 到 Master 的网络是通的只是还没有完成认证。3. Salt 核心配置与工作原理拆解3.1 密钥认证机制Salt 的认证流程类似 SSH 首次连接的过程。Minion 启动后生成公钥和私钥公钥发给 MasterMaster 确认后把该 Minion 加入可信列表。后续通信都会使用 AES 加密保证安全。在 Master 上接受 Minion 公钥# 接受所有未认证的 key sudo salt-key -A # 或者只接受指定 Minion sudo salt-key -a web-server-01接受后再次查看sudo salt-key -LAccepted Keys 列表中就会出现web-server-01。这一步是整个 Salt 使用中比较容易卡住的地方。很多新手在 Minion 启动后直接执行salt * test.ping会得到无响应或报错原因往往是 key 还没有被接受。因此先salt-key -L查看状态再决定是否接受或排查网络是排错的重要步骤。3.2 测试连通性test.ping认证完成后可以在 Master 上执行最简单的命令来验证连通性sudo salt web-server-01 test.ping预期输出web-server-01: Truetest.ping并不是真的发送 ICMP 包而是让 Minion 执行一个返回 True 的模块用来证明 Master 与 Minion 之间的消息通道是通的。如果想对多台机器操作可以用通配符# 所有 Minion sudo salt * test.ping # 匹配 web- 开头的 Minion sudo salt web-* test.ping3.3 执行模块与命令批量执行Salt 真正的威力在于执行模块。它把常用操作封装成了一个个函数例如cmd.run在 Minion 上执行 Shell 命令。pkg.install调用系统的包管理器安装软件。service.start/service.stop/service.restart管理服务。disk.usage查看磁盘空间。file.write/file.read写文件、读文件。network.interfaces查看网卡信息。grains.items查看机器详细信息。下面看一个批量查看磁盘空间的例子sudo salt * disk.usage执行后结果会按 Minion ID 分组返回。如果机器数量大可以配合参数限制输出格式sudo salt * disk.usage --outjson批量安装软件也只需要一条命令sudo salt * pkg.install nginx这里 Salt 会自动识别 Minion 的操作系统CentOS 下调用 yum/dnfUbuntu 下调用 apt。3.4 State 与 SLS 文件执行模块适合“一次性命令”但运维中更需要的是“持续状态”。例如我们希望 Nginx 永远保持安装状态、配置文件永远保持某个内容、服务永远运行。这种声明式期望状态Salt 通过 State 系统实现。State 的配置写在 SLSSalt State Language文件中使用 YAML 语法描述“目标应该处于什么状态”。一个简单的 SLS 文件示例如下# /srv/salt/webserver/init.sls nginx-install: pkg.installed: - name: nginx nginx-service: service.running: - name: nginx - enable: True这个文件描述了两件事nginx-install是一个 State ID表示需要确保 nginx 包已安装。nginx-service表示需要确保 nginx 服务处于运行状态并且开机自启。执行这条 Statesudo salt web-server-01 state.sls webserverSalt 会去/srv/salt/webserver/init.sls读取配置然后让 Minion 检查并执行。如果系统已经满足条件Salt 会显示没有变化如果不满足会执行对应操作。3.5 Pillar 与变量管理State 文件中的硬编码会带来很多问题例如不同环境开发、测试、生产的 Nginx 端口不同、域名不同。Salt 提供了 Pillar 机制用于给 Minion 分配变量。Pillar 文件同样存放在 Master 上目录通常是/srv/pillar。修改/etc/salt/master配置后可以指定 Pillar 调用路径pillar_roots: base: - /srv/pillar然后创建 Pillar 的入口文件/srv/pillar/top.slsbase: web-server-01: - webserver再创建/srv/pillar/webserver.slswebserver: domain: example.com port: 8080这样在 State 文件中就可以引用 Pillar 变量# /srv/salt/webserver/init.sls nginx-config: file.managed: - name: /etc/nginx/conf.d/site.conf - source: salt://webserver/templates/site.conf.j2 - template: jinja - context: domain: {{ pillar[webserver][domain] }} port: {{ pillar[webserver][port] }}Pillar 的另一个特点是只有匹配的 Minion 才能看到自己的 Pillar 数据适合存放一些敏感配置如密码、Token。当然在生产环境还需要结合加密方案不只是把 Password 放在 Pillar 里就完事。3.6 Grain 与目标匹配Grain 是 Minion 的静态信息相当于机器的“标签”。通过grains.items可以查看系统类型、内核版本、内存大小、IP 地址等。Grain 可以帮助我们批量选择特定范围的机器。例如只对 CentOS 系统的 Minion 执行命令sudo salt -G os_family:RedHat test.ping只对内存大于 4GB 的机器执行任务sudo salt -G mem_total:4096 test.ping此外Salt 还支持复合匹配可以组合条件sudo salt -C Gos:CentOS and Eweb-* test.ping这种匹配能力在生产环境非常实用。发布任务时不用手动维护一份机器清单而是通过条件动态筛选。4. 完整实战案例用 Salt 批量部署 Nginx接下来我们做一个完整的实战从零开始用 Salt 完成以下目标在目标 Minion 上安装 Nginx。写入一个自定义的首页内容。启动 Nginx 并设置为开机自启。使用 Pillar 区分不同机器的站点标题。4.1 创建项目结构在 Master 上创建如下目录结构/srv/salt/ ├── top.sls └── webserver/ ├── init.sls ├── files/ │ └── index.html.j2 └── templates/ └── site.conf.j2top.sls是 State 的入口文件用于决定哪些 Minion 执行哪些 State。我们先创建/srv/salt/top.slsbase: web-*: - webserver这里的意思是所有 ID 以web-开头的 Minion 都会执行webserver这个 State。然后创建/srv/salt/webserver/init.sls# 安装 nginx nginx-install: pkg.installed: - name: nginx # 写入 nginx 站点配置 nginx-site-config: file.managed: - name: /etc/nginx/conf.d/site.conf - source: salt://webserver/templates/site.conf.j2 - template: jinja - context: site_domain: {{ pillar[webserver][domain] }} # 写入自定义首页 nginx-index: file.managed: - name: /usr/share/nginx/html/index.html - source: salt://webserver/files/index.html.j2 - template: jinja - context: site_title: {{ pillar[webserver][title] }} # 启动 nginx 服务 nginx-service: service.running: - name: nginx - enable: True - reload: True - watch: - file: nginx-site-config - file: nginx-index这里有两个细节需要解释source使用salt://协议表示文件来自 Master 的/srv/salt目录。watch的作用是监听文件变化如果配置文件或首页内容被修改State 会自动执行 service 的 reload而不用手动重启。4.2 创建模板文件Nginx 站点配置模板/srv/salt/webserver/templates/site.conf.j2server { listen 80; server_name {{ site_domain }}; location / { root /usr/share/nginx/html; index index.html; } }首页模板/srv/salt/webserver/files/index.html.j2!DOCTYPE html html head title{{ site_title }}/title /head body h1Welcome to {{ site_title }}/h1 pThis page is managed by SaltStack./p /body /html4.3 配置 Pillar创建 Pillar 相关文件。/srv/pillar/top.slsbase: web-*: - webserver/srv/pillar/webserver.slswebserver: domain: example.com title: Example Web Server如果想让不同 Minion 显示不同内容可以在 Pillar 的 top.sls 中按 ID 分别指定base: web-01: - webserver web-02: - webserver2关于 Pillar 的作用这里再强调一遍它让“配置内容”和“执行逻辑”分离。State 文件可以保持不变只修改 Pillar 数据就能下发不同配置这是工程化落地的关键点。4.4 执行部署在 Master 上先执行 Pillar 刷新确保 Minion 拿到最新变量sudo salt * saltutil.refresh_pillar然后执行 Statesudo salt web-* state.apply webserver如果使用旧版本的 Salt也可以写state.sls webserver两者效果一致。执行过程会输出每个 State 的执行结果例如web-01: ---------- ID: nginx-install Function: pkg.installed Name: nginx Result: True Comment: All specified packages are already installed Started: 10:30:01.123456 Duration: 150.123 ms Changes: ---------- ID: nginx-site-config Function: file.managed Name: /etc/nginx/conf.d/site.conf Result: True Comment: File /etc/nginx/conf.d/site.conf updated Started: 10:30:01.234567 Duration: 25.456 ms Changes: diff: New file重点看Result字段如果是True说明执行成功如果是False则需要排查对应 State 的错误信息。4.5 验证结果部署完成后可以验证 Nginx 是否正常。在 Minion 上查看服务状态sudo salt web-* service.status nginx执行端口的访问测试sudo salt web-* cmd.run curl -I http://127.0.0.1/预期能看到类似输出web-01: HTTP/1.1 200 OK Server: nginx/1.20.1再次执行 State观察结果是否不再产生变化sudo salt web-* state.apply webserver如果没有文件变动Salt 会输出Comment: File ... is in the correct state说明状态已经收敛。这里也体现出一个最佳实践第一次执行 State 后建议再执行一次确认状态收敛避免遗漏或出现依赖顺序问题。5. 常见问题与排查思路Salt 环境在初次搭建和使用过程中容易遇到一些固定问题。下面按现象、原因、解决方案进行整理。5.1 Minion 显示密钥认证失败现象Minion did not return. [No response]原因Minion 的公钥还没有被 Master 接受。Minion 配置的 Master 地址错误。4505/4506 端口不通。Minion ID 重复。排查步骤在 Master 上执行sudo salt-key -L看 Unaccepted Keys 是否有 Minion。如果没有检查 Minion 上的/etc/salt/minion中master配置是否正确。在 Minion 上执行sudo salt-minion -l debug查看详细日志。检查防火墙是否放通 4505、4506 端口。解决方案接受 key 后重试sudo salt-key -a minion_id sudo salt minion_id test.ping5.2 Minion 状态显示 Down现象sudo salt * test.ping web-01: Minion did not return. [No response]原因Minion 服务没有启动。Minion 与 Master 之间的网络断开。Minion 的密钥与 Master 端记录不一致。Minion 负载过高导致任务处理超时。排查步骤在 Minion 上执行sudo systemctl status salt-minion查看服务状态。在 Master 上查看/var/log/salt/master日志。在 Minion 上查看/var/log/salt/minion日志。尝试重启 Minion 服务。解决方案sudo systemctl restart salt-minion sudo salt * test.ping如果仍然 Down可以在 Master 端删除旧 key在 Minion 端删除/etc/salt/pki/minion目录后重新启动认证流程# Master 端删除 sudo salt-key -d web-01 # Minion 端清理密钥 sudo rm -rf /etc/salt/pki/minion # 重启 Minion sudo systemctl restart salt-minion # Master 端重新接受 sudo salt-key -a web-015.3 SLS 文件语法或缩进错误现象Data failed to compile: #-- next line in /srv/salt/webserver/init.sls ------------- #-- raising error: Could not parse原因YAML 缩进不正确。冒号后没有空格。State ID 重复。模板变量使用了未定义的 Jinja 变量。排查步骤先检查 YAML 缩进Salt 的 SLS 文件对空格非常敏感建议统一用两个空格缩进不要使用 Tab。执行sudo salt web-* state.apply webserver --state-outputchanges获取详细的出错位置。在本地用 Python 的 yaml 库解析检查语法python3 -c import yaml; print(yaml.safe_load(open(/srv/salt/webserver/init.sls)))这种方法能快速暴露 YAML 的语法错误但无法检查 Salt 的 State 语义问题。解决方案按照上述逻辑修正缩进或变量引用。5.4 文件模板渲染失败现象Rendering SLS base:webserver.init failed: Jinja variable dict object has no attribute domain原因State 文件中引用了 Pillar 变量但 Minion 没有刷新 Pillar或者 Pillar 的 top.sls 没有匹配到该 Minion。解决方案sudo salt * saltutil.refresh_pillar sudo salt * pillar.items先确认目标 Minion 能拿到 Pillar 数据再重新执行 State。5.5 常见问题快速排查表问题现象常见原因解决思路test.ping 无响应key 未接受salt-key -L查看并接受Minion 一直显示 Down服务未启动systemctl start salt-minion执行 State 报编译错误YAML 缩进错误检查两空格缩进不用 TabJinja 变量不存在Pillar 未刷新saltutil.refresh_pillar文件没有按预期更新watch 条件未触发检查文件名和路径是否一致执行速度慢大量 Minion 同时返回使用批量执行和并行策略6. 最佳实践与工程建议6.1 目录结构与命名规范生产环境中Salt 的目录结构会直接影响可维护性。建议按照下面的方式组织/srv/salt/ ├── top.sls ├── common/ │ ├── init.sls │ ├── packages.sls │ └── users.sls ├── nginx/ │ ├── init.sls │ ├── files/ │ └── templates/ ├── app/ │ ├── init.sls │ └── files/ └── monitor/ └── init.sls命名上遵循几个原则State ID 用“功能 资源类型”的组合例如nginx-install、nginx-config-file。目录名代表业务模块或软件名不要用日期或人名命名。模板文件放在templates子目录静态文件放在files子目录。6.2 配置隔离与环境区分千万不要把测试环境和生产环境的配置写在同一个 State 里用 if 判断这样会越来越难维护。更好的做法是用不同的pillar_roots区分环境。用不同的 Master 管理不同的环境。通过 Salt Syndic 做多级架构由中心 Master 管理多个区域 Master。例如可以在/etc/salt/master中配置多套 rootspillar_roots: dev: - /srv/pillar/dev prod: - /srv/pillar/prod然后通过 Minion 的配置指定环境pillar_environment: dev这样同一套 State 代码可以在不同环境中复用只是变量数据不同。6.3 State 幂等性与变更控制Salt 的 State 系统强调“声明期望状态”理论上重复执行多次结果一致这就是幂等性。但在实际编写时容易出现状态不幂等的情况例如每次执行都追加一段文本到某个文件而不是使用file.replace。在cmd.run中执行不可重复的命令例如直接往 cron 里重复写入任务。建议遵循以下原则优先使用 Salt 内置的 State 模块不要用cmd.run写逻辑。如果必须执行 Shell 脚本加入unless或onlyif条件确保只有不满足条件时才执行。文件操作优先用file.managed尽量使用模板渲染而不是覆盖整个文件。6.4 安全与权限控制Salt 作为运维工具拥有很大的权限一旦 Master 被攻破所有 Minion 都可能被控制。因此需要注意Master 与 Minion 之间通过密钥认证不要随便把私钥拷给无关人员。使用 Salt 的外部 Pillar 或 Vault 集成管理敏感信息避免把密码明文写在 SLS 文件中。关闭 Master 上不必要的外网访问通过防火墙限制 4505、4506 端口只允许内网访问。给不同团队配置 Roster 与客户端 ACL访问控制列表避免普通开发人员直接执行危险命令。在/etc/salt/master中可以通过client_acl或user指定授权用户和允许的执行模块例如client_acl: devops: - web-*: - test.ping - service.status这意味着 devops 用户只能对 web- 开头的机器执行test.ping和service.status不能执行cmd.run等高风险模块。6.5 性能与大集群优化当 Minion 数量达到几百台甚至上千台时Salt 默认配置可能遇到性能瓶颈。常用优化方向包括调整 Master 的 worker 线程数worker_threads根据 CPU 核数适当增加。开启 Minion 端acceptance_wait_time避免大量 Minion 同时重连造成压力。使用 Salt SSH 模式管理无法安装代理的机器。使用 Syndic 或多 Master 架构做水平扩展。批量操作时使用--batch-size 10%控制并发避免雪崩sudo salt * -b 10% state.apply webserver6.6 版本管理与回滚运维变更必须有版本意识和回滚方案Salt 也不例外将所有 SLS、Pillar、模板文件纳入 Git 管理标签按发布版本命名。使用 GitFS 功能让 Salt 直接从 Git 仓库拉取 State 文件实现配置快速回滚。重大变更先在测试环境执行再对一小批 Minion 灰度执行最后全量执行。执行涉及删除文件或停止服务的操作时先确认目标 Minion 的备份状态。一个简单的灰度发布命令可以这样写# 先发布到 10% 的机器 sudo salt * -b 10 state.apply app # 确认无问题后全量发布 sudo salt * state.apply app7. 总结与学习路线本文围绕 Salt 的 Master/Minion 架构、密钥认证、执行模块、State 配置管理、Pillar 变量管理以及实战部署 Nginx 展开完整演示了从环境搭建到批量部署与验证的过程。如果你能亲手把实验做通再根据实际项目把目录结构、环境隔离、权限控制补上就已经具备用 Salt 承担生产环境基础运维任务的能力。接下来可以按这个方向逐步深入学习 Salt 的更多执行模块例如schedule定时任务、event事件监听、reactor响应机制。掌握 Jinja 模板的高级用法包括条件渲染、宏定义和变量继承。研究 Salt SSH 模式适用在无法安装 Minion 的场景。了解 Salt API把 Salt 集成进公司内部的运维平台。多接触 GitFS、Vault 集成、Salt Formulas 社区方案积累工程经验。在实际项目中建议优先关注变更风险和权限边界所有批量操作都要有回滚手段和评审记录。先把一个小模块跑通再逐步扩大管理范围Salt 会成为你运维工作中非常可靠的帮手。如果这篇文章对你有帮助可以收藏备用。后续我也会继续分享 Salt 的进阶用法和真实踩坑记录欢迎在评论区交流你的使用问题。