0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

Ansible与SaltStack配置管理工具的对比

马哥Linux运维 来源:马哥Linux运维 2026-02-04 11:01 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

一、概述

1.1 背景介绍

在大规模服务器运维场景中,配置管理工具是基础设施自动化的核心组件。经过多年生产环境实践,Ansible和SaltStack作为两款主流的配置管理工具,各自占据了相当的市场份额。本文基于笔者在多个企业级项目中的实际运维经验,深入对比这两款工具的架构设计、性能表现、易用性和适用场景,为技术选型提供参考依据。

2015年至今,笔者先后在电商、金融、游戏等多个行业的生产环境中部署和使用过这两款工具。管理的服务器规模从几十台到上万台不等,积累了大量一手经验。Ansible以其无代理架构和低学习曲线著称,而SaltStack则以高性能和事件驱动架构见长。两者各有优劣,选择哪一款取决于具体的业务场景和团队技术栈。

1.2 技术特点

Ansible核心特点:

无代理架构(Agentless):通过SSH协议与目标主机通信,无需在被管理节点安装额外软件

声明式配置:使用YAML格式编写Playbook,描述期望达到的状态

幂等性设计:相同的任务多次执行结果一致,避免配置漂移

模块化架构:内置超过3000个模块,覆盖主流云平台和中间件

Push模式:从控制节点主动推送配置到被管理节点

SaltStack核心特点:

代理架构(Agent-based):在被管理节点部署minion进程,与master保持长连接

事件驱动:基于ZeroMQ消息队列实现异步通信,支持实时事件响应

高性能并发:得益于长连接设计,可同时管理数万台服务器

双模式支持:同时支持Push和Pull两种配置下发模式

远程执行引擎:除配置管理外,提供强大的远程命令执行能力

1.3 适用场景

Ansible适用场景:

场景类型 具体应用 推荐理由
中小规模集群 100-500台服务器 无代理架构降低运维复杂度
混合环境管理 物理机+虚拟机+容器 SSH普适性强,兼容性好
网络设备配置 交换机、路由器、防火墙 丰富的网络模块支持
CI/CD流水线 Jenkins、GitLab集成 命令行友好,易于集成
临时任务执行 Ad-hoc命令、应急操作 无需预装代理,即开即用

SaltStack适用场景:

场景类型 具体应用 推荐理由
大规模集群 1000+台服务器 长连接+ZeroMQ高性能通信
实时配置管理 频繁配置变更场景 事件驱动,响应速度快
复杂编排需求 多层级依赖关系 强大的状态依赖管理
云原生环境 Kubernetes、容器编排 Salt-SSH和Salt-Cloud模块
安全合规场景 实时监控配置状态 Beacon和Reactor机制

1.4 环境要求

组件 Ansible SaltStack 说明
控制节点操作系统 CentOS Stream 9/Rocky 9/Ubuntu 24.04 CentOS Stream 9/Rocky 9/Ubuntu 24.04 推荐使用LTS版本
Python版本 3.11+ 3.11+ 控制节点和被管理节点
工具版本 2.16+ 3006+ 当前稳定版本
内存要求(控制节点) 4GB+ 8GB+ Salt Master需要更多内存
网络要求 SSH 22端口 4505/4506端口 防火墙放行
被管理节点 仅需SSH和Python 需安装salt-minion 代理vs无代理

二、详细步骤

2.1 准备工作

2.1.1 实验环境规划

本次对比测试环境采用以下架构:

控制节点:
- 主机名:ops-master
- IP地址:192.168.100.10
- 操作系统:Rocky Linux 9.3
- 配置:4核CPU / 16GB内存 / 100GB SSD

被管理节点(10台测试机):
- 主机名:web-node-01 至 web-node-10
- IP地址:192.168.100.11 至 192.168.100.20
- 操作系统:Rocky Linux 9.3
- 配置:2核CPU / 4GB内存 / 50GB SSD

2.1.2 Ansible环境部署

步骤一:安装Ansible

# Rocky Linux 9 / CentOS Stream 9
sudo dnf install -y epel-release
sudo dnf install -y ansible-core ansible-collection-ansible-posix ansible-collection-community-general

# Ubuntu 24.04
sudo apt update
sudo apt install -y software-properties-common
sudo add-apt-repository --yes --update ppa:ansible/ansible
sudo apt install -y ansible

# 验证安装
ansible --version
# ansible [core 2.16.3]
#  config file = /etc/ansible/ansible.cfg
#  configured module search path = ['/root/.ansible/plugins/modules']
#  ansible python module location = /usr/lib/python3.11/site-packages/ansible
#  executable location = /usr/bin/ansible
#  python version = 3.11.7

步骤二:配置SSH免密登录

# 生成SSH密钥对
ssh-keygen -t ed25519 -C"ansible@ops-master"-f ~/.ssh/ansible_key -N""

# 批量分发公钥到被管理节点
foriin{11..20};do
  ssh-copy-id -i ~/.ssh/ansible_key.pub root@192.168.100.$i
done

# 验证免密登录
ssh -i ~/.ssh/ansible_key root@192.168.100.11"hostname"

步骤三:创建Ansible目录结构

# 创建项目目录
mkdir -p /opt/ansible/{inventory,playbooks,roles,group_vars,host_vars,files,templates}

# 目录结构说明
# /opt/ansible/
# ├── ansible.cfg     # 主配置文件
# ├── inventory/      # 主机清单
# │  ├── hosts.ini    # 静态清单
# │  └── dynamic.py    # 动态清单脚本
# ├── playbooks/      # 剧本文件
# ├── roles/        # 角色目录
# ├── group_vars/     # 组变量
# ├── host_vars/      # 主机变量
# ├── files/        # 静态文件
# └── templates/      # Jinja2模板

步骤四:配置ansible.cfg

# /opt/ansible/ansible.cfg
[defaults]
# 主机清单路径
inventory = ./inventory/hosts.ini
# 远程用户
remote_user = root
# SSH私钥路径
private_key_file = ~/.ssh/ansible_key
# 禁用主机密钥检查(生产环境建议开启)
host_key_checking = False
# 并发连接数
forks = 50
# 超时时间(秒)
timeout = 30
# 日志路径
log_path = /var/log/ansible/ansible.log
# 重试文件路径
retry_files_save_path = /tmp/ansible-retry
# 角色搜索路径
roles_path = ./roles:/etc/ansible/roles
# 回调插件,美化输出
stdout_callback = yaml
# 显示任务执行时间
callback_whitelist = timer, profile_tasks

[privilege_escalation]
# 提权设置
become = True
become_method = sudo
become_user = root
become_ask_pass = False

[ssh_connection]
# SSH参数优化
ssh_args = -C -o ControlMaster=auto -o ControlPersist=60s -o StrictHostKeyChecking=no
# 管道模式,提升性能
pipelining = True
# 控制路径
control_path = /tmp/ansible-ssh-%%h-%%p-%%r

[persistent_connection]
# 持久连接超时
connect_timeout = 30
command_timeout = 30

2.1.3 SaltStack环境部署

步骤一:配置Salt仓库

# Rocky Linux 9 / CentOS Stream 9
sudo rpm --import https://repo.saltproject.io/salt/py3/redhat/9/x86_64/SALT-PROJECT-GPG-PUBKEY-2023.pub

sudo tee /etc/yum.repos.d/salt.repo << 'EOF'
[salt-repo]
name=Salt repo for RHEL/CentOS 9
baseurl=https://repo.saltproject.io/salt/py3/redhat/9/x86_64/3006
enabled=1
gpgcheck=1
gpgkey=https://repo.saltproject.io/salt/py3/redhat/9/x86_64/SALT-PROJECT-GPG-PUBKEY-2023.pub
EOF

# Ubuntu 24.04
curl -fsSL https://repo.saltproject.io/salt/py3/ubuntu/24.04/amd64/SALT-PROJECT-GPG-PUBKEY-2023.gpg | sudo gpg --dearmor -o /usr/share/keyrings/salt-archive-keyring.gpg

echo"deb [signed-by=/usr/share/keyrings/salt-archive-keyring.gpg] https://repo.saltproject.io/salt/py3/ubuntu/24.04/amd64/3006 noble main" | sudo tee /etc/apt/sources.list.d/salt.list

步骤二:安装Salt Master

# Rocky Linux 9
sudo dnf install -y salt-master salt-minion salt-ssh salt-api

# Ubuntu 24.04
sudo apt update
sudo apt install -y salt-master salt-minion salt-ssh salt-api

# 验证安装
salt --version
# salt 3006.5

步骤三:配置Salt Master

# /etc/salt/master
# 监听地址
interface:0.0.0.0

# 工作进程数
worker_threads:10

# 文件服务器后端
fileserver_backend:
-roots

# 文件根目录
file_roots:
base:
 -/srv/salt/base
dev:
 -/srv/salt/dev
prod:
 -/srv/salt/prod

