Instalación y Configuración de SaltStack
SaltStack is a powerful infrastructure automation and configuration management tool that uses a master-minion architecture for managing large-scale infrastructures. Salt combines the simplicity of configuration management with advanced remote execution capabilities, making it ideal for infrastructure orchestration. This guide covers master and minion installation, state management, pillar data, grains for targeting, formula organization, and the event-driven reactor.
Tabla de Contenidos
- SaltStack Overview
- Master Installation
- Minion Installation and Configuration
- Key Management
- State Management
- Pillar Data
- Grains and Targeting
- Formulas and Modules
- Event-Driven Reactor
- Conclusion
Descripción General de SaltStack
SaltStack (or Salt) is an event-driven automation platform for infrastructure configuration and orchestration. Using a simple YAML syntax and a master-minion model, Salt enables fast, reliable configuration management and remote execution at scale.
Key components:
- Master: Central server managing minions and executing commands
- Minions: Remote systems managed by the master
- States: Declarative configuration definitions (YAML)
- Pillar: Private data store for each minion
- Grains: System information and custom data on minions
- Formulas: Reusable state modules and execution code
- Reactor: Event-driven automation
Architecture:
┌─────────────────────┐
│ Salt Master │
│ (Central Control) │
└──────────┬──────────┘
│
┌────┴────┬─────────┐
│ │ │
ZMQ ZMQ ZMQ
│ │ │
▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐
│ Minion 1 │ │ Minion 2 │ │ Minion 3 │
│ (Managed)│ │(Managed) │ │(Managed) │
└──────────┘ └──────────┘ └──────────┘
Instalación del Maestro
Install and configure the Salt Master.
Installation:
# Ubuntu/Debian
sudo apt-get update
sudo apt-get install -y salt-master
# CentOS/RHEL
sudo yum install -y salt-master
# macOS
brew install saltstack
# Start master
sudo systemctl start salt-master
sudo systemctl enable salt-master
# Verify
sudo salt-key -L
Master configuration:
# /etc/salt/master
# Master IP address (interface to bind)
interface: 0.0.0.0
# Default port
port: 4506
# Minimum number of required minions for batch mode
min_open_files: 100000
# Key management
auto_accept: False # Require manual key acceptance
# File roots - location of state files
file_roots:
base:
- /srv/salt/states
dev:
- /srv/salt/dev
prod:
- /srv/salt/prod
# Pillar roots - location of pillar data
pillar_roots:
base:
- /srv/salt/pillar
# Return jobs to this minion
return_minion: true
# Job cache settings
job_cache: True
job_cache_dir: /var/cache/salt/jobs
# Worker processes
worker_threads: 5
# Timeout for minion responses
timeout: 5
# Include custom configuration
include: /etc/salt/master.d/*.conf
Create directory structure:
# Salt file structure
sudo mkdir -p /srv/salt/states
sudo mkdir -p /srv/salt/dev
sudo mkdir -p /srv/salt/prod
sudo mkdir -p /srv/salt/pillar
sudo mkdir -p /etc/salt/master.d
# Set permissions
sudo chown -R salt:salt /srv/salt
sudo chown -R salt:salt /etc/salt
Test master connectivity:
# Ping all minions
sudo salt '*' test.ping
# Show minion details
sudo salt '*' grains.items
# Execute command on all minions
sudo salt '*' cmd.run "hostname"
Instalación y Configuración del Minión
Install and configure Salt minions.
Installation:
# Ubuntu/Debian
sudo apt-get update
sudo apt-get install -y salt-minion
# CentOS/RHEL
sudo yum install -y salt-minion
# macOS
brew install salt-minion
# Start minion
sudo systemctl start salt-minion
sudo systemctl enable salt-minion
Minion configuration:
# /etc/salt/minion
# Master IP or hostname
master: salt-master.example.com
# Minion ID (defaults to hostname)
id: webserver-01
# Port for minion connection
port: 4505
# Connection timeout
auth_timeout: 5
# Authentication retries
auth_tries: 5
# Authentication wait
auth_wait: 3
# Use TCP keepalive
tcp_keepalive: True
# File roots mapping (optional)
file_client: remote
# Module refresh interval
module_refresh_interval: 60
# Custom grains
grains:
environment: production
role: webserver
datacenter: us-west-1
# Logging
log_level: info
log_level_logfile: warning
# Capabilities
enable_fqdns_grains: True
# Include custom configuration
include: /etc/salt/minion.d/*.conf
Minion test:
# Test minion status
sudo salt-minion -d
# Check minion logs
sudo tail -f /var/log/salt/minion
# Test connectivity to master
sudo salt-call test.ping
Multiple masters configuration:
# /etc/salt/minion
# List of masters for failover
master:
- master1.example.com
- master2.example.com
- master3.example.com
# Master discovery
master_type: failover
# Try all masters before failing
master_tries: -1
Gestión de Claves
Manage authentication keys between master and minions.
Accept minion keys:
# List unsigned keys
sudo salt-key -L
# Accept specific minion
sudo salt-key -a minion-id
# Accept all minions (use with caution)
sudo salt-key -A -y
# Reject minion
sudo salt-key -r minion-id
# Delete key
sudo salt-key -d minion-id
# List accepted keys
sudo salt-key -l accepted
# List rejected keys
sudo salt-key -l rejected
# List pending keys
sudo salt-key -l pending
Auto-accept minion keys:
# /etc/salt/master - Enable auto-accept (not recommended for production)
auto_accept: True
# Or use fingerprinting
auto_accept_fingerprints: True
Verify key fingerprints:
# Get minion fingerprint
sudo salt-call key.finger
# Get master fingerprint
sudo salt-key -F
# Verify minion fingerprint matches
sudo salt-key -f minion-id
Gestión de Estado
Define infrastructure state using YAML.
Simple state file:
# /srv/salt/states/packages.sls
# Install packages
common-packages:
pkg.installed:
- names:
- curl
- wget
- git
- htop
# Ensure service running
nginx:
pkg.installed:
- name: nginx
service.running:
- name: nginx
- enable: True
- watch:
- pkg: nginx
Apply state:
# Apply specific state
sudo salt '*' state.apply packages
# Apply to specific minions
sudo salt 'webserver-*' state.apply packages
# Apply multiple states
sudo salt '*' state.apply packages,nginx
# Test state (dry-run)
sudo salt '*' state.apply packages test=True
# Show what would change
sudo salt '*' state.apply packages --test
Complex state with templates:
# /srv/salt/states/nginx/init.sls
nginx-package:
pkg.installed:
- name: nginx
nginx-service:
service.running:
- name: nginx
- enable: True
- require:
- pkg: nginx-package
nginx-config:
file.managed:
- name: /etc/nginx/nginx.conf
- source: salt://nginx/files/nginx.conf
- template: jinja
- user: root
- group: root
- mode: 644
- require:
- pkg: nginx-package
- watch_in:
- service: nginx-service
nginx-vhost:
file.managed:
- name: /etc/nginx/sites-available/default
- source: salt://nginx/files/vhost.conf.j2
- template: jinja
- context:
server_name: {{ salt['grains.get']('fqdn') }}
port: {{ pillar.get('nginx:port', 80) }}
- require:
- pkg: nginx-package
- watch_in:
- service: nginx-service
Template with Jinja:
# /srv/salt/nginx/files/vhost.conf.j2
server {
listen {{ port }};
server_name {{ server_name }};
location / {
proxy_pass http://backend;
proxy_set_header Host $host;
}
}
Datos de Almacén
Store sensitive and variable data per minion.
Pillar structure:
# /srv/salt/pillar/top.sls
base:
'*':
- common
'webserver-*':
- webserver
'environment:production':
- match: grain
- production
# /srv/salt/pillar/common.sls
common:
ntp_servers:
- 0.ubuntu.pool.ntp.org
- 1.ubuntu.pool.ntp.org
# /srv/salt/pillar/webserver.sls
nginx:
port: 80
worker_processes: 4
upstream: 127.0.0.1:3000
app:
name: myapp
version: 1.0.0
# /srv/salt/pillar/production.sls
database:
host: db.prod.internal
port: 5432
password: secure_password_here
Use pillar in states:
# /srv/salt/states/app.sls
nginx-config:
file.managed:
- name: /etc/nginx/sites-available/default
- contents: |
server {
listen {{ pillar['nginx']['port'] }};
location / {
proxy_pass http://{{ pillar['app']['upstream'] }};
}
}
app-env:
file.managed:
- name: /opt/app/.env
- contents: |
APP_NAME={{ pillar['app']['name'] }}
APP_VERSION={{ pillar['app']['version'] }}
DB_HOST={{ pillar['database']['host'] }}
DB_PORT={{ pillar['database']['port'] }}
Access pillar from minion:
# View all pillar data
sudo salt-call pillar.items
# View specific pillar value
sudo salt-call pillar.get nginx:port
# View with default
sudo salt-call pillar.get 'nginx:port' 80
Granos y Segmentación
Use grains for system information and targeting.
View grains:
# List all grains
sudo salt '*' grains.items
# Get specific grain
sudo salt '*' grains.get os
# Get multiple grains
sudo salt '*' grains.items
Common grains:
os Operating system
osrelease OS version
osfullname Full OS name
hostname System hostname
fqdn Fully qualified domain name
ipv4 IPv4 addresses
ipv6 IPv6 addresses
cpu_cores Number of CPU cores
mem_total Total memory
virtual Virtualization type
Custom grains:
# /etc/salt/minion.d/custom_grains.conf
grains:
environment: production
role: webserver
datacenter: us-west-1
team: platform
cost_center: engineering
Or define in state:
# /srv/salt/states/grains.sls
set-custom-grains:
grains.present:
- name: environment
- value: production
set-role-grain:
grains.present:
- name: role
- value: webserver
Targeting with grains:
# Target by OS
sudo salt -G 'os:Ubuntu' state.apply
# Target by role
sudo salt -G 'role:webserver' state.apply packages
# Target by multiple grains
sudo salt -G 'os:Ubuntu and role:webserver' state.apply
# List matching minions
sudo salt -G 'role:webserver' test.ping
# Compound targeting
sudo salt -C 'G@role:webserver and not G@environment:dev' state.apply
Fórmulas y Módulos
Organize reusable configurations as formulas.
Formula structure:
nginx-formula/
├── nginx/
│ ├── init.sls
│ ├── files/
│ │ ├── nginx.conf
│ │ └── vhost.conf.j2
│ ├── defaults.yaml
│ └── map.jinja
├── pillar.example
└── README.md
Reusable formula:
# /srv/salt/nginx/init.sls
{% from "nginx/map.jinja" import nginx_settings with context %}
nginx-package:
pkg.installed:
- name: {{ nginx_settings.package }}
nginx-service:
service.running:
- name: {{ nginx_settings.service }}
- enable: True
nginx-config:
file.managed:
- name: {{ nginx_settings.config_path }}
- user: {{ nginx_settings.user }}
- group: {{ nginx_settings.group }}
- mode: 644
- template: jinja
- context:
settings: {{ nginx_settings }}
Map file for OS abstraction:
# /srv/salt/nginx/map.jinja
{% set nginx_settings = salt['grains.filter_by']({
'Debian': {
'package': 'nginx',
'service': 'nginx',
'config_path': '/etc/nginx/nginx.conf',
'user': 'www-data',
'group': 'www-data',
},
'RedHat': {
'package': 'nginx',
'service': 'nginx',
'config_path': '/etc/nginx/nginx.conf',
'user': 'nginx',
'group': 'nginx',
},
}, merge=salt['pillar.get']('nginx:settings')) %}
Reactor Controlado por Eventos
Automate responses to Salt events.
Reactor configuration:
# /etc/salt/master.d/reactor.conf
reactor:
- 'salt/minion/*/start':
- /srv/salt/reactor/minion_start.sls
- 'salt/job/*/ret/*':
- /srv/salt/reactor/job_return.sls
Reactor state:
# /srv/salt/reactor/minion_start.sls
# Triggered when minion starts
highstate_on_start:
local.state.apply:
- tgt: {{ data['id'] }}
- arg:
- highstate
notify_admin:
local.cmd.run:
- tgt: salt-master
- arg:
- 'echo "Minion {{ data[id] }} joined" | mail [email protected]'
Job return reactor:
# /srv/salt/reactor/job_return.sls
# Triggered when job completes
check_status:
local.cmd.run:
- tgt: salt-master
- arg:
- 'logger "Job {{ data[jid] }} completed on {{ data[id] }}"'
store_return:
local.event.fire:
- name: custom/job/complete
- data:
minion: {{ data['id'] }}
jid: {{ data['jid'] }}
Fire custom events:
# Fire event from master
sudo salt-call event.fire_master "message" "tag"
# From minion
sudo salt-call event.fire "message" "custom/event/name"
# Async execution tracked by reactor
sudo salt '*' cmd.run 'sleep 10' -b 10 # Batch mode
Conclusión
SaltStack provides powerful infrastructure automation through a clean master-minion model and YAML-based configuration. By mastering state management, pillar data for configuration, grains for targeting, and the reactor for event-driven automation, you create scalable infrastructure management that grows with your organization. SaltStack's combination of configuration management and remote execution capabilities makes it ideal for complex infrastructure orchestration at any scale.


