76design

Server Provisioning CentOS with Ansible

robots building robots

Robots Building Robots

Introduction

Ansible is a powerful tool for provisioning CentOS on commercial grade linux webservers. In my last article, Webmin Configuration on CentOS, I discussed the steps to setup a new server complete with Webmin and Percona. This is our preferred setup for reliable webservers, but one glance at the article will make it obvious that there are quite a few steps. Like any good programmer, I can’t stand repetition, hence seek to automate.

“Most of you are familiar with the virtues of a programmer. There are three, of course: laziness, impatience, and hubris.”

– Larry Wall

A process known as server provisioning will help us outfit a new machine with all the tools we want, automatically. There are many different tools that can be employed for doing this, and we have tried several. I’d like to write about the approach that we have converged on.

We find Ansible to be the simplest and therefore, most appealing for our purposes. Other approaches that we have used, like Chef, are very powerful, but equally configuration heavy – and more complex than we typically need for webservers.

Since my last article there is a new minor-version of CentOS available – CentOS 6.5. This new version alleviates the need for some of the caveats in my last article, but creates some new gotcha’s along the way.

Here I will provide a working Ansible playbook for provisioning a new:

I will also show you how I tested this on real hardware using DigitalOcean hardware – for pennies-on-the-droplet.

What’s the Point?

Before we get too mired in the technical details of automated server provisioning, why are we talking about this?

Previously we discussed the details involved with setting up a single server, this is useful, but of course, tedious. Automating this procedure means server deployment is:

So this is the point – improved Quality Assurance for both our clients and for us as developers. Additionally, we can use virtual servers to precisely mimic the production environments that our software will run on later, in real life. There are several advantages to this, but the main goal is to save time and money, while increasing site reliability.

So this allows us to create predictable environments in which to develop. Whether we’re building a simple WordPress website, or a beastly complicated Java Web Application like 76insights, we can mock the machine it will run on. This is great for development, given that our team members each develop on different operating systems. Also, and more critically, this reduces the number of variables between development and production environments.

Ansible

The idea from the last article was basically writing down some of the modifications that we usually make when building a new server. Roughly speaking, the overview of what we did from a new OS install can be listed:

Simple. But the article was much longer than that! Wouldn’t it be nice if we could just script the steps above and save that script so we could repeat, as needed?

That is precisely what Ansible does for us.

Some of the primary features of Ansible (and the ones that are important for us), are that it’s:

  1. streamlined and fast
  2. requires no node agent installation
  3. functions over SSH
  4. built on Python

The basic idea with the Ansible approach is to build playbooks. Simply enough, these playbooks contain plays, which are simply snippets that allow us to script the steps of the deployment tasks. These tasks are then ‘pushed’ onto the target machine(s) et voila, we produce exactly the results we want with a single command.

pro-tip: we present the Ansible scripts first, you can follow along on your own DigitalOcean droplet

Our First Playbook

In order to create our first playbook [the naïve but] quickest way is to literally just start scripting. The following snippet will actually perform all the steps we need to do to install Webmin on a fresh machine:

vim webmin.yml

---
- hosts: all
  user: root
  tasks:
  - name: ensure wget present
    yum: name=wget state=present
  - name: download virtualmin install script
    shell: wget http://software.virtualmin.com/gpl/scripts/install.sh creates=/root/install.sh
  - name: virtualmin install executable
    file: path=/root/install.sh mode=0755
  - name: virtualmin install (possibly ~15 mins)
    shell: ~/install.sh --yes chdir=/root
  - name: Virtualmin Post-Installation Wizard
    pause: prompt="virtualmin post-installation, https://{{inventory_hostname}}:10000"

vim hosts

[all]
ocean.76labs.com

Then we can easily run the playbook, and install webmin:

pro-tip: see how to setup ansible on a workstation

ansible-playbook -i hosts webmin.yml

Another of the attractive features of Ansible is the declarative syntax it uses. I find the script above very readable and easy to follow.

This is a great way to get started, but as you can imagine, this flat structure will quickly get out-of-hand as the ruleset starts to grow. To avoid this pitfall and indeed to follow Ansible Best Practices, next we will consider how to better structure our playbook for more complex tasks.