# Pillar根目录
pillar_roots:
base:
 -/srv/pillar/base
prod:
 -/srv/pillar/prod

# 自动接受minion密钥(生产环境不建议)
auto_accept:False

# 日志级别
log_level:info
log_file:/var/log/salt/master

# 作业缓存
job_cache:True
keep_jobs:24

# 事件返回器
event_return:mysql

# 超时设置
timeout:30
gather_job_timeout:30

# 启用Reactor
reactor:
-'salt/minion/*/start':
 -/srv/reactor/minion_start.sls

# REST API配置
rest_cherrypy:
port:8000
ssl_crt:/etc/pki/tls/certs/salt-api.crt
ssl_key:/etc/pki/tls/private/salt-api.key

步骤四:创建Salt目录结构

# 创建目录结构
sudo mkdir -p /srv/{salt,pillar,reactor}/{base,dev,prod}
sudo mkdir -p /var/log/salt

# 目录结构说明
# /srv/
# ├── salt/        # 状态文件目录
# │  ├── base/      # 基础环境
# │  │  ├── top.sls   # 顶层文件
# │  │  └── common/   # 通用配置
# │  ├── dev/       # 开发环境
# │  └── prod/      # 生产环境
# ├── pillar/       # Pillar数据目录
# │  ├── base/
# │  │  └── top.sls
# │  └── prod/
# └── reactor/       # Reactor配置
#   └── base/

步骤五:启动Salt Master

# 启动服务
sudo systemctlenable--now salt-master
sudo systemctlenable--now salt-api

# 检查服务状态
sudo systemctl status salt-master
sudo salt-master --version

# 开放防火墙端口
sudo firewall-cmd --permanent --add-port=4505/tcp
sudo firewall-cmd --permanent --add-port=4506/tcp
sudo firewall-cmd --permanent --add-port=8000/tcp
sudo firewall-cmd --reload

步骤六:部署Salt Minion到被管理节点

# 在被管理节点执行
# 安装salt-minion
sudo dnf install -y salt-minion

# 配置minion
sudo tee /etc/salt/minion << 'EOF'
# Master地址
master: 192.168.100.10

# Minion ID(默认使用主机名)
id: web-node-01

# 日志级别
log_level: info

# Grains配置
grains:
  roles:
    - webserver
  environment: production
  datacenter: dc1
EOF

# 启动minion
sudo systemctl enable --now salt-minion

步骤七:接受Minion密钥

# 在Master上查看待接受的密钥
sudo salt-key -L
# Accepted Keys:
# Denied Keys:
# Unaccepted Keys:
# web-node-01
# web-node-02
# ...
# Rejected Keys:

# 接受所有密钥
sudo salt-key -A -y

# 验证连接
sudo salt'*'test.ping
# web-node-01:
#   True
# web-node-02:
#   True

2.2 核心配置

2.2.1 Ansible主机清单配置

静态清单示例:

# /opt/ansible/inventory/hosts.ini
[webservers]
web-node-01 ansible_host=192.168.100.11
web-node-02 ansible_host=192.168.100.12
web-node-03 ansible_host=192.168.100.13
web-node-04 ansible_host=192.168.100.14
web-node-05 ansible_host=192.168.100.15

[dbservers]
db-node-01 ansible_host=192.168.100.16
db-node-02 ansible_host=192.168.100.17

[cacheservers]
cache-node-01 ansible_host=192.168.100.18
cache-node-02 ansible_host=192.168.100.19
cache-node-03 ansible_host=192.168.100.20

[webservers:vars]
nginx_port=80
app_env=production

[all:vars]
ansible_python_interpreter=/usr/bin/python3
ansible_ssh_private_key_file=~/.ssh/ansible_key

组变量配置:

# /opt/ansible/group_vars/webservers.yml
---
# Nginx配置
nginx_version:"1.24"
nginx_worker_processes:auto
nginx_worker_connections:65535
nginx_keepalive_timeout:65
nginx_client_max_body_size:"100m"

# 应用配置
app_name:"myapp"
app_port:8080
app_log_level:"info"

# 系统优化参数
sysctl_settings:
net.core.somaxconn:65535
net.ipv4.tcp_max_syn_backlog:65535
net.ipv4.ip_local_port_range:"1024 65535"
net.ipv4.tcp_tw_reuse:1
vm.swappiness:10

2.2.2 SaltStack状态配置

Top文件配置:

# /srv/salt/base/top.sls
base:
'*':
 -common.packages
 -common.users
 -common.sshd
 -common.ntp

'web-node-*':
 -nginx
 -php
 -app

'db-node-*':
 -mysql
 -backup

'cache-node-*':
 -redis
 -sentinel

通用包管理状态:

# /srv/salt/base/common/packages.sls
# 基础软件包安装
base_packages:
pkg.installed:
 -pkgs:
  -vim-enhanced
  -wget
  -curl
  -htop
  -iotop
  -net-tools
  -bind-utils
  -lsof
  -strace
  -tcpdump
  -sysstat
  -tree

# 禁用不需要的服务
disable_postfix:
service.dead:
 -name:postfix
 -enable:False

Pillar配置:

# /srv/pillar/base/top.sls
base:
'*':
 -common

'web-node-*':
 -nginx
 -app

'db-node-*':
 -mysql

# /srv/pillar/base/common.sls
timezone:Asia/Shanghai
dns_servers:
-223.5.5.5
-223.6.6.6
ntp_servers:
-ntp.aliyun.com
-ntp1.aliyun.com

2.3 启动和验证

2.3.1 Ansible验证测试

# 测试连通性
ansible all -m ping

# 收集系统信息
ansible all -m setup -a"filter=ansible_distribution*"

# 执行ad-hoc命令
ansible webservers -m shell -a"uptime"

# 运行playbook
ansible-playbook playbooks/site.yml --check --diff

# 限制执行范围
ansible-playbook playbooks/site.yml --limitweb-node-01

# 指定标签执行
ansible-playbook playbooks/site.yml --tags"nginx,config"

2.3.2 SaltStack验证测试

# 测试连通性
salt'*'test.ping

# 收集Grains信息
salt'*'grains.items

# 执行远程命令
salt'web-node-*'cmd.run'uptime'

# 应用状态
salt'*'state.apply

# 测试模式运行
salt'*'state.applytest=True

# 高状态应用
salt'*'state.highstate

# 刷新Pillar数据
salt'*'saltutil.refresh_pillar

三、示例代码和配置

3.1 完整配置示例

3.1.1 Ansible完整Playbook示例

# /opt/ansible/playbooks/deploy_webserver.yml
---
-name:部署Web服务器
hosts:webservers
become:yes
gather_facts:yes

vars:
 nginx_version:"1.24"
 php_version:"8.2"
 app_name:"myapp"
 deploy_user:"deploy"
 deploy_group:"deploy"
 app_root:"/var/www/{{ app_name }}"

pre_tasks:
 -name:更新系统软件包缓存
  ansible.builtin.dnf:
   update_cache:yes
  when:ansible_os_family=="RedHat"

 -name:检查系统内存
  ansible.builtin.fail:
   msg:"系统内存不足,需要至少2GB"
  when:ansible_memtotal_mb<2048

roles:
    -role:common
      tags:common
    -role:nginx
      tags:nginx
    -role:php-fpm
      tags:php
    -role:app
      tags:app

tasks:
    -name:创建部署用户
      ansible.builtin.user:
        name:"{{ deploy_user }}"
        group:"{{ deploy_group }}"
        shell:/bin/bash
        home:"/home/{{ deploy_user }}"
        create_home:yes
        state:present

    -name:配置sudo权限
      ansible.builtin.lineinfile:
        path:/etc/sudoers.d/{{deploy_user}}
        line:"{{ deploy_user }} ALL=(ALL) NOPASSWD: /usr/bin/systemctl restart nginx, /usr/bin/systemctl reload nginx"
        create:yes
        mode:'0440'
        validate:'visudo -cf %s'

    -name:创建应用目录结构
      ansible.builtin.file:
        path:"{{ item }}"
        state:directory
        owner:"{{ deploy_user }}"
        group:"{{ deploy_group }}"
        mode:'0755'
      loop:
        -"{{ app_root }}"
        -"{{ app_root }}/releases"
        -"{{ app_root }}/shared"
        -"{{ app_root }}/shared/logs"
        -"{{ app_root }}/shared/config"

    -name:部署Nginx虚拟主机配置
      ansible.builtin.template:
        src:templates/nginx/vhost.conf.j2
        dest:/etc/nginx/conf.d/{{app_name}}.conf
        owner:root
        group:root
        mode:'0644'
        backup:yes
      notify:重载Nginx配置

    -name:配置PHP-FPM池
      ansible.builtin.template:
        src:templates/php/pool.conf.j2
        dest:/etc/php-fpm.d/{{app_name}}.conf
        owner:root
        group:root
        mode:'0644'
      notify:重启PHP-FPM服务

    -name:配置系统内核参数
      ansible.posix.sysctl:
        name:"{{ item.key }}"
        value:"{{ item.value }}"
        sysctl_file:/etc/sysctl.d/99-app-tuning.conf
        reload:yes
        state:present
      loop:"{{ sysctl_settings | dict2items }}"

    -name:配置文件描述符限制
      ansible.builtin.template:
        src:templates/system/limits.conf.j2
        dest:/etc/security/limits.d/99-app.conf
        owner:root
        group:root
        mode:'0644'

    -name:部署日志切割配置
      ansible.builtin.template:
        src:templates/logrotate/app.j2
        dest:/etc/logrotate.d/{{app_name}}
        owner:root
        group:root
        mode:'0644'

