22 Nov 2022
Ansible is an open sourceIT automation tool that automates provisioning, configuration management, application deployment, orchestration, and many other manual IT processes.
Ansible can be used to automate the installation of software, automate daily tasks, provision infrastructure, improve security and compliance, patch systems, and share automation across the entire organization using SSH.
To install Ansible onto MacOS, we’ll be using Homebrew
brew install ansible
Verify the installation with the version command ansible --version
.
ansible --version
ansible [core 2.13.4]
To install Ansible onto a Debian based family, you can use the built-in repository.
sudo apt install ansible
Verify the installation.
ansible --version
Ansible uses a file called “inventory” to store the computers (nodes) that can connect too and manage.
Inventory files can be formatted in INI
or YAML
.
A simple example of this shows two groups of servers called “groupname” and “group2” in an INI
format.
[groupname]
192.168.1.10
192.168.1.11
[group2]
myserver.home.lan
192.168.1.12
In YAML this would look like:
groupname:
hosts:
192.168.1.10:
192.168.1.11:
group2:
hosts:
myserver.home.lan:
192.168.1.12:
We can list all hosts within an inventory file using issuing the command
ansible-inventory -i path\to\inventory --list
Ansible has some default groups, they are all
and ungrouped
, in addition we can create children groups, as shown in the example below.
This creates a group called “myapp”, which contains the groups “app” and “db”.
[app]
192.168.1.10
192.168.1.11
[db]
192.168.1.12
[myapp:children]
app
db
In YAML this would look like:
myapp:
app:
hosts:
192.168.1.10:
192.168.1.11:
db:
hosts:
192.168.1.12:
Variables can be added to the inventory file, such as specific user per node, as shown in the example below:
[groupname]
192.168.1.10 ansible_user=admin
In YAML this would look like:
groupname:
hosts:
192.168.1.10:
ansible_user: admin
Another simple, but effective use case are Alias’:
[groupname]
server1 ansible_host=192.168.1.10
In YAML this would look like:
groupname:
server1:
ansible_host: 192.168.1.10
Variables can be created for the whole group including parent groups, as shown in the example below
[groupname]
192.168.1.10
192.168.1.11
[groupname:vars]
ansible_user=admin
In YAML this would look like:
groupname:
hosts:
192.168.1.10:
192.168.1.11:
vars:
ansible_user: admin
The last option I want to mention is the use of ranges for nodes, for example:
[groupname]
192.168.1.[10:11]
In YAML this would look like:
groupname:
hosts:
192.168.1.[10:11]
This can be used for FQDNs as well, including alphabetric ranges
groupname:
hosts:
www[01:10].example.com
groupname:
hosts:
db-[a:d].example.com
When connecting to hosts Ansible will use SSH authorised keys. To generate a SSH authorised key follow these steps:
ssh-keygen
.ssh-copy-id [email protected]
Passwords can still be used with either the switch -k
or --ask-pass
, but is not the recommended approach for servers, but can be useful for communicating with network devices such as switches.
Now we can execute our first Ansible command.
Note: Python must be installed on the node.
The example Ansible command below uses the inventory file, combined with a groupname to identify which computers to target for the module ping command.
The -u
switch must be used if the username is different that the Ansible host, or this can be configured within the inventory file.
ansible -i pathto\inventory groupname -m ping -u admin
Another useful module is setup
, this retrieves all the information Ansible can about the host.
ansible -i pathto\inventory groupname -m setup -u admin
To run ad-hoc commands you can remove the -m
module switch, use the -a
, argument switch. Ansible by default will use the -m command
module if none is specified.
In the example below we are issuing the command free -h
, which returns available memory of the nodes.
ansible -i pathto\inventory group -a "free -h" -u admin
This is the same as running:
ansible -i pathto\inventory group -m command -a "free -h" -u admin
Note: By default, Ansible connects to 5 systems at a time in parallel, these are called forks. Forks can be modified by changing the Strategy.
Ansible configuration files can be used to create overrides to the default value. A simple example of this could be using the current directory inventory file, removing the requirement of including the inventory file path in our commands:
touch ansible.cfg
[defaults]
INVENTORY = inventory.yml
A full list of Ansible configurations can be found on the Ansible Configuration Settings page.
There may be cases where you’ll need to limit the command to a host.
To limit, which nodes are affected you can use
ansible -i pathto\inventory --limit "db"
To exclude, or negate limit, this will apply the command to all except “db”.
ansible -i pathto\inventory all --limit 'all:!db'
To run tasks asynchronously by keeping the connection open on the node until completion. This will run the task in the background.
The example below uses -b
to “become” administrator, as this is a requirement of apt upgrade -y
. Become can be turn on or off for globally or for a particular task if required.
The arguments required for asynchronous tasks are -B
for Background, with a time in seconds before termination. The -P
argument is for Polling.
ansible -i pathto\inventory group -b -B 3600 -P 0 -a "apt upgrade -y"
To check the progress of a job you’ll need the “ansible_job_id” that is provided when you run the above command.
ansible -i pathto\inventory group -m async_status -a "jid=290649113753.244308"
YAML files start with a ---
, this indicates the beginning of the YAML document called front matter, you can also end the document using ...
at the end.
---
- name: Playbook Name
hosts: groupname
# become admin for all tasks
become: true
tasks:
- name: Install apache
# use package: for cross-platform
apt:
name: apache2
state: present
- name: Copy configuration files
copy:
src: "example.com.conf"
dest: "/etc/apache2/sites-available/example.com.conf"
owner: www-data
group: www-data
# mode: u=rwx,g=rx,o=r
mode: 0754
- name: Is Apache Started
service:
name: httpd
state: started
# enabled: true
enabled: yes
It’s always worth running your YAML through a linter, such as YAML Lint.
To run the playbook, call the ansible-playbook
command with your inventory file and the playbook you wish to run.
ansible-playbook -i inventory main.yml
Using multiple links within YAML can be achieved through:
|
, which will include a newline and any trailing spaces.>
, which will fold a new line into a space.Examples include
include_newline: |
each new line
is a new line
folded_newline: >
a single line of text
shown with multiple lines
Variables can be contained within your main YAML, like in the example below.
---
- name: Playbook Name
hosts: groupname
vars:
proxy_vars:
http_proxy: http://proxy:80/
https_proxy: https://proxy:443/
These variables can then be used per task.
---
- name: Playbook Name
hosts: groupname
vars:
proxy_vars:
http_proxy: http://proxy:80/
https_proxy: https://proxy:443/
tasks:
- name: Taskname
environment: proxy_vars
Variables can also be used with handlebars
---
- name: Playbook Name
hosts: groupname
vars:
package: httpd
tasks:
- name: Taskname
package:
name: ""
state: present
Variables can be included from another YAML file, as shown in the code below.
---
key: value
---
- name: Playbook Name
hosts: groupname
vars_files:
- vars.yml
To environment variables for all nodes within the playbook, you can configure at the top level
---
- name: Playbook Name
hosts: groupname
environment:
http_proxy: http://proxy:80/
https_proxy: https://proxy:443/
Lastly we can use information gathered from the “setup” module and use them as variables such as `ansible_os_family’.
Handlers run at the end of the playbook; a handler can call other handlers.
Handlers can be created then called only when a change is made on the node, for example restarting a service if the configuration has been changed.
The below handler is called via the notify
command.
To run the handlers as soon as possible using the meta: flush_handlers
task.
By default, handlers will not be actioned if the play fails, this can be override by using --force-handlers
on the Ansible command.
handlers:
- name: Restart apache
ansible.builtin.service:
name: apache
state: restarted
tasks:
- name: Change Config
ansible.builtin.template:
src: mysite.conf
dest: /etc/mysite.conf
notify: Restart apache
- name: flush handlers immediately
meta: flush_handlers
Commonly used modules to get started with:
service
apt
yum
package
get_url
unarchive
command
copy
debug
20