Configuration Management tools like SaltStack are invaluable for managing infrastructure at scale. Even in the growing world of containerization where immutable image deployment is the norm, those images need to be built in a repeatable and auditable fashion.
This article will detail installation of the SaltStack master on Ubuntu Xenial 16.04, with validation using a single Minion.
Note that Minion/agent installation is not mandatory if using Salt SSH.
Installation
The first step is to add the SaltStack repository and key:
$ wget -qO - https://repo.saltstack.com/apt/ubuntu/16.04/amd64/latest/SALTSTACK-GPG-KEY.pub | sudo apt-key add - $ sudo apt-get install apt-transport-https ca-certificates -y $ echo "deb http://repo.saltstack.com/apt/ubuntu/16.04/amd64/latest $(lsb_release -cs) main" | sudo tee -a /etc/apt/sources.list.d/saltstack.list
Then refresh the repository and install the SaltStack master:
$ sudo apt-get update $ sudo apt-cache policy salt-master $ sudo apt-get install salt-master -y
Make sure the firewall allows communication to the SaltStack ports and create default directories to support the state and pillar files:
$ sudo ufw allow 4505:4506/tcp $ sudo mkdir -p /srv/salt $ sudo mkdir -p /srv/pillar $ sudo systemctl restart salt-master
The log is at ‘/var/log/salt/master’ and ‘journalctl -u salt-master’. And the main configuration file is at ‘/etc/salt/master’.
Test Minion
In order to validate the SaltStack Master, we will install a Minion on the same server.
$ sudo apt-get install salt-minion -y
Then we will need to modify the configuration at ‘/etc/salt/minion’, so that it points to the master. Find the line that starts with ‘master:’ and point it at localhost (or the name/IP address of listening master)
master: localhost
Then restart the minion:
$ sudo systemctl restart salt-minion
Now, even though the Salt minion has projected its identity to the master, we need to have the master accept the key for security. List the minions that are waiting for acceptance:
$ sudo salt-key -L Accepted Keys: Denied Keys: Unaccepted Keys: xenial1 Rejected Keys:
You can see that my minion is named ‘xenial1’ (which is the hostname). We now need to accept the key, and after we do that, we can run a few quick commands to validate it is working properly.
$ sudo salt-key -y -a xenial1 $ sudo salt 'xenial1' test.version $ sudo salt 'xenial1' cmd.run 'ls /tmp'
Validate States and Pillars
Now we will create a set of state and pillar files for a quick test. If you need to read more about the concept of Pillars for defining variable data and State files for applying logic, then see the “Salt in 10 minutes” walkthrough.
Remember, my minion’s name is ‘xenial1’, but you will need to adjust this to target your own minion’s name.
Create the following pillar files in the Salt Master’s default directories:
# /srv/pillar/top.sls base: 'xenial1': - test1
# /srv/pillar/test1.sls test1: lookup: mystringdata: this is for test1 mydictdata: key1: dictvalue1 key2: dictvalue2 mylistdata: - item1 - item2
Then the following state files:
# /srv/salt/top.sls base: 'xenail1': - test1
# /srv/salt/test1.sls test1-task1: cmd.run: - name: echo this is test1.task1 # show string pillar data test1-pillartest-string: cmd.run: - name: echo {{ salt['pillar.get']('test1:lookup:mystringdata') }} # show list pillar data {% for value in salt['pillar.get']('test1:lookup:mylistdata') %} test1-pillartest-list-{{value}}: cmd.run: - name: echo from the list, {{ value }} {% endfor %} # show dictionary pillar data {% for key,value in salt['pillar.get']('test1:lookup:mydictdata').items() %} test1-pillartest-dict-{{key}}: cmd.run: - name: echo from the dictionary, {{ key }} is {{ value }} {% endfor %}
Now, when you check the pillar data for this minion, you should see output like below:
$ sudo salt 'xenial1' pillar.items xenial1: ---------- test1: ---------- lookup: ---------- mydictdata: ---------- key1: dictvalue1 key2: dictvalue2 mylistdata: - item1 - item2 mystringdata: this is for test1
And when you apply the highstate to this minion you should see something like below:
$ sudo salt 'xenial1' state.apply xenial1: ---------- ID: test1-task1 Function: cmd.run Name: echo this is test1.task1 Result: True Comment: Command "echo this is test1.task1" run Started: 15:35:29.107767 Duration: 14.613 ms Changes: ---------- pid: 10131 retcode: 0 stderr: stdout: this is test1.task1 ---------- ID: test1-pillartest-string Function: cmd.run Name: echo this is for test1 Result: True Comment: Command "echo this is for test1" run Started: 15:35:29.107767 Duration: 18.173 ms Changes: ---------- pid: 10132 retcode: 0 stderr: stdout: this is for test1 ---------- ID: test1-pillartest-list-item1 Function: cmd.run Name: echo from the list, item1 Result: True Comment: Command "echo from the list, item1" run Started: 15:35:29.124748 Duration: 2.184 ms Changes: ---------- pid: 10133 retcode: 0 stderr: stdout: from the list, item1 ---------- ID: test1-pillartest-list-item2 Function: cmd.run Name: echo from the list, item2 Result: True Comment: Command "echo from the list, item2" run Started: 15:35:29.127023 Duration: 6.268 ms Changes: ---------- pid: 10134 retcode: 0 stderr: stdout: from the list, item2 ---------- ID: test1-pillartest-dict-key2 Function: cmd.run Name: echo from the dictionary, key2 is dictvalue2 Result: True Comment: Command "echo from the dictionary, key2 is dictvalue2" run Started: 15:35:29.133386 Duration: 2.296 ms Changes: ---------- pid: 10135 retcode: 0 stderr: stdout: from the dictionary, key2 is dictvalue2 ---------- ID: test1-pillartest-dict-key1 Function: cmd.run Name: echo from the dictionary, key1 is dictvalue1 Result: True Comment: Command "echo from the dictionary, key1 is dictvalue1" run Started: 15:35:29.135772 Duration: 4.81 ms Changes: ---------- pid: 10136 retcode: 0 stderr: stdout: from the dictionary, key1 is dictvalue1 Summary for xenial1 ------------ Succeeded: 6 (changed=6) Failed: 0 ------------ Total states run: 6 Total run time: 32.344 ms
REFERENCES
https://repo.saltstack.com/#ubuntu
https://fabianlee.org/2016/10/31/saltstack-running-a-masterless-minion-on-ubuntu/
https://fabianlee.org/2017/05/12/saltstack-installing-a-salt-master-on-ubuntu-14-04/