Anyone with a passing interest in DevOps is probably familiar with configuration management and the variety of options available for the mass configuration and orchestration of servers: Puppet, Chef, Ansible, and, of course, Salt. Salt itself is a configuration management platform based in Python that leverages a high-speed data bus to allow users to manage their infrastructure.
Salt comes in two flavors: SaltStack Enterprise, which offers a graphical interface for managing Salt, and Salt Open, which stands out from certain competitors by offering no limits to how many minions you manage. In this post, we’ll be using Salt Open to get a quick look at Salt’s core features and functionalities. If you’re thinking about using Salt for future projects or are just curious about how Salt stacks up compared to other “Infrastructure as Code” options, this post is for you.
Start the Test Environment
For this demo, we’re going to use Vagrant and Virtual Box to set up a basic Salt environment. If you’re unfamiliar with Vagrant, check out this post to get started! Also, ensure you have guest tools installed for Virtual Box.
Navigate to the directory in which you want to store your Salt environment. We’re going to use the demo Vagrant environment offered by SaltStack employee David Boucha, found in this GitHub repository. Then, clone the Git repo:
$ git clone https://github.com/UtahDave/salt-vagrant-demo.git
Move into the provided directory, then start the Vagrant environment:
$ cd salt-vagrant-demo $ vagrant up
Note that it may take a few minutes for the Vagrant environment to provision.
Our environment has three Ubuntu 16.04 machines: A Salt Master (“master”) and two guests (“minion1” and “minion2”).
Log in to the master server:
$ vagrant ssh master
We’re now ready to run our first commands!
Using Salt for Orchestration
One of the primary features of Salt is that it can be used for orchestration – this means running a command on multiple computers without having to log in to each computer. Salt does this through the use of execution modules. Salt has a large list of execution modules pre-made, but you can also make your own using Python. Since we’re just trying out Salt, we’re going to use some pre-made ones to see how they work.
First, let’s take a look at the command structure by testing to make sure our minions are responding:
$ sudo salt '*' test.ping minion2: True minion1: True
As we can see, both minion1 and minion2 reported values of “true.” This means our servers are working properly and connected to our master. But, before we get any further, let’s break down the command we just ran:
sudo, of course, is the Linux program for granting superuser privileges to users.
saltis the primary command for the Salt platform that’s used on the master server. This command is used to run execution modules and states (discussed below) in parallel across all our servers.
'*'is the target. The target is where we can run our commands. We can target via minion names, server facts (such as operating system), or regular expression. In our example command, we use the regex for “all” to target every one of our servers.
test.pingis the execution module itself. In this case, it makes sure our servers can ping, or reply to our master server. Execution modules can also take parameters, which would come after the module name, but we’re not using any for this example.
Now, let’s try another. Say we want to install Apache only on our minion1 server. We would use the
$ sudo salt minion1 pkg.install apache2
Note that we have to already know the name of the package, which on Ubuntu is apache2.
But we don’t always want to run commands to bring a minion up to date. Instead, we often want to describe the end state of something and have any servers we add use this blueprint to reach the desired state. For this, we need Salt sates.
Using Salt States
To start, let’s move into the
$ cd /srv/salt
If we take a look, we can see that there is already a file and directory in there!
$ ls common top.sls
top.sls file is a mapping of what states we want to run on what servers. Let’s take a look at the one provided here:
$ cat top.sls base: '*': - common
base is our primary environment, and the
'*' line —much like in our execution module example— means that whatever is listed under this is added to all servers. In this case, the
common state will be added. But what is the “common” state?
Move into the
common directory and list the available files:
$ cd common $ ls init.sls packages.sls
Here we have two files ending in
.sls denotes that it’s a state file. In this case, the
init.sls file is the file that allows states to run via their directory name (remember that in our
top.sls file we call the “common” state, which is the name of our overall directory). This file lists any additional files we want to include with our state. This particular
init.sls file calls to the
packages.sls file, which installs htop, strace, and vim:
$ cat packages.sls common_packages: pkg.installed: - pkgs: - htop - strace - vim
As we can see, this state file is written in YAML, which is the default configuration language for Salt.
So, let’s create our own state file. Move back to the
/srv/salt/ directory, then create a
users directory and move into that new directory:
$ cd .. $ mkdir users $ cd users
Let’s create a user named
fox.sls. With your preferred text editor, open this file and add the following information:
fox: user.present: - fullname: Fox Mulder - home: /home/fox/ - shell: /bin/zsh/
But what does this mean? Let’s take a look at it line-by-line:
fox:: This is the reference ID, which means it’s the name of this state. Later, when we add this file to our user’s
init.sls, we’ll add it by calling it “fox”; furthermore, since this is a name key in YAML, it ends with a colon.
user.present: This is our state module, which is a preconfigured state that is ready for Salt to use. In this instance, we’re ensuring that our user (fox) is present.
- fullname: Fox Mulder: Here we have our first parameter for the
user.presentstate. In this case, we ensure our user has the full name of “Fox Mulder.”
- home: /home/fox: Another parameter, this one defining the home directory for our user.
- shell: /bin/zsh: Our final parameter, defining the default shell for our user.
Save and exit the file.
Next, add a second file,
init.sls, and add the following to call our
include: - users.fox
Save and exit.
We can now use these states to add the fox user to our minions! We can do this two ways. First, let’s add it manually to minion1 using the
$ sudo salt minion1 state.apply users
Alternatively, we can add our users state to the
top.sls file and then run a highstate – meaning, Salt will run all our states based upon the mapping we provide in the
Back in the
/srv/salt directory, open
top.sls and add
base: '*': - common - users
Apply the changes to all servers:
$ sudo salt '*' state.apply
And that’s it! You’ve now gotten hands-on with Salt! You can continue to experiment further or use the
exit command to log out of the master server. To stop your environment entirely, run