- Salt is Configuration Management Tool.
- It is written in Python
- It uses YAML
- Very flexible and faster
- Server-Client technology for Configuration Management
- Salt works on ZeroMQ for master and Minion Communication
Components of Salt:
salt-master | Master node which pushes the configuration |
salt-minion | Slave node which connects to Master and get the configuration |
Execution Modules | Salt Modules which can be used on command line execution |
State Modules | Salt Modules which can be used in State Files/Formulas |
Grains |
|
Pillars |
|
Top File / top.sls | This file is mainly used in state.apply or highstate. States are defined according to Minions, environments in this file. |
Salt Mine | Used to share data values among salt minions. For eg. If you set up a shared DB. You can configure the Salt minion that is running on the DB server to push its IP address to the salt mine automatically. This is better than storing it in a salt state or pillar. |
Runners | Modules that execute on Salt master to perform supporting tasks. They report job status, connection status, read data from external APIs, query salt minions |
Returners | Send data returned by Minions to another system such as DB. |
Reactor | Trigger actions when events occur. |
More Terminologies:
Formula | A collection of Salt state and Salt pillar files that configure an application or system component. Most formulas are made up of several Salt states spread across multiple Salt state files. |
State | A reusable declaration that configures a specific part of a system. Each Salt state is defined using a state declaration. |
State Declaration | A top level section of a state file that lists the state function calls and arguments that make up a state. Each state declaration starts with a unique ID. |
State Functions | Commands, used to perform a configuration task on a system. |
State File | File with SLS extension, contains one or more state declarations aka formula. |
Pillar File | A file with an SLS extension, defines custom variables and data for a system. |
Important files of Salt:
/etc/salt | Root configuration folder |
/etc/salt/master | Configuration file for salt-master |
/etc/salt/minion | Configuration file for salt-minion |
/etc/salt/master.d | Configuration directory for salt-master |
/etc/salt/minion.d | Configuration directory for salt-minion |
/etc/salt/minion_id | Stores id generated by salt for minion |
/etc/salt/pki/minion | Stores SSL Keys for minion |
/etc/salt/pki/master | Stores SSL Keys for master and connected minions |
Installing Salt:
Easiest way to install salt is using bootstrap script.
wget -O bootstrap-salt.sh https://bootstrap.saltstack.com sudo sh bootstrap-salt.sh -M stable (It will install salt-master and salt-minion) sudo sh bootstrap-salt.sh stable (It will install salt-minion)
You will get other ways to install salt on https://docs.saltstack.com/en/latest/topics/installation/
Setting up Environment:
File Roots:
- Root location where State / SLS files are stored.
- We can set it up as per our environments such as dev, stage, prod
Configuring file_roots:
file_roots: base: - /opt/salt/base
Pillar Roots:
- Root location where Pillar files are stored
- Similar like File Roots, we can setup pillar roots as per environments such as dev, stage, prod
pillar_roots: base: - /opt/pillar/base
Notes:
- In above example we have defined “base” environment in salt and configured location of state files and pillar.
- Best practice is to configure these parameters in separate file in
/etc/salt/master.d/file_roots.conf and pillar_roots.conf. For this we need to uncomment “default_include: master.d/*.conf” inside /etc/salt/master. - Whenever we use saltenv=base, it will check for state file in /opt/salt/base and pillar information in /opt/pillar/base.Ports: By default salt uses 4505 and 4506.
We can define these ports inside /etc/salt/master.
Restart salt-master
Configure salt-minion
Provide minion id in /etc/salt/minion_id. By default hostname of minion is stored in it.
Provide master name in /etc/salt/minion or /etc/salt/minion.d/master
master: salt-master
Note: Make sure Salt-master is reachable using hostname from Minion machine.
Restart salt-minion
Now salt-minion will request salt-master to accept key.
On Salt Master Check salt keys:
$ salt-key Accepted Keys: Denied Keys: Unaccepted Keys: minionID ====>; Minion id provided in /etc/salt/minion_id Rejected Keys:
Accept Salt-key:
$ salt-key -a minionID $ salt-key Accepted Keys: minionID Denied Keys: Unaccepted Keys: Rejected Keys:
Delete Salt-key:
$ salt-key -d minionID
Basic Ping Test from salt-master:
$ salt minionID test.ping minionID: True
Salt Modules:
- Salt has 2 types of modules: Execution Modules and State Modules.
- Salt Modules are written in Python
- Location of Modules: /usr/lib/python2.7/dist-packages/salt
Execution Modules:
- Execution Modules are executed on Command line. Such as in above example we used test.ping
- Formulation of commands modules:
salt <target> <module.function> <argument>
In above eg. target is minionID, module is test and ping is function from that module.
- Location: /usr/lib/python2.7/dist-packages/salt/modules
For eg. Sysctl Execution module
- Location is /usr/lib/python2.7/dist-packages/salt/modules/linux_sysctl.py
- Using sysctl Execution Module:
$ salt '*' sysctl.show $ salt '*' sysctl.assign vm.swappiness 20
More Examples of Execution Modules:
$ salt '*' user.add fred shell=/bin/zsh $ salt '*' network.connect google-public-dns-a.google.com port=53 proto=udp timeout=3 $ salt '*' cp.get_file salt://vimrc /etc/vimrc gzip=5 $ salt ns1 pkg.install pkgs=['bind9','bind9-docs','bind-utils'] $ salt '*' pkg.install sources='[{"foo": "salt://foo.deb"},{"bar": "salt://bar.deb"}]’
State Modules:
- State Modules are executed using State files.
- Location: /usr/lib/python2.7/dist-packages/salt/states
For eg. Sysctl state module
- Location is /usr/lib/python2.7/dist-packages/salt/states/sysctl.py
Create State file sysctl.sls:
change_swappiness: sysctl.present: - name: vm.swappiness - value: 30
Apply state using:
$ salt '*' state.apply sysctl
Note: Many times salt uses Execution Modules inside State Modules.
More examples of State Modules:
Add user:
user.present: - name: fred - shell: /bin/zsh
Install bind packages:
pkg.installed: - pkgs: - bind9 - bind9-docs - bind-utils
Install some packages using other sources:
pkg.installed: - name: mypkgs - sources: - foo: salt://foo.deb - bar: http://somesite.org/bar.deb
More Command line examples:
Run a command:
$ salt '*' cmd.run 'ls -l /etc'
Check Disk Usage:
$ salt '*' disk.usage
Install a Package:
$ salt '*' pkg.install cowsay
List Network Interfaces:
$ salt '*' network.interfaces
Select Target as per OS:
$ salt -G 'os:Ubuntu' test.ping
Select Target as per Minion ID:
$ salt 'minionID' disk.usage
Select Targets using Regular Expressions:
$ salt -E 'minion[0-9]' test.ping
Select Targets as list:
$ salt -L 'minion1,minion2' test.ping
Select Multiple targets in one command:
$ salt -C 'G@os:Ubuntu and minion* or S@192.168.0.*' test.ping
Writing & applying first state file or formula:
- We will install gpm and curl using state file.
- As per above configuration our base environment is configured.
- File root is configured under /opt/salt/base
- Create first state file name “first.sls” under /opt/salt/base
$ vi /opt/salt/base/first.sls install_packages: pkg.installed: - pkgs: - gpm - curl
We can apply particular state using “state.sls”. Here “state” is Execution Module and “sls” is function inside that.
When we apply state on particular file, it will check that file into file_roots of that environment.
So to apply above state, we need to run:
$ salt minionID state.sls first
Notes: Do not add sls extension.
If first.sls is inside /opt/salt/base/install/, then command will be ==> salt minionID state.sls install.first
Top File
- The Top file is used to apply multiple state files to your Salt minions during a highstate.
- The states that are applied to each system are determined by the targets that are specified in the Top file.
- A highstate causes all targeted minions to download the /srv/salt/top.sls file and find any matching targets.
- If a matching target is found, the minion applies all of the states listed under that target.
- Many users schedule highstate runs at regular intervals to ensure that systems remain in compliance.
- Top file is used to apply state as per the type of server such as Webserver, db Server, Common for all, etc.
For eg. Top file can be like
base: '*': - vim - users - scripts '*web*': - apache - python '*db*': - mysql
Above top file will apply vim, users, scripts states to all Minions and apache, python to web servers and mysql to db servers.
Note: Do not use TAB, use Space in any SLS file as it is YAML, it will throw an error in log file saying illegal tab character.
Top file example:
Create a Top file /opt/salt/base/top.sls and add below lines:
base: '*': - common 'minionID': - apache
Create /opt/salt/base/common.sls and add below lines:
install_common_packages: pkg.installed: - pkgs: - vim - gpm
Create /opt/salt/base/apache.sls and add below lines:
install_apache: pkg.installed: - name: apache2
Apply State:
$ salt '*' state.apply …. Summary for minion1 ------------ Succeeded: 2 (changed=2) Failed: 0 ------------ Total states run: 2 Total run time: 91.590 s
Note: If you have a large number of connected minions, you might want to limit how many systems are updated at once. You can do this using the –batch-size option:
$ salt --batch-size 10 '*' state.apply
Understanding Salt State:
Format of Salt State declaration. It uses YAML.
State_ID: –> String that describes this state. Must be Unique
module.function: –> State Module and Function to call
– name: name –> Arguments: Every function takes ‘name’ as the first arg.
– argument: value
– arguments: –> Other arguments are listed under the function.
– value1
– value2
Examples of States:
Create a Directory:
create my_new_directory: file.directory: - name: /opt/my_new_directory - user: root - group: root - mode: 755
Configure service running:
is_mysql_running: service.running: - name: mysql
Configure service running during boot:
is mysql enable at boot: service.running: - name: mysql - enable: True
Download git repo:
Salt uses State ID for the value of name. In below example name parameter is
“https://github.com/….” URL
https://github.com/saltstack/salt-bootstrap:
git.latest: - rev: develop - target: /tmp/salt
We also can write like this:
Clone the SaltStack bootstrap script repo:
pkg.installed: - name: git # make sure git is installed first! git.latest: - name: https://github.com/saltstack/salt-bootstrap - rev: develop - target: /tmp/salt
Add A User:
user account for xyz: user.present: - name: xyz - shell: /bin/bash - home: /home/xyz - groups: - sudo
An entry to /etc/hosts file:
myserver in hosts file: host.present: - name: myserver - ip: 192.168.0.42
Call an execution function:
restart vsftpd: module.run: - name: service.restart - m_name: vsftpd ==> # m_name gets passed to the execution module as "name"
Dry Run State:
test=True
Salt state functions provide a mechanism to display the changes that will be made during a live run. The return info will show states that will be applied in yellow and the result is reported as None.
$ salt 'minionID' state.apply test=True
init.sls:
If target a directory during a state.apply or in the state Top file, salt looks for an init.sls file in that directory and applies it.
Grains:
List all grains available for specific minion
$ salt minionID grains.ls
Get Grains with values using
$ salt minionID grains.items
Get value of specific Grain item
$ salt minionID grains.get os
Set Grain item role with value webserver
$ salt minionID grains.set 'role:webserver'
We also can set Grain items and values in /etc/salt/grains on minion.
Pillar:
List all pillar values for specific minion:
$ salt minionID pillar.ls
Configure Pillar values:
Create /opt/pillar/base/top.sls and add below lines:
base: '*': - common
Create /opt/pillar/base/common.sls and add below lines:
users: - ramesh: 1001
Refresh Pillars on Minion:
$ salt '*' saltutil.refresh_pillar
Git Pillar items:
$ salt minionID pillar.items
Git Value of Pillar items:
$ salt '*' pillar.get users
Using Pillar in State file with the help of Jinja2:
{% for user, uid in pillar.get('users', {}).items() %} {{user}}: user.present: - uid: {{uid}} {% endfor %}
This state will add user with defined UID in Pillar.
We also can use Grains to define values in Pillar. For eg. setup below values in common.sls
{% if grains['os_family'] == 'RedHat' %} apache: httpd git: git {% elif grains['os_family'] == 'Debian' %} apache: apache2 git: git-core {% endif %}
And in State file use:
install apache: pkg.installed: - name: {{ pillar['apache'] }}
Managing Files and Folders using Salt:
salt:// URL followed by path to the file relative to the srv/salt
Using file.managed:
deploy http.conf file: file.managed: - name: /etc/http/conf/http.conf - source: salt://apache/http.conf
In above example “salt://apache/http.conf ” is “/opt/salt/base/apache/http.conf”
Use file.append:
Insert new line we want to add to the config file.
update lftp conf: file.append: - name: /etc/lftp.conf - text: set net:limit-rate 100000:500000
Salt is very flexible and faster Configuration Management Tool. Which can be used by many ways.
Hope this note will help us to understand salt basics.
Do let me know your suggestions, questions on ngurjar [at] neeleshgurjar [dot] co [dot] in
Neelesh, quite informative.