Ansible
+
Eucalyptus

irving cordova

 

What is Eucalyptus?

  • An Amazon Web Services compatible private cloud
  • That implements Compute, Storage and Network virtualization & others
retrieved from: https://www.eucalyptus.com/eucalyptus-cloud/iaas

AWS Compatible?

  • Amazon API moves fast
  • Eucalyptus is always a bit behind
  • Private clouds even more so...

Running on Eucalyptus

a sample application

many moving parts

  • an application made of many different components
  • with complex configuration options
  • running in the cloud
retrieved from: http://arnoldit.com/wordpress/2012/03/01/datasift-architecture/

must run in multiple clouds

  • application must run in different clouds for different teams
  • each team wants multiple environments for testing  
retrieved from: http://www.dbta.com/Editorial/News-Flashes/IBM-Announces-Cloud-of-Clouds-Approach-to-Data-Migration-and-Storage-94054.aspx

We need automation!

Chef

  • Configuration management tool
  • Written in Ruby
  • With a Ruby DSL
  • And some inspiration from Puppet

Why Chef?

  • Ruby DSL was more powerful than some other alternatives
  • Order matters
  • Idempotent
  • Thin server

?

we were already familiar with it

bash "compile_redis_source" do
  cwd Chef::Config[:file_cache_path]
  code <<-EOH
    tar zxf redis.tar.gz
    cd antirez-redis-55479a7
    make && make install
  EOH
  creates "/usr/local/bin/redis-server"
end

service "redis" do
  provider Chef::Provider::Service::Upstart
  subscribes :restart, resources(:bash => "compile_redis_source")
  supports :restart => true, :start => true, :stop => true
end

template "redis.conf" do
  path "#{node[:redis][:dir]}/redis.conf"
  source "redis.conf.erb"
  owner "root"
  group "root"
  mode "0644"
  notifies :restart, resources(:service => "redis")
end
a sample chef recipe

What about all the moving parts?

we need orchestration!

the codification of a complete process

image and quote from: https://devcentral.f5.com/articles/wils-automation-versus-orchestration

Ironfan

An expressive toolset for constructing scalable, resilient architectures

  • Basically a Chef extension
  • Built by Infochimps
  • Allows to describe architecture in a DSL similar to Chef's recipes
  • EC2 Compatible
infochimps logo

Time to code

 

  • Ironfan implementation is successful
  • Application is deployed correctly
  • Runs in multiple environments with different configurations

But not everything is perfect...

  • Team must maintain a Chef server (thin server)
  • A different Chef server in each cloud
  • Recipes blow up with deep Ruby stack traces

Let's share with other teams!

image from: http://availagility.co.uk/2012/04/21/linking-flow-value-and-capability/multiple-teams-jpg/

my ruby version is not compatible!

what is rvm?

why is my modification to the recipe failing?

the Chef server died!

i think i messed up my ironfan config!

so i must push to chef server my modification?

i didn't do anything but my app reconfigured itself!

are there any other solutions out there?

simple to install

my ruby version is not compatible!

what is rvm?

i think i messed up my ironfan config!

server and agent less

the Chef server died!

so i must push to chef server my modification?

i didn't do anything but my app reconfigured itself!

how to make Ansible play nice with Eucalyptus?

step 1: 

can Ansible create servers in an Eucalyptus based clouds?

image from wikipedia
# file: create_server.yml
- hosts: local
  connection: local
  gather_facts: False

  tasks:
  - name: Provision server
    local_action: ec2
      ec2_url={{lookup('env', 'EC2_URL')}}
      aws_access_key={{ lookup('env', 'AWS_ACCESS_KEY_ID') }}
      aws_secret_key={{ lookup('env', 'AWS_SECRET_ACCESS_KEY') }}
      keypair={{lookup('env', 'keypair')}}
      instance_type=t1.micro
      image={{ lookup('env', 'image_centos') }}
      zone={{ lookup('env', 'regions') }}
      instance_tags='{"Name":"sample_server"}'
      wait=true
      count=1