A More Advanced Layout

As our playbooks start to grow in complexity, we quickly want to start fractioning out the tasks in more digestible bits. This is where roles come in and we can start to layout our playbook according to best practices. We have built a playbook that will provision our server, by:

  1. install Webmin and Virtualmin
  2. install required yum-repositories
  3. replace MySQL with Percona
  4. upgrade to PHP 5.5

Here is the file-structure for the playbook:

.
├── site.yml
├── hosts
├── LICENSE
├── README.md
└── roles
    ├── percona
    │   ├── files
    │   │   └── my.cnf
    │   ├── handlers
    │   │   └── main.yml
    │   ├── meta
    │   │   └── main.yml
    │   └── tasks
    │       └── main.yml
    ├── php
    │   ├── meta
    │   │   └── main.yml
    │   └── tasks
    │       └── main.yml
    ├── webmin
    │   └── tasks
    │       └── main.yml
    └── yum-repos
        └── tasks
            └── main.yml

You will have to clone the github repo to see the playbook code. In the interest of pace, we have decided not to dissect the code here, hopefully you will find Ansible readable enough to self-document. As we explain below, it is simply a matter of checking out the above playbook and running it:

git clone https://github.com/burlresearch/ansible-webmin.git
cd ansible-webmin
ansible-playbook -i hosts site.yml

Assuming everything goes smoothly, you should have your server fully provisioned in a matter of minutes. This is the power of Ansible. By putting a bit of work into planning for the system we know we need, we can achieve all our goals, with ease:

  1. less expensive
  2. more reliable
  3. more predictable

Provisioning Cloud Servers

iWeb Cloud – Motivation

Recently we took part in the iWeb Cloud Βeta program in order to help evaluate their new cloud server offering. Became apparent that we needed a mechanism to quickly and easily generate servers with the software of our choice. Using Ansible gave us the opportunity to quickly generate and regenerate server nodes. Servers are no longer monolithic entities, but rather dispensable processing agents that simply run an operating system.

DigitalOcean – Live Testing the Scripts

No matter which choice you make for our cloud server provider, Ansible will work since it only requires an SSH connection. We chose DigitalOcean for testing the scripts on this article. Though iWeb would have been just as simple, it was more convenient for us to not to charge the corporate account in this instance. So here are the steps to get a DigialOcean Cloud Service running:

  1. Sign Up or Log In: to your DigitalOcean account: https://cloud.digitalocean.com/registrations/new
  2. Enter a Hostname: we use a subdomain we control, ocean.76labs.com, but you may simply use a hosts definition
  3. Select Size: Choosing at least 1GB/1CPU 30GB SSD DISK is recommended for MySQL with Apache
  4. Select Image: CentOS 6.5 x64
  5. optional Add SSH keys: if you have a key, else wait for the email to setup your root password on the new droplet
  6. Create Droplet

DigitalOcean interface for creating a new Droplet.

Congratulations, you have a new, LIVE server, for testing and deployment! If you’re concerned about the price, all the testing we did for this article ended up costing US $0.14 – money well spent :)

Ansible – Setup

I use a Ubuntu Linux workstation – so your mileage may vary depending on your operating system. For me, setting up Ansible was a matter of:

sudo add-apt-repository ppa:rquillo/ansible
sudo apt-get update
sudo apt-get install ansible

Then, it is simply a matter of checking out the Ansible scripts I have prepared on github and running the playbook (ensure the edit the hosts file specific to your server):

git clone https://github.com/burlresearch/ansible-webmin.git
vim hosts   # set your server IP
cd ansible-webmin
ansible-playbook -i hosts site.yml

Hopefully you can follow along with the on-screen instructions and in a few minutes, your new server should be completely configured!

TL;DR

In conclusion, we have outlined how to completely provision a new server with all the tools we require. We have done this using an Ansible playbook, with a little preparation, having minimized time and maximized reliability.

Previously we discussed the details involved with setting up a single server, manually. Here we introduced Ansible to automate that provisioning procedure.

In our next article we will discuss how to put all our developers on equal footing. We will discuss virtualization with Vagrant – how to precisely mimic a production environment, without any hardware…