Exploring Ansible

At the behest of a friend in the DevOps community in Boston, I’ve been trying to give Ansible a go.  In thinking about this, I’ve also realized that I’ve stumbled across a few problematic areas in getting a basic Ansible setup that I hope to help others avoid by documenting them here.

First and foremost: I’m not a developer by any means.  I’m a glorified Systems Administrator by-day and a first-responder to outages generated from the aforementioned systems during the weekends.  What I’ve come to realize over time is that in order for me to progress at all, I need a better understanding of how more modern, dynamic services, APIs, and the assorted building blocks of the modern service-oriented web work.

The way I chose to go about this initial bit of discovery is pretty straightforward: I’m using a Vagrantfile to talk to DigitalOcean and kick off a droplet, and then I am using that droplet as a target for some test Ansible commands.  There are probably much easier (and frankly, more interesting) ways to do this, but this is what I know so I’m starting here.

First thing I did was get a directory set-up for this little test:

mkdir -p ~/ansible
cd !$

Vagrantfiles are pretty easy to grok and maintain.  If you can read and follow along with basic Ruby syntax, you’ll be able to modify what you need.  I started by initializing the Vagrantfile:

vagrant init

Once that completed, I had a directory structure that looks similar to this:

14:15:15-thomas-jamesgoin~/ansible$ ls -lah
total 32
drwxr-xr-x 6 thomas-jamesgoin staff 204B Apr 26 14:09 .
drwxr-xr-x@ 76 thomas-jamesgoin staff 2.5K Apr 26 14:09 ..
drwxr-xr-x 3 thomas-jamesgoin staff 102B Feb 14 22:12 .vagrant
-rw-r--r-- 1 thomas-jamesgoin staff 4.1K Mar 13 11:40 Vagrantfile

And then came the fun part: figuring out how to interact with DigitalOcean’s API.  From my current job, I have a pretty basic understanding of how tokens, APIs, and API keys worked, so I started looking around for documentation on how I could talk to DO without doing the GUI thing.  I stumbled upon the Vagrant plugin vagrant-digitalocean, which thankfully only requires a quick Vagrant CLI command to install:

vagrant plugin install vagrant-digitalocean

After that, I located docs on How To Use the DigitalOcean API v2, which made it easy for me to get a token and talk to the API.

Point of note: the way that I’m doing this operates on the assumption that I have a separate SSH key pair for use with DigitalOcean. This is not only good security practice, but also a great way to protect your primary SSH key pair. There’s plenty of documentation on how to generate an SSH key pair on the internet, so I’m not going to cover it here.

Using the docs on the GitHub page for the vagrant-digitalocean plugin under Configuration, my Vagrantfile looked something like this (I had to prune commented lines out of the below example due to character limits in blocks with hosted WordPress):

# -*- mode: ruby -*-
# vi: set ft=ruby :

Vagrant.configure(2) do |config|
  config.vm.box = "digital_ocean"
  config.vm.network "public_network"
  config.vm.hostname = 'dropletname.example.com'
  config.vm.provider :digital_ocean do |provider, override|
    override.ssh.private_key_path = '~/.ssh/digitalocean_vagrant'
    override.vm.box = 'digital_ocean'
    override.vm.box_url = "https://github.com/smdahlen/vagrant-digitalocean/raw/master/box/digital_ocean.box"

    provider.token = '(TOKEN)'
    provider.image = 'ubuntu-14-04-x64'
    provider.region = 'nyc2'
    provider.size = '512mb'
  end
end

Testing this was simple:

$ vagrant up
Bringing machine 'default' up with 'digital_ocean' provider...
==> default: Using existing SSH key: Vagrant
==> default: Creating a new droplet...
==> default: Assigned IP address: (REDACTED)
==> default: Rsyncing folder: /Users/thomas-jamesgoin/ansible/ => /vagrant...

And voila! A working DigitalOcean droplet instantiated from Vagrant!

So that was the more interesting part. Ansible installation and execution itself was the far more pedestrian effort (not sure why it asks for
sudo, but whatever).

$ sudo pip install ansible

Once that was completed, I took the IP address in the output of the vagrant up command and added it to a hosts file in my project directory. My directory structure now looked like this:

14:30:48-thomas-jamesgoin~/ansible$ ls -lah
total 24
drwxr-xr-x   6 thomas-jamesgoin  staff   204B Apr 26 14:24 .
drwxr-xr-x@ 76 thomas-jamesgoin  staff   2.5K Apr 26 14:24 ..
drwxr-xr-x   3 thomas-jamesgoin  staff   102B Feb 14 22:12 .vagrant
-rw-r--r--   1 thomas-jamesgoin  staff   3.8K Apr 26 14:24 Vagrantfile
-rw-r--r--   1 thomas-jamesgoin  staff    15B Apr 26 14:02 hosts

However, I had another problem: Ansible defaults to reading /etc/ansible/hosts, which isn’t really convenient for folks on OSX, so I added this to my ~/.bash_profile file:

###
# Ansible stuff
###
export ANSIBLE_HOST_KEY_CHECKING=False
export ANSIBLE_HOSTS=/Users/thomas-jamesgoin/ansible/hosts

Now I was ready to test an ad-hoc ansible command:

14:40:35-thomas-jamesgoin~/ansible$ ansible all -m ping -u root --private-key=~/.ssh/digitalocean_vagrant
(REDACTED) | SUCCESS => {
    "changed": false,
    "ping": "pong"
}

I’d discovered that with the way DigitalOcean currently provisions droplets, you unfortunately use -u root to run anything as the droplet has no user-accounts installed by default. There’s likely ways to ensure this is the case via Vagrant, which I’ll probably end-up investigating later. Similarly, --private-key= was required here because I haven’t quite figured out how ssh agent forwarding works in this whole setup… but at least I’m a few steps ahead of where I was when I started.

The next few steps I’ll be working on is provisioning a non-root user as part of the Vagrant bootstrap process, figuring out how to boot multiple droplets from the Vagrantfile, and how to do a simple app deployment. More to follow!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s