Deploying and Managing Infrastructure at Scale with SaltStack

  1. Overview

Salt is a Python-based, event-driven automation platform that combines remote execution, configuraton management, and cloud orchestration. Compared to Puppet (Ruby) and Ansible (Python, agent-less over SSH), Salt scales to tens of thousands of nodes with sub-second command latency thanks to its ZeroMQ transport.

  1. Lab Environment

Hostname IP Role OS
srv-master.example.com 192.168.56.11 Master & Minion CentOS 7.4
srv-node02.example.com 192.168.56.12 Minion CentOS 7.4
  1. Installation

# Add SaltStack repository
yum install -y https://repo.saltstack.com/yum/redhat/salt-repo-2016.11-2.el7.noarch.rpm

# Master
yum install -y salt-master
systemctl enable --now salt-master

# All nodes (including master acting as minion)
yum install -y salt-minion

Edit /etc/salt/minion on every minion:

master: 192.168.56.11
id: <unique-identifier>   # defaults to hostname
</unique-identifier>
systemctl enable --now salt-minion

  1. Key Exchange

salt-key -L                    # list pending
salt-key -A -y                 # accept all fingerprints

  1. First Remote Execution

salt '*' test.ping
salt '*' cmd.run 'uptime'

  1. State Tree Layout

/srv/salt/
├── base/          # common states
├── dev/
├── test/
└── prod/          # production states

Configure in /etc/salt/master:

file_roots:
  base:
    - /srv/salt/base
  prod:
    - /srv/salt/prod

  1. Installing Apache via States

# /srv/salt/base/web/apache.sls
httpd_pkg:
  pkg.installed:
    - name: httpd

httpd_svc:
  service.running:
    - name: httpd
    - enable: True

salt 'srv-node02.example.com' state.apply web.apache

  1. Top File (Hightsate)

# /srv/salt/base/top.sls
base:
  '*':
    - web.apache

salt '*' state.highstate

  1. Grains: Static Inventory

salt '*' grains.items
salt -G 'os:CentOS' cmd.run 'uptime'

  1. Pillar: Secure Runtime Data

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

# /srv/pillar/base/apache.sls
{% if grains['os'] == 'CentOS' %}
apache: httpd
{% else %}
apache: apache2
{% endif %}

# /srv/salt/base/web/apache.sls
httpd_pkg:
  pkg.installed:
    - name: {{ pillar['apache'] }}

  1. Targeting Patterns

  • Minion ID glob: 'srv-*'
  • List: -L 'srv-01,srv-02'
  • Regular expression: -E '^srv-(node1|node2)$'
  • Grains: -G 'osrelease:7.4'
  • Subnet: -S '192.168.56.0/24'
  • Pilllar: -I 'apache:httpd'
  • Nodegroup: -N webcluster
  1. Batch Execution

salt '*' -b 2 test.ping          # two at a time
salt -G 'os:CentOS' --batch-size 25% cmd.run 'reboot'

  1. Job Cache in MySQL

# /etc/salt/master
master_job_cache: mysql
mysql.host: '192.168.56.11'
mysql.user: salt
mysql.pass: salt
mysql.db: salt
mysql.port: 3306

  1. Salt-SSH (Agent-less Mode)

# /etc/salt/roster
srv-node02:
  host: 192.168.56.12
  user: root
  passwd: redhat

salt-ssh 'srv-node02' -r 'uptime]

  1. System Initialization Playbook

# /srv/salt/base/init/init-all.sls
include:
  - init.selinux
  - init.firewall
  - init.ntp
  - init.limits
  - init.sysctl
  - init.sshd
  - init.packages
  - init.users

  1. Redis Master-Slave Deployment

# /srv/salt/prod/redis/init.sls
redis_pkg:
  pkg.installed:
    - name: redis

redis_cfg:
  file.managed:
    - name: /etc/redis.conf
    - source: salt://redis/files/redis.conf.j2
    - template: jinja
    - defaults:
        bind_ip: {{ grains['fqdn_ip4'][0] }}
        port: 6379

