Provisioning servers with Ansible

By Paul,

September 2016

Web Dev
Here at Toward, we’re always trying to find new ways of optimising and streamlining our workflow. One of the repetitive and laborious tasks that we find ourselves doing every project is setting up web hosting for our clients.

This can involve downloading and installing the necessary software on the server, setting up the directory structure for the website/app and creating databases for those websites powered by a CMS.

Wouldn’t it be nice if we could achieve all this using one command from the terminal? Step in Ansible!

What is Ansible?

Ansible is a radically simple IT automation engine that automates cloud provisioning, configuration management, application deployment, intra-service orchestration, and many other IT needs.

As you can see, Ansible covers a wide range of services, however in this article I’ll just be concentrating on the provisioning functionality it offers.

Provisioning

In simple terms, 'provisioning' just means setting up a server ready to accommodate whatever websites/web apps you wish to put on it. Historically, whenever we’ve set up hosting for a client we would have to SSH into the new server and then trawl through a long list of server commands to get it set up how we needed it.

Ansible seeks to simplify this process using files called Inventories and Playbooks.

Hold on to your face.

Crazy pug gif

Inventories

In Ansible, inventory files are where you specify the servers that you want to run your tasks on. This will usually be a list of your server IP addresses/domain names. These servers can be organised into groups. We can then use these group names in our playbooks to specify which servers we want to run our tasks on.

Take the following example:

[webservers]
foo.example.com
192.100.178.111
 
[dbservers]
bar.example.com
Another.example.com

This inventory file has two groups of servers: webservers and dbservers. We can use either of these groups in our playbooks and the tasks in that playbook will be run on all servers in that group.

Playbooks

A playbook is a YAML file contains a set of tasks that you want to run on the server. When you run the playbook from the command line it will go through the tasks, in sequence, and execute them one by one.

Here’s an example playbook called example.yml:

---
- hosts: webservers
  remote_user: root

- name: move folder from one location to another
  command: mv sitefolder /var/www/sitefolder

- name: enable php5 mcrypt php module
  command: php5enmod mcrypt

If we were to run the following in the command line on our local machine...

ansible-playbook example.yml

Ansible would run all the tasks in the example.yml playbook on the webserversgroup in our inventory. This would result in the following changes on the servers:

  1. The sitefolder directory getting moved to the /var/www directory
  2. The php5 mcrypt module getting enabled

As you can see, each task in the playbook has a name and a command. The name contains a brief description of the task, whilst the command contains the actual command that gets executed on the server.

This is a great improvement to our workflow already, but at the moment we still have to specify the exact server commands that we want to run. Luckily Ansible ships with a set of modules that allow us to specify tasks in a more concise and readable fashion.

Modules

Let’s take an example of how modules can simplify how we write tasks. Let’s say we have a playbook called example2.yml that simply creates a directory on the server, sets the owner of that directory to a particular user and then modifies the permissions of that directory.

Using the command functionality that we used in our first example, our playbook would look like this:

---
- name: create directory
  command: mkdir exampledir
 
- name: set directory owner
  command: chown joebloggs:admin exampledir
 
- name: set directory permissions
  command: chmod 2775 exampledir

As you can see, whilst still reasonably concise, we needed three tasks to achieve what we need. However, if we use the file module that comes with Ansible, we simply need the following:

---
- name: create directory with correct owner and permissions
  file: path=exampledir state=directory owner=joebloggs group=admin mode=2775

Here, we’ve substituted the command module with the file module which enables us to put everything we need on one line. The file module is one of Ansible’s core modules that allows us to create, delete and set attributes on files and directories on a server.

Ansible ships with hundreds of modules that cover many common server tasks such as setting up and managing databases, installing packages and deploying files from version control.

Crazy robot typing gif

Now that we’ve covered playbooks and modules, let’s quickly look at roles.

Roles

Let’s say, for example, that we have two different playbooks in our project, and both playbooks need to be able to create a database on our server. The way things currently are we would have to add the relevant tasks to both our playbooks and that doesn’t make for DRY code. This is where roles come in.

Roles allow us to organise our tasks in a way that makes it trivial to include them in multiple playbooks.

In basic terms, a role is just a directory that lives in the roles directory of the your Ansible project. Each role directory contains a set of other directories containing tasks, variables and templates relevant to that role.

For example, if we created a roles > database directory then we could just call that role into our playbook as follows:

---
- hosts: webservers
- roles:
  - database

We’re currently in the process of updating our provisioning and deployment strategies at Toward using Ansible. Once finished, we’ll be using it to take care of the following when setting up servers:

  • Creating user accounts
  • Adding SSH keys
  • Installing required packages
  • Enabling required php/apache modules
  • Setting up directory structure ready for deployments
  • Setting up virtual host configurations
  • Creating required databases
  • Downloading and installing Craft CMS (our CMS of choice)
  • Configuring and installing SSL certificates

We’re also in the process of replacing Capistrano with Ansible as our method of deploying our websites/apps. Since both technologies just rely on commands being run on the server over an SSH connection the swap over is fairly straightforward. We can also use Ansible to easily synchronise databases between remote servers and our local development environments.

This article just scratches the surface of what Ansible is capable of. If you’re finding yourself spending too much time setting up hosting for each new project then do yourself a favour and take a look!