Taking the effort out of server configuration using Ansible
This article was originally published in the NorDevCon 2016 conference programme.
Ansible is an IT automation tool that is growing in popularity. It is ideally suited for configuration management, i.e. automating the configuration of your development and production infrastructure.
Ansible is a relatively new addition to the “DevOps” arena (first released in 2012) and it has quite a different philosophy to some of the more well established players in the field. Most notably, it is “agent-less”; i.e. there is no need to have an “agent” pulling updates from a “master” configuration manager.
Ansible has been designed to be easy to use and it achieves this through two aspects of its architecture:
- It uses a push based method to interact with the hosts (the machines to be configured)
- It uses OpenSSH as its authentication method
What this means in practise is that you can install Ansible on your laptop and
as long as you have setup password-less ssh
to the machines you are wanting
to interact with you are ready to go. In other words no master, no databases,
no services; no fighting the system that is meant to be making your life
easier!
Listing your inventory
Ansible has the concept of an inventory where you list all of the hosts that
you want to be able to interact with through Ansible. The inventory is a plain
text file using an INI-like format. The default path to the inventory file is
/etc/ansible/hosts
. However, you can provide an alternative path as a
command line argument using the -i
option.
Below is an example hosts
file that groups three web servers into a
webservers
group.
[webservers]
web1.example.com
web2.example.com
web3.example.com
It is also possible to create aliases and specify host specific variables. Below is an example of an alias to enable Ansible to communicate with a Vagrant generated virtual machine.
testserver ansible_ssh_host=127.0.0.1 ansible_ssh_port=2222 ansible_ssh_user=vagrant ansible_ssh_private_key_file=.vagrant/machines/default/virtualbox/private_key ansible_sudo=yes
Interacting with Ansible
There are two different ways of interacting with ansible: ad-hoc commands and playbooks. Ad-hoc commands are useful for quick tasks that you don’t want to save for later. Whereas playbooks provides a means to specify reproducible configuration recipes.
Ad-hoc commands are accessed using the ansible
program and can be useful if
you want to do something quickly. For example, suppose that there was a
critical security patch for bash that you needed to apply to all your
webservers rapidly.
ansible webservers -m apt -a "name=bash state=latest update_cache=yes"
There are a few things to note in the command above. The first argument
(webservers
) is the host group defined in the inventory. The -m apt
option states that we want to use Ansible’s apt
module, in other words our
servers are running on a Debian based OS such as Ubuntu. Finally, the -a ...
option specifies the arguments to supply, i.e. we want to install the latest
version of bash
.
It is worth noting that Ansible does not try to abstract away the layer of
package management. As such there are separate modules for apt
, yum
,
homebrew
, etc. This is useful in that the functionality of Ansible modules
are not limited by the constraint of a set of common features. For example in
this case we make use of the update_cache
option to run the equivalent of
apt-get update
before the we try to install the latest version of bash.
Batteries included as Ansible modules
Ansible comes with a large number of built-in modules for configuring your systems. These include modules for package management, performing systems administration tasks, working with files, interacting with source control programs, and much more.
Reproducible configuration scripts using playbooks
Ansible playbooks allow you to create reproducible recipes for configuring your servers. Playbooks are written in YAML and are meant to be human readable. As YAML is simply a data serialisation language, a playbook can be thought of as “infrastructure as data”.
Below is a basic playbook for configuring a firewall using firewalld
. In
real life a playbook would be written to configuration the entire system.
---
- name: configure a web server firewall using firewalld
hosts: testserver
tasks:
- name: install firewalld
apt: name=firewalld state=present
- name: ensure that firewalld is started and enable at boot
service: name=firewalld enabled=yes state=started
- name: open up port 80 for tcp
firewalld: port=80/tcp permanent=yes state=enabled
notify: restart firewalld
handlers:
- name: restart firewalld
service: name=firewalld state=restarted
There are a few things to note in the playbook above. The host(s) that the
playbook is defined to be applied to are defined in the hosts
entry. In
this case it is only run against the Vagrant testserver
alias we defined in
the inventory earlier. The apt
module is used to install firewalld
and
the service
module is used to ensure that firewalld
is started and
enabled at boot. Finally, we use Ansible’s firewalld
module to open up port
- Note that this task makes use of the
notify
action to trigger therestart firewalld
handler, which we define at the end of the playbook.
What now?
There is much more to Ansible than what has been outlined here. The key is to build things up bit by bit. You don’t need to use every feature of Ansible to get a job done.
For more information about Ansible have a look at the Ansible documentaiton. If you liked this article you may also be interested in the other Ansible tutorials on this site, which illustrate the use of Ansible as a tool to install scientific software.