redis_svc:
  service.running:
    - name: redis
    - enable: True
    - reload: True

# /srv/salt/prod/redis/slave.sls
include:
  - redis.init

replicate:
  cmd.run:
    - name: redis-cli slaveof 192.168.56.11 6379
    - unless: redis-cli info | grep role:slave
    - require:
      - service: redis_svc

  1. MySQL Master-Slave

# master.cnf snippet
[mysqld]
server_id = 101
log_bin   = mysql-bin

# slave.cnf snippet
[mysqld]
server_id = 102

# /srv/salt/prod/mysql/slave.sls
include:
  - mysql.install

sync:
  cmd.run:
    - name: |
        mysql -e "CHANGE MASTER TO
                  MASTER_HOST='192.168.56.11',
                  MASTER_USER='repl',
                  MASTER_PASSWORD='replpass',
                  MASTER_AUTO_POSITION=1;
                  START SLAVE;"
    - unless: mysql -e "SHOW SLAVE STATUS\G" | grep -q "Slave_IO_Running: Yes"

  1. HAProxy + Keepalived

# /srv/salt/prod/haproxy/install.sls
haproxy_src:
  archive.extracted:
    - name: /usr/local/src
    - source: salt://haproxy/files/haproxy-1.5.3.tar.gz
  cmd.run:
    - name: cd /usr/local/src/haproxy-1.5.3 && make TARGET=linux26 PREFIX=/usr/local/haproxy install
    - creates: /usr/local/haproxy/sbin/haproxy

# /srv/salt/prod/keepalived/install.sls
keepalived_src:
  archive.extracted:
    - name: /usr/local/src
    - source: salt://keepalived/files/keepalived-1.2.17.tar.gz
  cmd.run:
    - name: cd /usr/local/src/keepalived-1.2.17 && ./configure --prefix=/usr/local/keepalived && make && make install
    - creates: /usr/local/keepalived/sbin/keepalived

  1. Nginx + PHP-FPM

# /srv/salt/prod/nginx/install.sls
nginx_user:
  user.present:
    - name: www
    - uid: 1000
    - gid: 1000
    - shell: /sbin/nologin

nginx_build:
  cmd.run:
    - name: |
        cd /usr/local/src &&
        tar xf nginx-1.12.2.tar.gz &&
        cd nginx-1.12.2 &&
        ./configure --prefix=/usr/local/nginx \
                    --user=www --group=www \
                    --with-http_ssl_module \
                    --with-http_stub_status_module &&
        make && make install
    - creates: /usr/local/nginx/sbin/nginx

# /srv/salt/prod/php/install.sls
php_deps:
  pkg.installed:
    - pkgs:
      - libxml2-devel
      - openssl-devel
      - libcurl-devel
      - libjpeg-turbo-devel
      - libpng-devel
      - freetype-devel

php_build:
  cmd.run:
    - name: |
        cd /usr/local/src &&
        tar xf php-5.6.9.tar.gz &&
        cd php-5.6.9 &&
        ./configure --prefix=/usr/local/php \
                    --enable-fpm --with-fpm-user=www \
                    --with-fpm-group=www \
                    --with-mysqli=mysqlnd \
                    --with-pdo-mysql=mysqlnd &&
        make && make install
    - creates: /usr/local/php/sbin/php-fpm

  1. Putting It All Together

# /srv/salt/prod/top.sls
prod:
  'srv-master*':
    - nginx.install
    - php.install
    - mysql.master
    - redis.master
    - haproxy.install
    - keepalived.install
  'srv-node02*':
    - nginx.install
    - php.install
    - mysql.slave
    - redis.slave
    - haproxy.install
    - keepalived.install

salt '*' state.highstate test=True
salt '*' state.highstate

Tags: SaltStack configuration-management orchestration ZeroMQ Redis

Posted on Mon, 12 Oct 2026 16:28:52 +0000 by tibiz