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:

Salt breakdown

  • sudo, of course, is the Linux program for granting superuser privileges to users.
  • salt is 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.ping is 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 pkg.install module:

$ 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 /srv/salt directory:

$ 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

The 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 ; .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.present state. 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 fox state:

include:
  - users.fox

Note the users. prefix.

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 salt command:

$ 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 top.sls file.

Back in the /srv/salt directory, open top.sls and add - users:

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 vagrant halt.

 

DevOps Guides

Leave a Reply

Your email address will not be published. Required fields are marked *

Get actionable training and tech advice

We'll email you our latest articles up to once per week.