Ansible is an open source configuration management and orchestration utility. It can automate and standardize the configuration of remote hosts and virtual machines. Its orchestration functionality allows Ansible to coordinate the launch and graceful shutdown of multitiered applications. Because of this, Ansible can perform rolling updates of multiple systems in a way that results in zero downtime.
Instead of writing custom, individualized scripts, system administrators create high-level plays in Ansible. A play performs a series of tasks on the host, or group of hosts, specified in the play. A file that contains one or more plays is called a playbook. Ansible’s architecture is agentless. Work is pushed to remote hosts when Ansible executes. Modules are the programs that perform the actual work of the tasks of a play. Ansible is immediately useful because it comes with hundreds of core modules that perform useful system administrative work.
Inventories
- An inventory is a list of hosts that Ansible manages
- Inventory location may be specified as follows:
- Default:
/etc/ansible/hosts
- Specified by CLI:
ansible -i <filename>
- Can be set in
ansible.cfg
- Default:
- The inventory file may contain hosts, patterns, groups, and variables
- You may specify the inventory as a directory containing a series of inventory files (both static and dynamic)
- The inventory may be specified in YAML or INI format
- Can be static or dynamic
Default inventory file
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
[root@controlnode ~]# cat /etc/ansible/hosts # This is the default ansible 'hosts' file. # # It should live in /etc/ansible/hosts # # - Comments begin with the '#' character # - Blank lines are ignored # - Groups of hosts are delimited by [header] elements # - You can enter hostnames or ip addresses # - A hostname/ip can be a member of multiple groups # Ex 1: Ungrouped hosts, specify before any group headers. ## green.example.com ## blue.example.com ## 192.168.100.1 ## 192.168.100.10 # Ex 2: A collection of hosts belonging to the 'webservers' group ## [webservers] ## alpha.example.org ## beta.example.org ## 192.168.1.100 ## 192.168.1.110 # If you have multiple hosts following a pattern you can specify # them like this: ## www[001:006].example.com # Ex 3: A collection of database servers in the 'dbservers' group ## [dbservers] ## ## db01.intranet.mydomain.net ## db02.intranet.mydomain.net ## 10.25.1.56 ## 10.25.1.57 # Here's another example of host ranges, this time there are no # leading 0s: ## db-[99:101]-node.example.com |
Default host inventory defines two host groups, webservers and
db-servers.
Consider such an example:
1 2 3 4 5 6 7 8 9 |
[webservers] localhost ansible_connection=local web1.example.com web2.example.com:1234 ansible_connection=ssh ansible_user=ftaylor 192.168.3.7 [db-servers] web1.example.com db1.example.com |
Host entries can also define how Ansible communicates with the managed host, including transport and user account information. In the previous example, SSH on web2.example.com
is configured to listen on a non-standard port, port 1234
. The account Ansible should use to log into that host is ftaylor
.
Variables and Inventories
- Ansible recommends that variables not be defined in inventory files:
- Should be stored in YAML files located relative to inventory file
- group_vars
- host_vars
- Files named by host or group and may end in yml or yaml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
[miro@controlnode ansible]$ cat inventory maile.example.com [httpd] httpd1.example.com httpd2.example.com [miro@controlnode ansible]$ ls -lR .: razem 4 drwxrwxr-x. 2 miro miro 19 01-06 23:45 group_vars drwxrwxr-x. 2 miro miro 32 01-06 23:45 host_vars -rw-rw-r--. 1 miro miro 66 01-06 23:44 inventory ./group_vars: razem 4 -rw-rw-r--. 1 miro miro 16 01-06 23:45 httpd ./host_vars: razem 4 -rw-rw-r--. 1 miro miro 14 01-06 23:45 httpd1.example.com [miro@controlnode ansible]$ cat group_vars/httpd http_port: 8080 [miro@controlnode ansible]$ cat host_vars/httpd1.example.com opt_dir: /opt |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
[root@controlnode ansible]# ll razem 4 drwxrwxr-x. 2 miro miro 37 01-10 21:19 group_vars drwxrwxr-x. 2 miro miro 64 01-10 22:30 host_vars -rw-rw-r--. 1 miro miro 116 01-10 22:24 inventory [root@controlnode ansible]# cat inventory managedhost1 ansible_host=managedhost1.example.com [labservers] managedhost1.example.com [root@controlnode ansible]# cat host_vars/managedhost1.example.com opt_dir: /opt [root@controlnode ansible]# ansible managedhost1.example.com -i inventory -a "ls -l {{opt_dir}}" managedhost1.example.com | SUCCESS | rc=0 >> razem 0 -rw-r--r--. 1 root root 0 01-10 22:42 file1 -rw-r--r--. 1 root root 0 01-10 22:42 file2 [root@controlnode ansible]# cat group_vars/labservers logs : /var/log/messages [root@controlnode ansible]# ansible managedhost1.example.com -i inventory -b -a "tail {{logs}}" managedhost1.example.com | SUCCESS | rc=0 >> Jan 10 22:44:03 managedhost1 systemd-logind: Removed session 106. Jan 10 23:01:01 managedhost1 systemd: Started Session 108 of user root. Jan 10 23:02:10 managedhost1 systemd: Started Session 109 of user root. Jan 10 23:02:10 managedhost1 systemd-logind: New session 109 of user root. Jan 10 23:02:10 managedhost1 ansible-command: Invoked with warn=True executable=None _uses_shell=False _raw_params=ls -l /opt removes=None creates=None chdir=None stdin=None Jan 10 23:03:10 managedhost1 systemd-logind: Removed session 109. Jan 10 23:04:25 managedhost1 systemd: Started Session 110 of user root. Jan 10 23:04:25 managedhost1 systemd-logind: New session 110 of user root. Jan 10 23:04:26 managedhost1 ansible-command: Invoked with warn=True executable=None _uses_shell=False _raw_params=tail /opt removes=None creates=None chdir=None stdin=None Jan 10 23:04:37 managedhost1 ansible-command: Invoked with warn=True executable=None _uses_shell=False _raw_params=tail /var/log/messages removes=None creates=None chdir=None stdin=None |
YAML vs INI
YAML
INI
Static & Dynamic Inventories
Static:
- INI or YAML format
- Maintained by hand
- Easy to manage for static configuration
Dynamic:
- Executable (bash script, python script, etc.)
- Script returns JSON containing inventory information
- Good for use with cloud resources subject to sudden change
On Dynamic Inventories
- Specifying an executable file as the inventory is considered a dynamic inventory
- JSON output is expected to be returned to STDOUT from the executable
- The implementation (python, java, C, bash, etc) does not matter as long as the program can run on the control host and behaves as Ansible expects
- The program/script must respond to two possible parameters:
- –list
- –host [hostname]
- The program script must return JSON in the format Ansible is expecting
- Do not forget to make the file executable:
chmod +x dynamic.py
- Using dynamic inventories, you can pull inventory information from the likes of:
- A cloud provider
- LDAP
- Cobbler
- Other CMDB software