an ansible task to create a server in eucalyptus

Creating a server:

  • Ansible uses boto on the backend, which is compatible with Eucalyptus
  • Only modification needed is to pass the endpoint for the Eucalyptus API
  • Instance tags are used to assign meaningful names to the server
image from wikipedia

step 2: 

can Ansible access the servers it just created?

image from http://aws.amazon.com/ec2/
#!/usr/bin/env python

'''
EC2 external inventory script
=================================

Generates inventory that Ansible can understand by making API request to
AWS EC2 using the Boto library.

NOTE: This script assumes Ansible is being executed where the environment
variables needed for Boto have already been set:
    export AWS_ACCESS_KEY_ID='AK123'
    export AWS_SECRET_ACCESS_KEY='abc123'

This script also assumes there is an ec2.ini file alongside it.  To specify a
different path to ec2.ini, define the EC2_INI_PATH environment variable:

    export EC2_INI_PATH=/path/to/my_ec2.ini

If you're using eucalyptus you need to set the above variables and
you need to define:

    export EC2_URL=http://hostname_of_your_cc:port/services/Eucalyptus

For more details, see: http://docs.pythonboto.org/en/latest/boto_config_tut.html
the ec2 dynamic inventory from ansible

The dynamic EC2 inventory

  • Exporting the EC2_URL variable is sufficient to make the EC2 inventory script connect to Eucalyptus
$ export EC2_URL=http://127.0.0.1:8773/services/Eucalyptus
$ ansible -i ec2.py -u ubuntu us-east-1d -m ping
  • The EC2 inventory groups the servers based on the tags they have
image from: http://www.clker.com/clipart-server-farm.html

step 3: 

can Ansible support multiple instances of the app in the same cloud?

# filter out the instances that don't have a cluster tag
cluster = os.environ.get('CLUSTER')
if cluster != None:
  if 'cluster' in instance.tags and instance.tags['cluster'] != cluster:
    return
  if not 'cluster' in instance.tags:
    return
modifying ec2 inventory to only return servers with the correct CLUSTER tag

step 4: 

can Ansible assign different roles to each server?

image from: http://www.nytimes.com/2008/12/04/fashion/04roles.html
{
  "ec2": [
    "euca-127-0-0-1.eucalyptus.cloud.net"
  ],
  "i-942C484F": [
    "euca-127-0-0-1.eucalyptus.cloud.net"
  ],
  "local": [
    "localhost"
  ],
  "tag_role_sample": [
    "euca-127-0-0-1.eucalyptus.cloud.net"
  ],
 "type_t1_micro": [
    "euca-127-0-0-1.eucalyptus.cloud.net"
  ]
}
# file: sample_role.yml

- hosts: 'tag_role_sample'
  roles:
    - sample
tags returned by EC2 inventory
translating tag to roles

step 5: 

what about overriding configuration on a per cluster basis?

image from: https://www.arbfile.org/webapp/pgStatic/content/EBulletinArbitrators/2013/pgEBulletinArbs_May2013.jsp
# file: hosts/group_vars/tag_cluster_mycluster
# Properties to override go here

msg: "Overriden!"
overriding variables per cluster

putting it all together

____ansible.cfg
|____bin
| |____ansible-eucalyptus
|____clouds
| |____sample_cloud.ini
|____hosts
| |____ec2.py
| |____group_vars
| | |____tag_cluster_mycluster
|____keys
| |____sample.key
|____tasks
| |____create_server.yml
| |____sample_role.yml
| |____roles
| | |____sample
| | | |____defaults
| | | | |____main.yml
| | | |____tasks
| | | | |____main.yml
final tree with all files in place

what is missing?

  • Better key management
  • Putting tags on the nodes to describe a cluster is cumbersome

questions?

irving@irvingc.com