handlers:
    -name:重载Nginx配置
      ansible.builtin.systemd:
        name:nginx
        state:reloaded

    -name:重启PHP-FPM服务
      ansible.builtin.systemd:
        name:php-fpm
        state:restarted

post_tasks:
    -name:健康检查-验证Nginx运行状态
      ansible.builtin.uri:
        url:"http://localhost/health"
        method:GET
        status_code:200
        timeout:10
      register:health_check
      retries:3
      delay:5
      until:health_check.status==200

    -name:发送部署通知
      ansible.builtin.uri:
        url:"{{ notification_webhook }}"
        method:POST
        body_format:json
        body:
          text:"服务器 {{ inventory_hostname }} 部署完成"
          status:"success"
      when:notification_webhookisdefined
      ignore_errors:yes

Nginx虚拟主机模板:

{# /opt/ansible/templates/nginx/vhost.conf.j2 #}
# {{ ansible_managed }}
# 应用名称: {{ app_name }}
# 生成时间: {{ ansible_date_time.iso8601 }}

upstream {{ app_name }}_backend {
  least_conn;
{% for server in upstream_servers | default(['127.0.0.1:9000']) %}
  server {{ server }} weight=1 max_fails=3 fail_timeout=30s;
{% endfor %}
  keepalive 32;
}

server {
  listen 80;
  listen [::]:80;
  server_name {{ server_name | default('_') }};

  root {{ app_root }}/current/public;
  index index.php index.html;

  # 访问日志
  access_log /var/log/nginx/{{ app_name }}_access.log main buffer=64k flush=5s;
  error_log /var/log/nginx/{{ app_name }}_error.log warn;

  # 安全头
  add_header X-Frame-Options "SAMEORIGIN" always;
  add_header X-Content-Type-Options "nosniff" always;
  add_header X-XSS-Protection "1; mode=block" always;

  # Gzip压缩
  gzip on;
  gzip_vary on;
  gzip_min_length 1024;
  gzip_types text/plain text/css application/json application/javascript text/xml application/xml;

  # 静态文件缓存
  location ~* .(jpg|jpeg|png|gif|ico|css|js|pdf|txt)$ {
    expires 30d;
    add_header Cache-Control "public, immutable";
  }

  # 健康检查端点
  location /health {
    access_log off;
    return 200 'OK';
    add_header Content-Type text/plain;
  }

  # PHP处理
  location ~ .php$ {
    try_files $uri =404;
    fastcgi_pass {{ app_name }}_backend;
    fastcgi_index index.php;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    include fastcgi_params;

    # FastCGI优化
    fastcgi_connect_timeout 60s;
    fastcgi_send_timeout 60s;
    fastcgi_read_timeout 60s;
    fastcgi_buffer_size 64k;
    fastcgi_buffers 16 64k;
  }

  # 默认路由
  location / {
    try_files $uri $uri/ /index.php?$query_string;
  }

  # 禁止访问隐藏文件
  location ~ /. {
    deny all;
    access_log off;
    log_not_found off;
  }
}

3.1.2 SaltStack完整状态示例

# /srv/salt/base/nginx/init.sls
{%setnginx=salt['pillar.get']('nginx',{})%}
{%setnginx_version=nginx.get('version','1.24')%}
{%setworker_processes=nginx.get('worker_processes','auto')%}
{%setworker_connections=nginx.get('worker_connections',65535)%}

# 安装Nginx
nginx_package:
pkg.installed:
 -name:nginx
 -version:"{{ nginx_version }}*"

# 创建必要目录
nginx_directories:
file.directory:
 -names:
  -/etc/nginx/conf.d
  -/etc/nginx/ssl
  -/var/log/nginx
  -/var/cache/nginx
 -user:root
 -group:root
 -mode:755
 -makedirs:True

# 主配置文件
nginx_main_config:
file.managed:
 -name:/etc/nginx/nginx.conf
 -source:salt://nginx/files/nginx.conf.jinja
 -template:jinja
 -user:root
 -group:root
 -mode:644
 -context:
   worker_processes:{{worker_processes}}
   worker_connections:{{worker_connections}}
 -require:
  -pkg:nginx_package
 -watch_in:
  -service:nginx_service

# 默认虚拟主机配置
nginx_default_vhost:
file.managed:
 -name:/etc/nginx/conf.d/default.conf
 -source:salt://nginx/files/default.conf.jinja
 -template:jinja
 -user:root
 -group:root
 -mode:644
 -require:
  -file:nginx_directories
 -watch_in:
  -service:nginx_service

# 删除默认欢迎页
nginx_remove_default_html:
file.absent:
 -name:/usr/share/nginx/html/index.html
 -require:
  -pkg:nginx_package

# 系统内核优化
nginx_sysctl:
sysctl.present:
 -names:
  -net.core.somaxconn:
   -value:65535
  -net.ipv4.tcp_max_syn_backlog:
   -value:65535
  -net.ipv4.ip_local_port_range:
   -value:"1024 65535"
  -net.ipv4.tcp_tw_reuse:
   -value:1

# 文件描述符限制
nginx_limits:
file.managed:
 -name:/etc/security/limits.d/99-nginx.conf
 -contents:|
    nginx soft nofile 65535
    nginx hard nofile 65535
    nginx soft nproc 65535
    nginx hard nproc 65535
 -user:root
 -group:root
 -mode:644

# 日志切割配置
nginx_logrotate:
file.managed:
 -name:/etc/logrotate.d/nginx
 -source:salt://nginx/files/logrotate.conf
 -user:root
 -group:root
 -mode:644

# 开放防火墙端口
nginx_firewall:
firewalld.present:
 -name:public
 -services:
  -http
  -https
 -prune_services:False

# 启动Nginx服务
nginx_service:
service.running:
 -name:nginx
 -enable:True
 -reload:True
 -require:
  -pkg:nginx_package
  -file:nginx_main_config

Nginx主配置模板:

{# /srv/salt/base/nginx/files/nginx.conf.jinja #}
# Salt管理的配置文件 - 请勿手动修改
# 生成时间: {{ salt['status.time']('%Y-%m-%d %H:%M:%S') }}
# Minion ID: {{ grains['id'] }}

user nginx;
worker_processes {{ worker_processes }};
error_log /var/log/nginx/error.log warn;
pid /run/nginx.pid;

worker_rlimit_nofile 65535;

events {
  use epoll;
  worker_connections {{ worker_connections }};
  multi_accept on;
}

http {
  include /etc/nginx/mime.types;
  default_type application/octet-stream;

  # 日志格式
  log_format main '$remote_addr - $remote_user [$time_local] "$request" '
          '$status $body_bytes_sent "$http_referer" '
          '"$http_user_agent" "$http_x_forwarded_for" '
          'rt=$request_time uct="$upstream_connect_time" '
          'uht="$upstream_header_time" urt="$upstream_response_time"';

  log_format json escape=json '{'
    '"time":"$time_iso8601",'
    '"remote_addr":"$remote_addr",'
    '"request":"$request",'
    '"status":$status,'
    '"body_bytes_sent":$body_bytes_sent,'
    '"request_time":$request_time,'
    '"upstream_response_time":"$upstream_response_time"'
  '}';

  access_log /var/log/nginx/access.log main buffer=64k flush=5s;

  # 性能优化
  sendfile on;
  tcp_nopush on;
  tcp_nodelay on;
  keepalive_timeout 65;
  types_hash_max_size 4096;

  # Gzip压缩
  gzip on;
  gzip_vary on;
  gzip_proxied any;
  gzip_comp_level 5;
  gzip_min_length 1024;
  gzip_types text/plain text/css application/json application/javascript
       text/xml application/xml application/xml+rss text/javascript;

  # 安全配置
  server_tokens off;

  # 请求体限制
  client_max_body_size 100m;
  client_body_buffer_size 128k;

  # 代理缓冲配置
  proxy_buffer_size 64k;
  proxy_buffers 16 64k;
  proxy_busy_buffers_size 128k;

  # 包含虚拟主机配置
  include /etc/nginx/conf.d/*.conf;
}

3.2 实际应用案例

3.2.1 案例一:多环境配置管理

场景描述:管理开发、测试、生产三套环境,每套环境配置不同,需要实现配置隔离和统一管理。

Ansible实现方案:

# 目录结构
# /opt/ansible/
# ├── inventories/
# │  ├── dev/
# │  │  ├── hosts.ini
# │  │  └── group_vars/
# │  │    └── all.yml
# │  ├── staging/
# │  │  ├── hosts.ini
# │  │  └── group_vars/
# │  │    └── all.yml
# │  └── prod/
# │    ├── hosts.ini
# │    └── group_vars/
# │      └── all.yml

# /opt/ansible/inventories/dev/group_vars/all.yml
---
env_name:development
app_debug:true
log_level:debug
db_host:dev-db.internal
redis_host:dev-redis.internal
api_endpoint:https://api-dev.example.com

# /opt/ansible/inventories/prod/group_vars/all.yml
---
env_name:production
app_debug:false
log_level:warning
db_host:prod-db.internal
redis_host:prod-redis.internal
api_endpoint:https://api.example.com

# 执行命令
# 部署到开发环境
ansible-playbook-iinventories/devplaybooks/deploy.yml

# 部署到生产环境
ansible-playbook-iinventories/prodplaybooks/deploy.yml

SaltStack实现方案:

# /srv/pillar/base/top.sls
base:
'*':
 -common

dev:
'env:dev':
 -match:grain
 -dev/settings

staging:
'env:staging':
 -match:grain
 -staging/settings

prod:
'env:prod':
 -match:grain
 -prod/settings

# /srv/pillar/dev/settings.sls
env_name:development
app_debug:true
log_level:debug
db_host:dev-db.internal
redis_host:dev-redis.internal
api_endpoint:https://api-dev.example.com

# /srv/pillar/prod/settings.sls
env_name:production
app_debug:false
log_level:warning
db_host:prod-db.internal
redis_host:prod-redis.internal
api_endpoint:https://api.example.com

# 执行命令
# 刷新Pillar
salt'*'saltutil.refresh_pillar

# 应用到开发环境
salt-G'env:dev'state.apply

# 应用到生产环境
salt-G'env:prod'state.apply

3.2.2 案例二:滚动更新部署

场景描述:Web集群有20台服务器,需要实现滚动更新,每次更新5台,确保服务不中断。

Ansible实现方案:

# /opt/ansible/playbooks/rolling_update.yml
---
-name:滚动更新Web应用
hosts:webservers
become:yes
serial:5# 每批5台
max_fail_percentage:25# 最大失败比例25%

pre_tasks:
 -name:从负载均衡器摘除当前节点
  ansible.builtin.uri:
   url:"http://{{ lb_api }}/api/v1/backends/{{ inventory_hostname }}/disable"
   method:POST
   headers:
    Authorization:"Bearer{{ lb_api_token }}"
   status_code:200
  delegate_to:localhost

 -name:等待当前连接处理完毕
  ansible.builtin.wait_for:
   timeout:30

 -name:健康检查-确认节点已摘除
  ansible.builtin.uri:
   url:"http://{{ lb_api }}/api/v1/backends/{{ inventory_hostname }}/status"
   method:GET
  register:lb_status
  until:lb_status.json.status=="disabled"
  retries:6
  delay:5
  delegate_to:localhost

tasks:
 -name:停止应用服务
  ansible.builtin.systemd:
   name:"{{ app_name }}"
   state:stopped

 -name:备份当前版本
  ansible.builtin.shell:|
    if [ -L {{ app_root }}/current ]; then
     cp -a $(readlink -f {{ app_root }}/current) {{ app_root }}/rollback/$(date +%Y%m%d%H%M%S)
    fi
  args:
   executable:/bin/bash

 -name:清理旧版本(保留最近5个)
  ansible.builtin.shell:|
    cd {{ app_root }}/releases && ls -t | tail -n +6 | xargs -r rm -rf
  args:
   executable:/bin/bash

 -name:下载新版本
  ansible.builtin.unarchive:
   src:"{{ artifact_url }}/{{ app_name }}-{{ app_version }}.tar.gz"
   dest:"{{ app_root }}/releases/"
   remote_src:yes
   owner:"{{ deploy_user }}"
   group:"{{ deploy_group }}"

 -name:更新符号链接
  ansible.builtin.file:
   src:"{{ app_root }}/releases/{{ app_version }}"
   dest:"{{ app_root }}/current"
   state:link
   owner:"{{ deploy_user }}"
   group:"{{ deploy_group }}"

 -name:运行数据库迁移
  ansible.builtin.shell:|
    cd {{ app_root }}/current && ./bin/migrate
  args:
   executable:/bin/bash
  run_once:true
  delegate_to:"{{ groups['webservers'][0] }}"

 -name:启动应用服务
  ansible.builtin.systemd:
   name:"{{ app_name }}"
   state:started

 -name:等待应用启动
  ansible.builtin.uri:
   url:"http://localhost:{{ app_port }}/health"
   status_code:200
  register:health_result
  until:health_result.status==200
  retries:12
  delay:5

post_tasks:
 -name:将节点重新加入负载均衡器
  ansible.builtin.uri:
   url:"http://{{ lb_api }}/api/v1/backends/{{ inventory_hostname }}/enable"
   method:POST
   headers:
    Authorization:"Bearer{{ lb_api_token }}"
   status_code:200
  delegate_to:localhost

 -name:验证节点已恢复服务
  ansible.builtin.uri:
   url:"http://{{ lb_api }}/api/v1/backends/{{ inventory_hostname }}/status"
   method:GET
  register:lb_status
  until:lb_status.json.status=="enabled"
  retries:6
  delay:5
  delegate_to:localhost

SaltStack实现方案:

# /srv/salt/base/app/rolling_update.sls
{%setbatch_size=salt['pillar.get']('deploy:batch_size',5)%}
{%setapp_version=salt['pillar.get']('deploy:version')%}
{%setapp_root=salt['pillar.get']('app:root','/var/www/app')%}

# 从负载均衡器摘除
remove_from_lb:
http.query:
 -name:http://{{pillar['lb_api']}}/api/v1/backends/{{grains['id']}}/disable
 -method:POST
 -header_dict:
   Authorization:"Bearer{{ pillar['lb_api_token'] }}"

# 等待连接排空
wait_for_drain:
module.run:
 -name:test.sleep
 -length:30
 -require:
  -http:remove_from_lb

# 停止应用
stop_app:
service.dead:
 -name:{{pillar['app_name']}}
 -require:
  -module:wait_for_drain

# 备份当前版本
backup_current:
cmd.run:
 -name:|
    if [ -L {{ app_root }}/current ]; then
     cp -a $(readlink -f {{ app_root }}/current) {{ app_root }}/rollback/$(date +%Y%m%d%H%M%S)
    fi
 -require:
  -service:stop_app

# 下载新版本
download_release:
archive.extracted:
 -name:{{app_root}}/releases/
 -source:{{pillar['artifact_url']}}/{{pillar['app_name']}}-{{app_version}}.tar.gz
 -user:{{pillar['deploy_user']}}
 -group:{{pillar['deploy_group']}}
 -require:
  -cmd:backup_current

# 更新符号链接
update_symlink:
file.symlink:
 -name:{{app_root}}/current
 -target:{{app_root}}/releases/{{app_version}}
 -user:{{pillar['deploy_user']}}
 -group:{{pillar['deploy_group']}}
 -require:
  -archive:download_release

# 启动应用
start_app:
service.running:
 -name:{{pillar['app_name']}}
 -require:
  -file:update_symlink

# 健康检查
health_check:
http.wait_for_successful_query:
 -name:http://localhost:{{pillar['app_port']}}/health
 -status:200
 -wait_for:60
 -require:
  -service:start_app

# 重新加入负载均衡器
add_to_lb:
http.query:
 -name:http://{{pillar['lb_api']}}/api/v1/backends/{{grains['id']}}/enable
 -method:POST
 -header_dict:
   Authorization:"Bearer{{ pillar['lb_api_token'] }}"
 -require:
  -http:health_check
# Salt滚动更新执行命令
salt'web-node-*'state.apply app.rolling_update batch=5 batch_wait=30

3.2.3 案例三:配置合规性检查

场景描述:定期检查所有服务器的安全配置是否符合基线要求,生成合规报告。

Ansible实现方案:

# /opt/ansible/playbooks/compliance_check.yml
---
-name:安全合规性检查
hosts:all
become:yes
gather_facts:yes

vars:
 compliance_rules:
  sshd:
   PermitRootLogin:"no"
   PasswordAuthentication:"no"
   X11Forwarding:"no"
   MaxAuthTries:"3"
   Protocol:"2"
  password_policy:
   PASS_MAX_DAYS:"90"
   PASS_MIN_DAYS:"7"
   PASS_WARN_AGE:"14"

tasks:
 -name:检查SSH配置合规性
  ansible.builtin.shell:|
    grep -E "^{{ item.key }}" /etc/ssh/sshd_config | awk '{print $2}'
  register:sshd_check
  loop:"{{ compliance_rules.sshd | dict2items }}"
  changed_when:false

 -name:记录SSH配置检查结果
  ansible.builtin.set_fact:
   sshd_compliance:"{{ sshd_compliance | default({}) | combine({item.item.key: {'expected': item.item.value, 'actual': item.stdout, 'compliant': item.stdout == item.item.value}}) }}"
  loop:"{{ sshd_check.results }}"

 -name:检查密码策略合规性
  ansible.builtin.shell:|
    grep -E "^{{ item.key }}" /etc/login.defs | awk '{print $2}'
  register:password_check
  loop:"{{ compliance_rules.password_policy | dict2items }}"
  changed_when:false

 -name:检查防火墙状态
  ansible.builtin.systemd:
   name:firewalld
  register:firewall_status

 -name:检查SELinux状态
  ansible.builtin.command:getenforce
  register:selinux_status
  changed_when:false

 -name:检查未授权SUID文件
  ansible.builtin.shell:|
    find /usr /bin /sbin -perm -4000 2>/dev/null | wc -l
  register:suid_files
  changed_when:false

 -name:检查空密码账户
  ansible.builtin.shell:|
    awk -F: '($2 == "" ) { print $1 }' /etc/shadow
  register:empty_password
  changed_when:false

 -name:生成合规性报告
  ansible.builtin.set_fact:
   compliance_report:
    host:"{{ inventory_hostname }}"
    timestamp:"{{ ansible_date_time.iso8601 }}"
    ssh_config:"{{ sshd_compliance }}"
    firewall_enabled:"{{ firewall_status.status.ActiveState == 'active' }}"
    selinux_enforcing:"{{ selinux_status.stdout == 'Enforcing' }}"
    suid_file_count:"{{ suid_files.stdout }}"
    empty_password_users:"{{ empty_password.stdout_lines }}"

 -name:保存合规性报告到本地
  ansible.builtin.copy:
   content:"{{ compliance_report | to_nice_json }}"
   dest:"/tmp/compliance/{{ inventory_hostname }}_{{ ansible_date_time.date }}.json"
  delegate_to:localhost

 -name:汇总合规性报告
  ansible.builtin.template:
   src:templates/compliance_summary.html.j2
   dest:"/tmp/compliance/summary_{{ ansible_date_time.date }}.html"
  delegate_to:localhost
  run_once:true

四、最佳实践和注意事项

4.1 最佳实践

4.1.1 性能优化

Ansible性能优化:

# /opt/ansible/ansible.cfg 性能优化配置

[defaults]
# 增加并发数,根据控制节点性能调整
forks = 100

# 启用SSH持久连接
[ssh_connection]
# ControlMaster复用SSH连接
ssh_args = -C -o ControlMaster=auto -o ControlPersist=600s -o PreferredAuthentications=publickey

# 开启管道模式,减少SSH连接开销
pipelining = True

# 使用更快的SCP传输
transfer_method = piped
scp_if_ssh = smart
# Playbook层面优化
---
-name:优化后的Playbook
hosts:all
# 关闭自动收集facts,按需手动收集
gather_facts:no

pre_tasks:
 # 仅收集必要的facts
 -name:收集最小化系统信息
  ansible.builtin.setup:
   gather_subset:
    -min
    -network
   gather_timeout:10

tasks:
 # 使用free策略提升并发效率
 -name:并行执行任务
  # ...

# 策略配置
# strategy: free # 自由策略,任务完成即继续
# strategy: linear # 线性策略(默认),等待所有主机完成
# 使用Mitogen加速Ansible执行(可选)
pip install mitogen

# ansible.cfg配置
# [defaults]
# strategy_plugins = /path/to/mitogen/ansible_mitogen/plugins/strategy
# strategy = mitogen_linear

SaltStack性能优化:

# /etc/salt/master 性能优化配置

# 增加工作线程数
worker_threads:20

# ZeroMQ高水位标记
zmq_hwm:10000

# 批量执行返回超时
gather_job_timeout:60

# 事件发布缓存
event_publisher_niceness:0

# 启用缓存
cache:localfs
# 缓存过期时间(秒)
cachedir:/var/cache/salt
cache_job_timeout:3600

# Pillar缓存
pillar_cache:True
pillar_cache_ttl:3600

# Git文件服务器缓存
gitfs_update_interval:60
gitfs_env_whitelist:
-base
-prod

# 返回数据压缩
serial:msgpack
# 使用salt-ssh进行无代理连接测试
salt-ssh'*'test.ping --roster-file=/etc/salt/roster

# 批量执行优化
salt'*'state.apply batch=100 batch_wait=5

# 异步执行长时间任务
salt'*'state.apply --async
salt-run jobs.lookup_jid 

4.1.2 安全加固

Ansible安全加固:

# 使用Ansible Vault加密敏感数据
# 创建加密文件
# ansible-vault create group_vars/all/vault.yml

# group_vars/all/vault.yml(加密后)
vault_db_password:"SuperSecretPassword123!"
vault_api_key:"sk-xxxxxxxxxxxxxxxxxxxx"
vault_ssl_private_key:|
 -----BEGIN PRIVATE KEY-----
 MIIEvgIBADANBgkqhkiG9w0BAQE...
 -----END PRIVATE KEY-----

# group_vars/all/vars.yml(引用加密变量)
db_password:"{{ vault_db_password }}"
api_key:"{{ vault_api_key }}"
# ansible.cfg 安全配置
[defaults]
# 启用主机密钥检查
host_key_checking = True

# 日志脱敏
no_log = True # 默认隐藏敏感输出

# 禁用cowsay
nocows = True

[privilege_escalation]
# 使用sudo而非su
become_method = sudo
# 要求sudo密码
become_ask_pass = True
# Playbook安全实践
---
-name:安全配置示例
hosts:all
become:yes

tasks:
 -name:创建数据库用户(隐藏密码输出)
  community.mysql.mysql_user:
   name:app_user
   password:"{{ vault_db_password }}"
   priv:'app_db.*:ALL'
   state:present
  no_log:true# 关键:隐藏任务输出

 -name:部署包含敏感信息的配置文件
  ansible.builtin.template:
   src:config.yml.j2
   dest:/etc/app/config.yml
   owner:app
   group:app
   mode:'0600'# 仅所有者可读写
  no_log:true

SaltStack安全加固:

# /etc/salt/master 安全配置

# 禁用自动接受密钥
auto_accept:False

# 启用密钥认证
require_auth:True

# 限制命令执行
publisher_acl:
# 运维组可执行所有命令
ops_group:
 -'*'
# 开发组只能执行特定命令
dev_group:
 -'web-*':
  -test.*
  -status.*
  -state.apply
 -'db-*':
  -test.ping

# 启用审计日志
external_auth:
pam:
 ops_group%:
  -'*'
 dev_group%:
  -'web-*':
   -test.ping
   -state.apply

# SSL/TLS配置
ssl:
keyfile:/etc/salt/pki/master/master.pem
certfile:/etc/salt/pki/master/master.crt

# 启用客户端证书验证
verify_master_pubkey_sign:True
# 使用SaltStack Pillar保护敏感数据
# /srv/pillar/base/secrets.sls
#!jinja|gpg
db_password:|
 -----BEGIN PGP MESSAGE-----
 hQEMA...
 -----END PGP MESSAGE-----

api_token:|
 -----BEGIN PGP MESSAGE-----
 hQEMA...
 -----END PGP MESSAGE-----

# 使用GPG加密Pillar数据
# gpg --encrypt --armor --recipient ops@example.com secret.txt

4.1.3 高可用架构

Ansible高可用架构:

          ┌─────────────────┐
          │  GitLab/GitHub │
          │ (Playbook仓库) │
          └────────┬────────┘
              │
       ┌──────────────┼──────────────┐
       │       │       │
       ▼       ▼       ▼
  ┌────────────┐ ┌────────────┐ ┌────────────┐
  │ Ansible  │ │ Ansible  │ │ Ansible  │
  │ Node 01  │ │ Node 02  │ │ Node 03  │
  └──────┬─────┘ └──────┬─────┘ └──────┬─────┘
      │        │        │
      └───────────────┼───────────────┘
              │
          ┌───────┴───────┐
          │  SSH Pool  │
          └───────┬───────┘
              │
    ┌───────────────────┼───────────────────┐
    ▼          ▼          ▼
 ┌─────────┐     ┌─────────┐     ┌─────────┐
 │ Target │     │ Target │     │ Target │
 │ Group A │     │ Group B │     │ Group C │
 └─────────┘     └─────────┘     └─────────┘
# 使用AWX/Tower实现企业级高可用
# AWX Kubernetes部署配置
# awx-operator/awx.yml
---
apiVersion:awx.ansible.com/v1beta1
kind:AWX
metadata:
name:awx
namespace:awx
spec:
replicas:3
admin_user:admin
admin_password_secret:awx-admin-password

postgres_configuration_secret:awx-postgres-config
postgres_storage_class:managed-premium
postgres_storage_requirements:
 requests:
  storage:50Gi

# 任务执行Pod配置
task_resource_requirements:
 requests:
  cpu:500m
  memory:1Gi
 limits:
  cpu:2000m
  memory:4Gi

SaltStack高可用架构:

          ┌─────────────────┐
          │  Salt Syndic  │
          │ (Master of   │
          │  Masters)   │
          └────────┬────────┘
              │
       ┌──────────────┼──────────────┐
       │       │       │
       ▼       ▼       ▼
  ┌────────────┐ ┌────────────┐ ┌────────────┐
  │  Master  │ │  Master  │ │  Master  │
  │  DC-A  │ │  DC-B  │ │  DC-C  │
  └──────┬─────┘ └──────┬─────┘ └──────┬─────┘
      │        │        │
      ▼        ▼        ▼
  ┌──────────────────────────────────────────┐
  │       Salt Minions         │
  │ (多Master故障转移配置)         │
  └──────────────────────────────────────────┘
# /etc/salt/minion 多Master配置
master:
-salt-master-01.example.com
-salt-master-02.example.com
-salt-master-03.example.com

# Master故障转移
master_type:failover
master_shuffle:True
master_alive_interval:30

# 随机选择Master
random_master:True

# 重试配置
retry_dns:30
retry_dns_count:3
# /etc/salt/master Syndic配置
# Salt Master同时作为Syndic
syndic_master:salt-syndic.example.com
syndic_master_port:4506
syndic_log_file:/var/log/salt/syndic

# Syndic认证
syndic_wait:30

4.2 注意事项

4.2.1 配置注意

Ansible配置注意事项:

配置项 注意事项 建议值
forks 过高会导致控制节点资源耗尽 CPU核心数 * 5
timeout 过短可能导致任务误判失败 30-60秒
pipelining 需要目标主机禁用requiretty 生产环境建议开启
host_key_checking 生产环境必须开启 True
gather_facts 全量收集影响性能 按需收集
become 最小权限原则 仅必要时使用

SaltStack配置注意事项:

配置项 注意事项 建议值
worker_threads 根据CPU和连接数调整 CPU核心数 * 2
auto_accept 生产环境严禁开启 False
gather_job_timeout 大规模执行需增加 60-120秒
pillar_cache 频繁更新场景需关闭 根据场景
state_verbose 生产环境关闭详细输出 False
file_recv 文件上传功能,有安全风险 False

4.2.2 常见错误

错误类型 错误描述 解决方案
SSH连接超时 UNREACHABLE! SSH timed out 检查网络连通性,增加timeout值
权限拒绝 Permission denied (publickey) 检查SSH密钥配置和权限
模块未找到 MODULE FAILURE 安装对应的Ansible Collection
Python解释器 /usr/bin/python: No such file 指定ansible_python_interpreter
幂等性失败 changed状态不稳定 检查任务设计,使用when条件
变量未定义 undefined variable 使用default过滤器或检查变量定义
Salt Minion离线 Minion did not return 检查minion服务状态和网络
Salt密钥冲突 Key mismatch 删除旧密钥,重新认证
Pillar渲染失败 Pillar render error 检查Jinja语法和变量引用
状态依赖错误 Requisite failed 检查require/watch依赖链

4.2.3 兼容性

操作系统兼容性矩阵:

操作系统 Ansible 2.16+ SaltStack 3006+ 备注
CentOS Stream 9 完全支持 完全支持 推荐
Rocky Linux 9 完全支持 完全支持 推荐
AlmaLinux 9 完全支持 完全支持 推荐
Ubuntu 24.04 LTS 完全支持 完全支持 推荐
Debian 12 完全支持 完全支持 支持
RHEL 9 完全支持 完全支持 企业版
Windows Server 2022 部分支持 完全支持 需WinRM/SSH

Python版本兼容性:

Python版本 Ansible 2.16+ SaltStack 3006+ 状态
3.9 支持 支持 维护中
3.10 支持 支持 推荐
3.11 完全支持 完全支持 推荐
3.12 支持 部分支持 测试中

五、故障排查和监控

5.1 故障排查

5.1.1 日志分析

Ansible日志配置和分析:

# 配置详细日志输出
exportANSIBLE_LOG_PATH=/var/log/ansible/ansible.log
exportANSIBLE_DEBUG=True

# 运行时启用调试
ansible-playbook playbook.yml -vvvv

# 日志级别说明
# -v  : 显示任务结果
# -vv  : 显示任务配置和结果
# -vvv : 显示SSH连接信息
# -vvvv : 显示完整调试信息

# 分析日志常用命令
# 查看失败任务
grep -E"FAILED|UNREACHABLE"/var/log/ansible/ansible.log

# 统计任务执行时间
grep"TASK|PLAY RECAP"/var/log/ansible/ansible.log

# 提取特定主机日志
grep"web-node-01"/var/log/ansible/ansible.log

SaltStack日志配置和分析:

# Master日志位置
tail -f /var/log/salt/master

# Minion日志位置
tail -f /var/log/salt/minion

# 启用调试日志
salt-master -l debug
salt-minion -l debug

# 日志级别配置
# /etc/salt/master 或 /etc/salt/minion
# log_level: debug
# log_level_logfile: info

# 分析日志
# 查看认证失败
grep -E"Authentication|denied"/var/log/salt/master

# 查看执行错误
grep -E"Error|Exception|Traceback"/var/log/salt/master

# 事件日志
salt-run state.event pretty=True

5.1.2 常见问题排查

问题一:Ansible SSH连接失败

# 诊断步骤
# 1. 检查SSH连通性
ssh -v -i ~/.ssh/ansible_key root@target_host

# 2. 检查SSH配置
cat ~/.ssh/config
cat /etc/ssh/ssh_config

# 3. 测试Ansible连接
ansible target_host -m ping -vvvv

# 4. 检查Python解释器
ansible target_host -m raw -a"which python3"

# 常见解决方案
# 配置Python解释器
ansible_python_interpreter=/usr/bin/python3

# 禁用主机密钥检查(仅测试环境)
exportANSIBLE_HOST_KEY_CHECKING=False

问题二:SaltStack Minion无响应

# 诊断步骤
# 1. 检查Minion服务状态
systemctl status salt-minion
journalctl -u salt-minion -f

# 2. 检查Master连接
salt-call --localtest.ping
salt-call test.ping -l debug

# 3. 检查网络连通性
nc -zv salt-master 4505
nc -zv salt-master 4506

# 4. 重新生成Minion密钥
rm /etc/salt/pki/minion/minion_master.pub
systemctl restart salt-minion

# 5. 在Master上重新接受密钥
salt-key -d minion-id -y
salt-key -a minion-id -y

问题三:状态应用失败

# Ansible诊断
# 检查任务详细输出
ansible-playbook playbook.yml --check --diff -v

# 单步执行
ansible-playbook playbook.yml --step

# 从特定任务开始
ansible-playbook playbook.yml --start-at-task="任务名称"

# Salt诊断
# 测试模式运行
salt'minion-id'state.applytest=True

# 查看状态编译结果
salt'minion-id'state.show_lowstate

# 查看Pillar数据
salt'minion-id'pillar.items

5.1.3 调试技巧

# Ansible调试模块使用
---
-name:调试示例
hosts:all
tasks:
 -name:打印变量值
  ansible.builtin.debug:
   var:my_variable

 -name:打印自定义消息
  ansible.builtin.debug:
   msg:"当前主机:{{ inventory_hostname }}, IP:{{ ansible_host }}"

 -name:条件断点
  ansible.builtin.pause:
   prompt:"检查变量值是否正确,按Enter继续"
  when:debug_mode|default(false)

 -name:保存调试信息到文件
  ansible.builtin.copy:
   content:"{{ hostvars[inventory_hostname] | to_nice_json }}"
   dest:"/tmp/debug_{{ inventory_hostname }}.json"
  delegate_to:localhost
# Salt调试命令
# 查看模块文档
salt'*'sys.doc state.file

# 查看可用模块
salt'*'sys.list_modules

# 查看Grains
salt'*'grains.items

# 查看Pillar
salt'*'pillar.items

# 执行状态调试
salt-call state.apply nginx -l debug --local

# 查看事件总线
salt-run state.event pretty=True tagmatch='salt/job/*'

5.2 性能监控

5.2.1 关键指标

Ansible执行性能指标:

指标名称 说明 健康阈值 告警阈值
任务执行时间 单个任务执行耗时 < 30s > 60s
Playbook总时长 整个Playbook执行时间 < 10min > 30min
并发连接数 同时执行的SSH连接 < forks值 = forks值
失败任务比例 失败任务占比 0% > 5%
重试次数 任务重试次数 0 > 3

SaltStack执行性能指标:

指标名称 说明 健康阈值 告警阈值
命令响应时间 从发送到返回 < 5s > 30s
Minion在线率 在线Minion比例 > 99% < 95%
Master CPU使用率 控制节点CPU < 60% > 80%
Master内存使用率 控制节点内存 < 70% > 85%
ZeroMQ队列长度 消息队列积压 < 1000 > 5000
Job完成率 成功完成的任务 > 99% < 95%

5.2.2 监控配置

Ansible监控脚本:

#!/usr/bin/env python3
# /opt/ansible/scripts/ansible_metrics.py
# Ansible执行指标收集脚本

importjson
importtime
importsubprocess
fromdatetimeimportdatetime
frompathlibimportPath

classAnsibleMetrics:
 def__init__(self, log_path="/var/log/ansible"):
    self.log_path = Path(log_path)
    self.metrics_file = self.log_path /"metrics.json"

 defcollect_execution_metrics(self, playbook_output):
   """解析Playbook执行结果,提取指标"""
    metrics = {
     "timestamp": datetime.now().isoformat(),
     "ok":0,
     "changed":0,
     "unreachable":0,
     "failed":0,
     "skipped":0,
     "rescued":0,
     "ignored":0
    }

   # 解析PLAY RECAP行
   forlineinplaybook_output.split('
'):
     if'ok='inline:
        parts = line.split()
       forpartinparts:
         if'='inpart:
            key, value = part.split('=')
           ifkeyinmetrics:
              metrics[key] = int(value)

   returnmetrics

 defexport_prometheus_metrics(self, metrics):
   """导出Prometheus格式指标"""
    output = []
    output.append("# HELP ansible_task_total Ansible任务执行统计")
    output.append("# TYPE ansible_task_total counter")

   forkey, valueinmetrics.items():
     ifkey !="timestamp":
        output.append(f'ansible_task_total{{status="{key}"}}{value}')

   return'
'.join(output)

if__name__ =="__main__":
  collector = AnsibleMetrics()
 # 示例用法
  result = subprocess.run(
    ["ansible-playbook","playbook.yml"],
    capture_output=True,
    text=True
  )
  metrics = collector.collect_execution_metrics(result.stdout)
  print(collector.export_prometheus_metrics(metrics))

SaltStack监控配置:

# /etc/salt/master.d/monitoring.conf
# Salt Master监控配置

# 启用Salt API用于监控
rest_cherrypy:
port:8000
ssl_crt:/etc/pki/tls/certs/salt-api.crt
ssl_key:/etc/pki/tls/private/salt-api.key

# 事件返回器配置(存储到MySQL)
event_return:mysql
mysql.host:'localhost'
mysql.user:'salt'
mysql.pass:'salt_password'
mysql.db:'salt'

# 返回器配置
return:mysql

# Beacon监控配置示例
beacons:
diskusage:
 -/:90%
 -/var:80%
service:
 -services:
   nginx:
    onchangeonly:True
   salt-minion:
    onchangeonly:True
load:
 -averages:
   1m:
    -2.0
   5m:
    -1.5
   15m:
    -1.0
# /srv/salt/base/monitoring/salt_exporter.sls
# 部署Salt Prometheus Exporter

salt_exporter_download:
file.managed:
 -name:/usr/local/bin/salt_exporter
 -source:https://github.com/example/salt-exporter/releases/latest/salt_exporter
 -mode:755

salt_exporter_service:
file.managed:
 -name:/etc/systemd/system/salt-exporter.service
 -contents:|
    [Unit]
    Description=Salt Prometheus Exporter
    After=network.target

   [Service]
   Type=simple
   ExecStart=/usr/local/bin/salt_exporter--listen-address=:9175
   Restart=always

   [Install]
   WantedBy=multi-user.target
service.running:
 -name:salt-exporter
 -enable:True
 -require:
  -file:salt_exporter_download
  -file:salt_exporter_service

5.2.3 告警配置

# Prometheus告警规则
# /etc/prometheus/rules/ansible_alerts.yml
groups:
-name:ansible_alerts
 rules:
  -alert:AnsibleHighFailureRate
   expr:|
     sum(rate(ansible_task_total{status="failed"}[5m])) /
     sum(rate(ansible_task_total[5m])) > 0.05
   for:5m
   labels:
    severity:critical
   annotations:
    summary:"Ansible任务失败率过高"
    description:"过去5分钟内Ansible任务失败率超过5%"

  -alert:AnsiblePlaybookTimeout
   expr:ansible_playbook_duration_seconds>1800
   for:0m
   labels:
    severity:warning
   annotations:
    summary:"Ansible Playbook执行超时"
    description:"Playbook执行时间超过30分钟"

-name:salt_alerts
 rules:
  -alert:SaltMinionOffline
   expr:salt_minion_connected==0
   for:5m
   labels:
    severity:critical
   annotations:
    summary:"Salt Minion离线"
    description:"Minion{{ $labels.minion }}已离线超过5分钟"

  -alert:SaltMasterHighLoad
   expr:salt_master_cpu_usage_percent>80
   for:10m
   labels:
    severity:warning
   annotations:
    summary:"Salt Master负载过高"
    description:"Salt Master CPU使用率超过80%持续10分钟"

5.3 备份与恢复

5.3.1 Ansible备份策略

#!/bin/bash
# /opt/ansible/scripts/backup.sh
# Ansible配置备份脚本

BACKUP_DIR="/backup/ansible"
DATE=$(date +%Y%m%d_%H%M%S)
ANSIBLE_HOME="/opt/ansible"

# 创建备份目录
mkdir -p"${BACKUP_DIR}/${DATE}"

# 备份配置文件
tar -czf"${BACKUP_DIR}/${DATE}/config.tar.gz"
 "${ANSIBLE_HOME}/ansible.cfg"
 "${ANSIBLE_HOME}/inventory/"
 "${ANSIBLE_HOME}/group_vars/"
 "${ANSIBLE_HOME}/host_vars/"

# 备份Playbooks和Roles
tar -czf"${BACKUP_DIR}/${DATE}/playbooks.tar.gz"
 "${ANSIBLE_HOME}/playbooks/"
 "${ANSIBLE_HOME}/roles/"

# 备份Vault密钥(加密存储)
if[ -f ~/.vault_pass ];then
  gpg --encrypt --recipient ops@example.com 
    -o"${BACKUP_DIR}/${DATE}/vault_pass.gpg"
    ~/.vault_pass
fi

# 保留最近30天备份
find"${BACKUP_DIR}"-typed -mtime +30 -execrm -rf {} ;

echo"备份完成:${BACKUP_DIR}/${DATE}"

5.3.2 SaltStack备份策略

#!/bin/bash
# /opt/salt/scripts/backup.sh
# SaltStack配置备份脚本

BACKUP_DIR="/backup/salt"
DATE=$(date +%Y%m%d_%H%M%S)

# 创建备份目录
mkdir -p"${BACKUP_DIR}/${DATE}"

# 备份Master配置
tar -czf"${BACKUP_DIR}/${DATE}/master_config.tar.gz"
  /etc/salt/master 
  /etc/salt/master.d/

# 备份PKI密钥
tar -czf"${BACKUP_DIR}/${DATE}/pki.tar.gz"
  /etc/salt/pki/

# 备份Salt状态和Pillar
tar -czf"${BACKUP_DIR}/${DATE}/srv_salt.tar.gz"
  /srv/salt/ 
  /srv/pillar/ 
  /srv/reactor/

# 备份Minion密钥列表
salt-key -L >"${BACKUP_DIR}/${DATE}/minion_keys.txt"

# 备份Grains数据
salt'*'grains.items --out=json >"${BACKUP_DIR}/${DATE}/grains.json"

# 保留最近30天备份
find"${BACKUP_DIR}"-typed -mtime +30 -execrm -rf {} ;

echo"备份完成:${BACKUP_DIR}/${DATE}"
# 灾难恢复Playbook
# /opt/ansible/playbooks/salt_recovery.yml
---
-name:SaltStack灾难恢复
hosts:salt_master
become:yes

vars:
 backup_path:/backup/salt/latest

tasks:
 -name:停止SaltMaster服务
  ansible.builtin.systemd:
   name:salt-master
   state:stopped

 -name:恢复Master配置
  ansible.builtin.unarchive:
   src:"{{ backup_path }}/master_config.tar.gz"
   dest:/
   remote_src:yes

 -name:恢复PKI密钥
  ansible.builtin.unarchive:
   src:"{{ backup_path }}/pki.tar.gz"
   dest:/
   remote_src:yes

 -name:恢复Salt状态文件
  ansible.builtin.unarchive:
   src:"{{ backup_path }}/srv_salt.tar.gz"
   dest:/
   remote_src:yes

 -name:启动SaltMaster服务
  ansible.builtin.systemd:
   name:salt-master
   state:started
   enabled:yes

 -name:验证Minion连接
  ansible.builtin.command:salt'*'test.ping
  register:ping_result

 -name:显示恢复结果
  ansible.builtin.debug:
   var:ping_result.stdout_lines

六、总结

6.1 技术要点回顾

通过本文的对比分析,从架构设计、部署方式、性能表现、易用性等多个维度对Ansible和SaltStack进行了全面评估:

架构对比:

对比维度 Ansible SaltStack
通信方式 SSH(无代理) ZeroMQ(代理)
配置语言 YAML + Jinja2 YAML + Jinja2
学习曲线 较低 中等
执行模式 Push Push + Pull
扩展性 Python模块 Python模块 + Reactor
实时性 按需执行 事件驱动

选型建议:

选择Ansible的场景:

中小规模集群(100-500台)

团队配置管理经验较少

混合环境(物理机+虚拟机+网络设备)

CI/CD集成需求强

不希望在目标机器安装代理

选择SaltStack的场景:

大规模集群(1000+台)

需要实时配置管理

复杂的事件驱动自动化

需要高频率配置变更

对执行性能有严格要求

6.2 进阶学习方向

Ansible进阶:

Ansible Tower/AWX企业级部署

自定义模块和插件开发

Ansible Galaxy角色开发和分享

Ansible与Kubernetes集成

Ansible Lint和测试框架

SaltStack进阶:

Salt Syndic分布式架构

Salt Cloud云资源管理

Salt Reactor高级应用

Salt Beacon监控集成

Salt Thorium智能自动化

6.3 参考资料

Ansible官方文档:https://docs.ansible.com/

SaltStack官方文档:https://docs.saltproject.io/

Ansible Galaxy:https://galaxy.ansible.com/

SaltStack Formulas:https://github.com/saltstack-formulas

Red Hat Ansible Automation Platform:https://www.redhat.com/en/technologies/management/ansible

附录

A. 命令速查表

Ansible常用命令:

# 连通性测试
ansible all -m ping

# 执行Ad-hoc命令
ansible webservers -m shell -a"df -h"

# 运行Playbook
ansible-playbook playbook.yml

# 检查模式(干运行)
ansible-playbook playbook.yml --check --diff

# 限制执行范围
ansible-playbook playbook.yml --limitweb-node-01

# 指定标签
ansible-playbook playbook.yml --tags"nginx,config"

# 跳过标签
ansible-playbook playbook.yml --skip-tags"backup"

# 列出任务
ansible-playbook playbook.yml --list-tasks

# 列出主机
ansible-playbook playbook.yml --list-hosts

# 加密文件
ansible-vault encrypt secrets.yml

# 解密文件
ansible-vault decrypt secrets.yml

# 编辑加密文件
ansible-vault edit secrets.yml

# 查看加密文件
ansible-vault view secrets.yml

SaltStack常用命令:

# 连通性测试
salt'*'test.ping

# 执行远程命令
salt'web-*'cmd.run'uptime'

# 应用状态
salt'*'state.apply

# 高状态应用
salt'*'state.highstate

# 测试模式
salt'*'state.applytest=True

# 刷新Pillar
salt'*'saltutil.refresh_pillar

# 查看Grains
salt'*'grains.items

# 查看Pillar
salt'*'pillar.items

# 密钥管理
salt-key -L     # 列出所有密钥
salt-key -a minion # 接受密钥
salt-key -d minion # 删除密钥
salt-key -A     # 接受所有待定密钥

# 批量执行
salt'*'state.apply batch=5

# 异步执行
salt'*'state.apply --async
salt-run jobs.lookup_jid 

B. 配置参数详解

Ansible关键配置参数:

参数 默认值 说明
forks 5 并发连接数
timeout 10 SSH连接超时(秒)
remote_user 当前用户 远程登录用户
host_key_checking True 是否检查主机密钥
pipelining False 是否启用管道模式
gathering implicit Facts收集策略
fact_caching memory Facts缓存后端
retry_files_enabled True 是否生成重试文件
stdout_callback default 输出回调插件

SaltStack关键配置参数:

参数 默认值 说明
worker_threads 5 工作线程数
timeout 5 命令超时(秒)
gather_job_timeout 10 任务收集超时(秒)
auto_accept False 自动接受密钥
file_recv False 允许Minion上传文件
pillar_cache False 启用Pillar缓存
state_verbose True 详细状态输出
log_level warning 日志级别

C. 术语表

术语 Ansible SaltStack
控制节点 Control Node Master
被管理节点 Managed Node Minion
配置清单 Inventory Roster/Grains
配置文件 Playbook State
变量数据 Variables Pillar
模块 Module Execution Module
任务 Task State Function
角色 Role Formula
模板 Template (Jinja2) Template (Jinja2)
事件 Callback Event/Reactor
执行结果 Return Value Return

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 服务器
    +关注

    关注

    14

    文章

    10440

    浏览量

    91848
  • 配置管理
    +关注

    关注

    0

    文章

    7

    浏览量

    6384

原文标题:Ansible与SaltStack对比:配置管理工具如何选?

文章出处:【微信号:magedu-Linux,微信公众号:马哥Linux运维】欢迎添加关注!文章转载请注明出处。

收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    Linux环境下如何管理Python包管理工具

    Linux环境下,需要对软件包进行安装、卸载、升级和查询等操作,包含这些操作的工具,称为包管理工具
    发表于 08-22 15:14 1178次阅读
    Linux环境下如何<b class='flag-5'>管理</b>Python包<b class='flag-5'>管理工具</b>

    93.093 包管理工具管理工具扩展介绍

    管理工具
    充八万
    发布于 :2023年07月21日 05:03:29

    北京鼎普科技诚聘配置管理

    配置管理员1、负责项目版本发布过程,包括基线管理、版本管理、发布管理、变更管理、权限控制;2、产品、项目
    发表于 01-17 11:06

    NPM的nodejs官方包管理工具详解

    NPM:nodejs官方包管理工具的简介、安装、使用方法之详细攻略
    发表于 12-25 10:46

    登录管理工具LimitLogin

    LimitLogin是一款于2005年面世的登录管理工具,由一名微软合作伙伴技术专家和一名应用程序开发顾问合力开发。LimitLogin旨在在Active Directory域中跟踪和限制并发工作站和终端用户登录。
    发表于 07-16 06:27

    Linux的进程管理工具之Supervisor

    Linux进程管理工具Supervisor
    发表于 06-12 10:58

    RQM测试管理工具的应用和功能

    RQM — 需求驱动的测试管理工具
    发表于 01-14 07:54

    RTool远程管理工具使用指南

    映翰通公司开发的远程管理工具(简称 RTool),可对 InDTU 设备(简称 DTU)进行远程管理。远程管理包括:远程升级 DTU 的固件、远程读取/下发配置、远程重启。DTU 充当
    发表于 10-19 07:12

    基于Web的集群管理工具CWMS

    针对目前集群管理工具中没有实现单一入口或者仅提供命令行交互方式等问题,设计并实现了基于Web的集群管理工具CWMS。分析集群管理系统的体系结构,对集中式体系结构加以改进
    发表于 04-15 09:29 13次下载

    CANopen网络管理工具 V1.18

    CANopen网络管理工具 V1.18 网络管理工具
    发表于 11-15 17:12 75次下载

    基于CVS的OPNET模型配置管理研究

    在分析OPNET模型开发配置管理需求的基础上,通过分析流行的配置管理工具,选择CVS作为合适的配置管理工具,详细介绍了基于CVS的OPNET模型配置管理的流程和要点,并给出了WinCV
    发表于 11-17 11:39 0次下载

    Saltstack配置管理大全

    Saltstack配置管理大全
    发表于 09-08 09:01 9次下载
    <b class='flag-5'>Saltstack</b><b class='flag-5'>配置管理</b>大全

    基于SVN软件配置管理及持续集成

    SVN是一款广泛使用的配置管理工具,适合中小型软件团队使用。本文叙述了SVN的特点,介绍了配置管理的基本概念和相关角色:详细介绍了基于SVN的软件配置管理和持续集成,主要包括权限管理
    发表于 11-07 17:50 6次下载
    基于SVN软件<b class='flag-5'>配置管理</b>及持续集成

    目前接口管理工具有哪些_接口管理工具作用是什么

    接口文档管理工具是一个在线API文档系统,致力于快速解决团队内部接口文档的编写,和减少团队协作开发的沟通成本。作为一个后端程序员,和前端对接时总是需要写冗杂繁琐的接口文档,不仅效率低且沟通成本也高
    发表于 01-04 16:00 1.1w次阅读

    cmp项目管理工具的优缺点

    CMP项目管理工具,在不同的语境下有不同的含义。一种是指综合项目管理平台(Comprehensive Management Platform),它旨在整合和优化项目的各个方面,包括时间管理、资源
    的头像 发表于 12-17 09:42 1779次阅读