Академический Документы
Профессиональный Документы
Культура Документы
Jul
4 Comments
25
At first learning Salt can seem like a daunting task, which can be if a holistic view of the system is
not clear during the process. Here we will list and describe the basic components of Salt and how
they interact with each other. This is not a step-by-step guide, the folks at SaltStack (the company
that makes Salt) have provided us with great documentation and good step-by-step walkthroughs to
get you through your first steps. I recommend you go there after getting a sense of the big picture
here.
What is Salt?
Salt is a multi OS provisioning and manteinance system. What it does is get all the software and
configuration into brand new servers automatically. This allows administrators and IT personnel to
spend the least amount of time setting new servers, liberating them for more important tasks like
developing new systems, investigating new tools, fixing bugs or getting the HP printer to work (good
luck with that). It also standarizes what gets installed on each server, so bugs are easier to diagnose
and fix. Salt also allows you to automatize and paralellize other common tasks like updating the
server software or running backup scripts.
Installation
The installation process is very well covered in the Salt docs, you can find them here. As of Salt
2014.1.5 the following OS are supported: Archlinux, Gentoo, Debian, Ubuntu, Fedora, Windows, OS
https://blog.talpor.com/2014/07/saltstack-beginners-tutorial/ 1/19
5/20/2016 Salt - Beginners Tutorial | Talpor Solutions Blog
X, Solaris, SUSE, RHEL, CentOS, Scientific Linux, Amazon Linux and Oracle Linux; so you're
probably covered.
Master
Minions
Keys
States
Grains
Pillar
The master is the Salt server, the minions are the target machines that will be provisioned. Each
minion has an unique ID based on its FQDN. One nice thing about Salt is that the firewall
configuration of the minions rarely has to be changed, as the master doesn't connect to its minions,
but is the minions that open and maintain a TCP connection to the master. The master then uses
these open TCP connections to send commands back.
Keys
Keys are used for security. When a minion initializes it generates an asymmetric cryptographic key
that must be approved by the master before it can send commands to that minion.
States
The states are the heart and soul of Salt, they define just that, a state, a specific set of things that are
to be a certain way. States are stored on the master as Jinja2 templates and passed to the minions
where they are rendered and parsed as YAML. They can be parameterized by grains and Pillar (more
https://blog.talpor.com/2014/07/saltstack-beginners-tutorial/ 2/19
5/20/2016 Salt - Beginners Tutorial | Talpor Solutions Blog
on that in a minute). States can manage a myriad of things including, but certainly not limited to,
files, MySQL databases, PostgreSQL databases, system packages, system services, ssh keys,
users, python virtual environments, rvm environments, pip packages, timezones, mail aliases; heck,
they can even run arbitrary commands on the console.
States are stored in sls files, each of these files can store several states and may reference other sls
files. An sls file may look something like this:
### ssh.sls ###
sshserver: # State ID.
pkg.installed: # Make sure that ssh is installed.
name: opensshserver
sshdconfig: # State ID.
file.managed: # Make sure that the ssh config on the minion
name: /etc/ssh/sshd_config # is the same as the one stored in the master
source: salt://ssh_state/files/sshd_config
require: # Make sure that ssh is installed before
pkg: sshserver # managing its config file.
sshservice: # State ID.
service.running: # Make sure the ssh service is running and
enable: True # that is configured to start at boot.
watch: # Restart the service if there are
file: sshdconfig # changes in the ssh config file.
Don't fret if it looks daunting or there are things that are not clear, the idea is to get a basic
understanding of the abstractions that states provide.
Grains
The grains are stored on each minion in YAML and hold OS and hardware specific information to that
minion. Things like the FQDN of the minion, its minion ID, the CPU flags, IPs of the different
interfaces, kernel information, total memory, OS family, the salt version of the minion among other
pieces of information; all of this is automatically gathered by Salt. You can add grains to a minion by
placing them in the file /etc/salt/grains in YAML format, or in the minion configuration file also in
YAML format under the id 'grains' . Here is just a fraction the grains on my computer:
https://blog.talpor.com/2014/07/saltstack-beginners-tutorial/ 3/19
5/20/2016 Salt - Beginners Tutorial | Talpor Solutions Blog
kernel: Linux
kernelrelease: 3.14.7100.fc19.x86_64
localhost: jonhdoe
lsb_distrib_id: Fedora
manufacturer: TOSHIBA
master: salt
mem_total: 5442
nodename: jonhdoe
num_cpus: 4
num_gpus: 1
os: Fedora
os_family: RedHat
osarch: x86_64
oscodename: Schrödinger’s Cat
osfinger: Fedora19
osfullname: Fedora
Pillar
Pillar is completely awesome and totally optional, but throughout this tutorial we'll assume that you
are/will use it. Pillar is stored in the master as a Jinja2 template; and is passed to minions, rendered
and parsed as YAML when its information is needed, thus, Pillar has access to the minion grains,
which includes the minion ID.
Pillar is used to store data, and it can store any kind of data; it is a very versatile system. It usually
holds:
Minion configuration: ie. The name of the Apache package (RedHat based is httpd, Debian based
is Apache2)
Variables: ie. The list of the company DNS servers, or a variable that indicates to which
deparment/subnet/category the minion belongs.
Configurations files are usually not stored in Pillar as they're generally specific to certain states and
are thus stored next to their sls files.
One of the neat things about Pillar is that the transfer is cryptographically secured, and that it is
stored in the master but rendered in the minion. This way you can pass common, static data to the
minions from the master (ie. The list of users to create on the minions for the admins to use), as well
as generate dynamic information regarding one minion in particular (ie. A list of name packages to
install based on the minion OS and IP).
https://blog.talpor.com/2014/07/saltstack-beginners-tutorial/ 4/19
5/20/2016 Salt - Beginners Tutorial | Talpor Solutions Blog
Pillar files are also stored with an sls extension. A Pillar file, lets call it common.sls, may look
something like this:
### common.sls ###
{% if grains['os'] == 'Debian' %}
apache: apache2
{% elif grains['os'] == 'RedHat' %}
apache: httpd
{% endif %}
users:
jaber:
username: gjaber
password: <cryptographic hash or a extract of a perl script here>
moba: LoL
rondon:
username: mrondon
password: <cryptographic hash or a extract of a perl script here>
moba: Dota2
dns:
server1: 8.8.8.8
server2: 8.8.4.4
You may not need Pillar at first, but is a powerful and essential tool for more advanced setups.
Basically, the states define how some things should be. Pillar and the grains are used to determine
which minions are subjected to which states and to parameterize the states themselves. Here is a
diagram:
https://blog.talpor.com/2014/07/saltstack-beginners-tutorial/ 5/19
5/20/2016 Salt - Beginners Tutorial | Talpor Solutions Blog
I omitted the details of the YAML parser as they're not essential to get the point across. Also, in the
image, it should be YAML not 'yalm'.
Note that the Pillar templates are rendered first and then fed into the states templates together with
the grains. After the rendering is done, Pillar and the grains are still used to determine what states
are to be applied to the minion.
In simpler cases, there won't be a complicated process to decide which states get applied because
we'll directly specify the sls file. On the simplest case the state and Pillar files won't even be
necessary because we'll just target a set of minions and specify one function we want to run on
them.
But how exactly does Pillar and the grains target minions and parameterize states? The section
"Targeting minions and specifying states/Pillar data" tackles these issues, but first we have to learn a
bit about how Salt is organized and the different options we have to send commands to the minions.
Directory structure
Before diving onto how exactly we target minions, we must learn how Salt normally stores its states
and Pillar information on the master.
The configuration files for the master are in /etc/salt/, the main one being /etc/salt/master. However
the state files (sls files) are usually stored in /srv/salt. Pillar files are usually stored in /srv/pillar. Each
of these directories has a file called top.sls that indicates which minions are subject to which
states/Pillar files. The configuration files for the minion are in /etc/salt also, the main one being
/etc/salt/minion.
https://blog.talpor.com/2014/07/saltstack-beginners-tutorial/ 6/19
5/20/2016 Salt - Beginners Tutorial | Talpor Solutions Blog
Salt has support for a multienvironment setup that allows for a minion to use a different set of
aggregated directories from which to pull states/Pillar based on this grains and Pillar data, but for the
purposes of this tutorial and the sake of simplicity, we'll assume that there are no shenanigans, so all
sls files are stored directly under /srv/salt and all Pillar files are stored under /srv/pillar, following a
plain directory structure.
Applying states
One is specifying a given set of minions and an sls file. Salt allows you to group minions by a name
beforehand, or use regular expressions, grains and pillar to define a set of minions. In this case, the
top.sls files are irrelevant.
The other, more interesting one, is to specify a set of minions (may be all minions) and saying to Salt:
“You find out what needs to be done to these guys, I'll drink cocoa while I wait”. Though this sounds
nice, what comes before is having configured the top.sls files on /srv/salt and /srv/pillar, and all of
the pertinent sls files, but to be fair that hard part you only have to do "once".
You can also specify a set of minions and a specific command to run on them (ie. pkg.install
apache2). This is useful when we don't need/want to create an sls file for a minor change.
Targeting what minions get hit is done from the command line. Specifying what is done to the those
minions is done either by writing a Salt function as part of the command (ie. pkg.install apache),
specifying an sls file, or asking Salt to use the top.sls files to determine the pertinent states.
Specifying minions
Let go over how to say who gets hit. This is done from the command line.
Salt uses ZeroMQ for the communication with its minions. As of Salt 2014.1.5, minions can be
targeted by: minion ID, grains, pillar data, IPv4 address, FQDN or predefined minion groups (node
groups), or by any combination of the above; all of these support regular expressions too. Lets see
some examples:
# test.ping is a special Salt
https://blog.talpor.com/2014/07/saltstack-beginners-tutorial/ 7/19
5/20/2016 Salt - Beginners Tutorial | Talpor Solutions Blog
# function that test the connectivity
# of the minion's Salt daemons.
# It is not an ICMP ping.
# The special * wild card matches all minions
salt '*' test.ping
# By minion ID, target all minions that end in *.baz.com
salt '*.baz.com' test.ping
# By minion ID, and using regexes instead of shelllike globbing,
# target webprod and webdev
salt E 'web(prod|dev)' test.ping
# By minion ID, a list of minions
salt L 'webjonh, dboracether' test.ping
# By grains, target the RedHat and Debian systems
salt G 'os:(RedHat|Debian)' test.ping
# By Pillar data, target human resources
salt I 'deparment:HR' test.ping
# By IP/subnet, target the local network
salt S '192.16.0.0/24' test.ping
# By minion ID and grains
salt C 'web* and G@os:Ubuntu' test.ping
# By grains and Pillar data
salt C 'G@cpuarch:x86_64 and I@office:32D' test.ping
Now onto saying what gets done. The simplest way is to specify a Salt function. Salt offers a variety
of functions. There are functions to manage the package system, run tests on the minion, manage
files, manage web servers among other things. These functions are called Execution Modules; you
can write your own execution modules by the way. Onto some examples:
# Ping all minions. Not an ICMP ping
salt '*' test.ping
# Emacs for everybody
salt '*' pkg.install emacs
# Run ls /etc
salt '*' cmd.run 'ls l /etc'
https://blog.talpor.com/2014/07/saltstack-beginners-tutorial/ 8/19
5/20/2016 Salt - Beginners Tutorial | Talpor Solutions Blog
We can also specify an sls file. Sls files don't normally use execution modules, and instead use state
modules that are called automagically by Salt when it processes the state, although there is a special
state module to call execution modules from within sls files. More on writing states in a minute:
# Apply the states from the ssh.sls file on all minions.
# Notice how we omit the .sls extension in the command line.
salt '*' state.sls ssh
This is the most powerful way of saying what gets done, although is the most difficult to set up. It
says to Salt to figure out what its to be done to each targeted minion. The command is simple
enough:
salt '*' state.highstate # Change '*' for the target of your preference.
The parameters that determine which of the selected minions get what states and pillar information
is in /srv/salt/top.sls and /srv/pillar/top.sls, directories may vary depending on your setup, but these
are the most common ones.
We'll explain only how to setup /srv/salt/top.sls, as one is analogous to the other:
### top.sls ###
base: # Mandatory name of the base env, ignore it for now
'*': # All minions targeted get the following sls files
common # Name of the sls file minus the extension
### common.sls ###
commonpkgs: # State ID
pkg.installed: # Make sure all of these are installed
names:
emacs
opensshserver
nginx
adminuser: # Set up a user for administration purposes
user.present:
name: {{ pillar['adminname'] }}
password: {{ pillar['adminpass'] }}
https://blog.talpor.com/2014/07/saltstack-beginners-tutorial/ 9/19
5/20/2016 Salt - Beginners Tutorial | Talpor Solutions Blog
# You could also store in Pillar a dictionary of users
# and iterate over them here, creating them all.
# https://gist.github.com/UtahDave/3785738
This top file is telling us: “all minions are to run the states on 'common'.sls". To clarify, this target is
not telling what minions get hit, that was specified on the command line, this target is acting on the
set of minions that were targeted, and is telling that all of those minions are to apply the states on
common.sls:
### /srv/salt/ ###
. .. common.sls nginx.sls postgres.sls top.sls
### top.sls ###
base:
'*':
common
'web*':
nginx
'db*':
postgres
This uses the minion ID to run different sls on different minions, particularly, is telling the targeted
web server minions to install nginx, and the database ones to install postgresql, and all of them to
run the states in common.sls. So for example, a minion with ID 'web-skynet' would apply the state
files 'common.sls' and 'nginx.sls', 'dbGlaDos' would apply 'common.sls' and 'postgres.sls', and
'theCakeIsALie' would only apply 'common.sls'. Lets see what else can we do:
### /srv/salt/ ###
https://blog.talpor.com/2014/07/saltstack-beginners-tutorial/ 10/19
5/20/2016 Salt - Beginners Tutorial | Talpor Solutions Blog
. .. apache.sls ati_fglrx.sls common.sls nginx.sls top.sls
### top.sls ###
base:
'*':
common
'web* and G@wserv:nginx':
match: compound # We need to specify the kind of
nginx # match when not matching against IDs
'web* and G@wserv:apache':
match: compound
apache
'gpus:model:*Radeon*': # Two colons means that the grain
match: grain_pcre # 'gpus' is a dictionary and we want
ati_fglrx # the key 'model'
Here we have set grains in our servers in advance that tells us whether it should run Apache or
Nginx, we also use a grain to install the ATI proprietary driver FGLRX on the targeted machines that
have Radeon graphic cards.
The top.sls on /srv/salt/pillar (directory may change depending on your implementation) functions
exactly the same way, only that instead of running states, it tells what minions receive which Pillar
files, and hence what data.
Writing states
Now onto the heart and soul of Salt, writing state files. Lets begin simple:
### sl.sls ###
slpkg: # State ID
pkg.latest: # State module
name: sl
Short, concise. It installs the package sl if it not installed already, updates it if it is outdated. Salt
makes sure that the package database is updated prior to doing package operations. What about
files?
### unattendedupgrades.sls ###
unattendedupgradeson: # State ID
file.uncomment: # State module
https://blog.talpor.com/2014/07/saltstack-beginners-tutorial/ 11/19
5/20/2016 Salt - Beginners Tutorial | Talpor Solutions Blog
name: /etc/apt/apt.conf.d/50unattendedupgrades
regex: 'UnattendedUpgrade::Mail .*;'
char: '//'
### collectdglobal.sls ###
collectdglobalconf:
file.managed:
name: /etc/collectd/collectd.conf
source: salt://collectd/files/collectd.conf
The first one uncomments a line that matches 'regex', turning on Ubuntu's unattended upgrades.
The second one makes sure that the file /etc/collectd/collectd.conf in the minion is exactly the same
as the one in /srv/salt/collectd/files/collectd.conf in the master; the Salt file state module is very
flexible. Now, what about services?
dockerserv: # Make sure the service 'docker' is
service.running: # running and enabled to start at boot.
name: docker
enable: True
This is simple, but how about a more complex configuration? With files, services, packages,
repositories, and custom commands?
dockerkernelpkgs: # Install these kernel packages
pkg.latest:
pkgs:
linuximagegenericltsraring
linuxheadersgenericltsraring
dockerapthttpstransportmethod: # Run this command...
cmd.run:
name: aptget update & aptget install y apttransporthttps
unless: [ ! e /usr/lib/apt/methods/https ] # ... unless this is true
require:
pkg: dockerkernelpkgs # This state has to run successfully first
dockerrepo: # Install the Ubuntu PPA for Docker...
pkgrepo.managed:
name: deb https://get.docker.io/ubuntu docker main
file: /etc/apt/sources.list.d/docker.list
keyserver: hkp://keyserver.ubuntu.com:80
keyid: 36A1D7869245C8950F966E92D8576A8BA88D21E9
require:
cmd: dockerapthttpstransportmethod # ...only if this state ran
https://blog.talpor.com/2014/07/saltstack-beginners-tutorial/ 12/19
5/20/2016 Salt - Beginners Tutorial | Talpor Solutions Blog
dockerpkg: # Install the package lxcdocker...
pkg.latest:
name: lxcdocker
require:
pkgrepo: dockerrepo # ...only if you ran the state dockerrepo alread
dockerserv: # Make sure that the 'docker' is up and
service.running: # running...
name: docker
enable: True # ... also set it to start at boot.
watch:
pkg: dockerpkg # If this package changes, restart this service.
Well, that was a handful. The most confusing bits might be the require and watch clauses, these
are requisites, which are pretty important in Salt.
You see, Salt ensures that states run in the order they are written, and if one fails, it will continue
forward; but when you add requirements to the mix, you can do stuff like restarting a service when a
file or package changes, turn off load balancing servers when a deployment is about to run, stop
running a state if a previous one fails among other things.
Most likely you'll be using 'require' the majority of the time, with a couple of 'watch' into the mix. If
you feel like you are writing too many boiler-plate 'require' clauses, you can turn on the fail hard
global option.
nginxpkg: # State ID
pkg.installed: # State module
name: nginx
nginx: # State ID
pkg.installed # State module
You see, EVERY state receives a 'name' argument, and when that argument is not provided in the sls
file, Salt uses the state ID and plugs it in the argument. This form is very common in examples
https://blog.talpor.com/2014/07/saltstack-beginners-tutorial/ 13/19
5/20/2016 Salt - Beginners Tutorial | Talpor Solutions Blog
I don't like this form, the reason is that *** the state ID namespace in salt is flat ***. That means that if
there are any two states with the same ID, no matter in which folders, sls files or environment, when
highstate gets run you'll get something along the lines of:
Detected conflicting IDs, SLS IDs need to be globally unique.
So lets say for example that you have one state for collectd for your web servers, and another for
your dns servers:
### webcollectdglobal.sls ###
/etc/collectd/collectd.conf: # State ID
file.managed:
source: salt://webcollectd/files/collectd.conf
### dnscollectdglobal.sls ###
/etc/collectd/collectd.conf: # State ID
file.managed:
source: salt://dnscollectd/files/collectd.conf
It will explode when you try to run highstate. There are two ways to solve this, number one:
### webcollectdglobal.sls ###
webcollectdglobal: # State ID
file.managed:
name: /etc/collectd/collectd.conf
source: salt://webcollectd/files/collectd.conf
### dnscollectdglobal.sls ###
dnscollectdglobal: # State ID
file.managed:
name: /etc/collectd/collectd.conf
source: salt://dnscollectd/files/collectd.conf
Problem solved. Number two, use the stateconf renderer, problem solved.
Caveat 2: The state module function file.recurse doesn't recurse file permissions
There is this neat state module function called file.recurse, it functions kind like rsync, you pass a
directory on the master and one on the minion, and it will make the one on the minion like the one on
the master, except that it will not recurse file permissions, so any executable files you will have to
https://blog.talpor.com/2014/07/saltstack-beginners-tutorial/ 14/19
5/20/2016 Salt - Beginners Tutorial | Talpor Solutions Blog
Caveat 3: The is a MySQL grants state module, but no PostgreSQL grants state module,
nor a general database state module for that matter.
Well just that, if you want to manage PostgreSQL grants, you'll have to use the cmd state module,
and your sls files will have to cater every kind of DB you're running separately.
I've encountered this problem several times, it is recorded as an issue. Don't fret if this happens, the
minions are still working and each one has its own internal log, but it can be disorienting at first.
There are surely other caveats, but these are the ones I remember for now that have affected me.
Onto the LIE.
I lied...yes...I know...I'm a terrible person, but hear me out, I did it for your own good. The matter of
fact is that states do have to be in files, but you can place them in files called 'init.sls' and place
those in directories with the name of the state. For example, if I want to make a SSH state, I wouldn't
make a file called 'ssh.sls', but I would create a 'ssh/' directory inside '/srv/salt/':
### /srv/salt/ssh/ ###
. .. init.sls files/
### /srv/salt/ssh/files/ ###
. .. sshd.conf
That way your sls files and all of its config files are kept inside a nice little box. This is particularly
useful to contain in an orderly manner several sls files that call each other.
Also it was a white lie, and a lie of omission, so we're cool...right??? Here, I'll give you some gifts to
compensate.
https://blog.talpor.com/2014/07/saltstack-beginners-tutorial/ 15/19
5/20/2016 Salt - Beginners Tutorial | Talpor Solutions Blog
1. Orchestration: this is for more complex setups that need to be done in a certain way and order. It
was previously handled by the Overstate system, but that is being replaced by the Orchestrate
runner.
2. salt-cloud: you give salt the credentials of your cloud computing services account (AWS, Linode,
DigitalOcean, etc), and it can provision the creation of instances on these platforms with the salt
minion package already installed. This makes a breeze to provision Salt with Salt for the parts of
your platform that are in the cloud.
3. salt-ssh: this is a functionality still in alpha. It is a command utility that allows to send orders to
other machines using only SSH (more akin to what Ansible does). It could simplify your simpler
use cases.
4. State and execution modules for managing Docker: So if you're part of the Docker hype train, you
might be interested in that execution and state modules for managing docker containers and
images are already in beta.
5. External authentication: if you want to run on a minion as somebody other than root (Salt runs as
root by default), you should take a look at this feature. It allows to use alternate authentication
methods.
7. Proxy minions; This feature is still under development. It aims to tackle the situation of having
some devices that can't, for whatever reason, run a Salt minion.
8. salt-call: When we send commands to a minions, said minion does not return all of the output,
moreover it sends it back only once it finished applying all of the required states. The command
salt-call allows you to call a salt command from within the minion and see the live output. It is
very useful for debugging purposes, specially when you are taking your first steps or testing a
brand new state. To be clear, salt-call is called from the minion you're trying to debug, not from
the master.
These are the ones I remember/know for now. Here are some other useful links I provided throughout
the tutorial:
2. Official walkthrough
https://blog.talpor.com/2014/07/saltstack-beginners-tutorial/ 16/19
5/20/2016 Salt - Beginners Tutorial | Talpor Solutions Blog
3. Requisites
4. Stateconf renderer
7. Environments
8. Nodegroups
9. Targeting minions
Topics : Salt Provisioning SaltStack DevOps
3 Tweet
Like 4
https://blog.talpor.com/2014/07/saltstack-beginners-tutorial/ 17/19
5/20/2016 Salt - Beginners Tutorial | Talpor Solutions Blog
talPor Solutions Blog How to make a Make a metric dashboard for Trello
simple Phonegap App in an hour or … with Django Dashing | talPor …
1 comment • 2 years ago 1 comment • 2 years ago
marduke182 — El performance de jQuery Niloronno — something is going wrong i
mobile es muy malo, no se como am doing every thing but couldn't run it in
trabajaran ahora pero antes trabajaban … the local server.To see the dashboard …
AvatarGerman Jaber — You're welcome. I'm AvatarAlejandro Rojas — Great to see this
glad it helped you. I'm not sure when you blog...I will tell Levi about it to keep off
read the article, but I recently added a … those 1.5 bugs
https://blog.talpor.com/2014/07/saltstack-beginners-tutorial/ 18/19
5/20/2016 Salt - Beginners Tutorial | Talpor Solutions Blog
https://blog.talpor.com/2014/07/saltstack-beginners-tutorial/ 19/19