- 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.
- 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 |
- 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
- Key Exchange
salt-key -L # list pending
salt-key -A -y # accept all fingerprints
- First Remote Execution
salt '*' test.ping
salt '*' cmd.run 'uptime'
- 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
- 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
- Top File (Hightsate)
# /srv/salt/base/top.sls
base:
'*':
- web.apache
salt '*' state.highstate
- Grains: Static Inventory
salt '*' grains.items
salt -G 'os:CentOS' cmd.run 'uptime'
- 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'] }}
- 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
- Batch Execution
salt '*' -b 2 test.ping # two at a time
salt -G 'os:CentOS' --batch-size 25% cmd.run 'reboot'
- 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
- 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]
- 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
- 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
- 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"
- 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
- 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
- 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