= ey_cloud_awareness
This gem makes it a little easier to live on the EngineYard cloud:
* automatically run cap tasks on all your instances
* automatically update your ssh aliases
* allow your app to get information about the cluster (aka "environment") it's running in
We use it over at http://brighterplanet.com.
== Don't read this
This gem depends on
/etc/chef/dna.json
being READABLE and containing certain attributes as named by EngineYard. You might have to add:
`sudo chmod a+r /etc/chef/dna.json`
to your before_migrate.rb script.
== Quick start
Put this in config/environment.rb:
config.gem 'ey_cloud_awareness', :version => '[WHATEVER THE CURRENT GEM VERSION IS]', :lib => false, :source => 'http://gemcutter.org'
Put this in your config/deploy.rb (or whereever your Capfile is):
# don't miss this line just because it's at the top
load "#{Gem.searcher.find('ey_cloud_awareness').full_gem_path}/lib/tasks/capistrano_tasks.rb"
task :my_production do
role :app_master, 'my_app.com' # or you can use its Elastic IP
set :rails_env, 'production' # required
set :deploy_to, '/data/my_app' # required
find_and_execute_task 'eyc_setup' # required
end
task :my_staging do
role :app_master, 'staging.my_app.com' # or you can use its Elastic IP
set :rails_env, 'production' # required
set :deploy_to, '/data/my_app' # required
find_and_execute_task 'eyc_setup' # required
end
# add more tasks if you have more cloud environments
That should be all.
== Running capistrano tasks on your instances
Commands like these will work:
cap my_production monit:status
cap my_production deploy:web:disable
cap my_production deploy:web:enable
cap my_production passenger:restart
cap my_production nginx:restart
Every time you use them, a special eyc_setup task is run that gets a fresh list of your environment's instances and sets roles like :app, :web, and :db.
== SSH into your instances
Let's say you want to ssh into...
ssh my_production-app_master
Well, you need to keep your ~/.ssh/config up-to-date. Easy!
cap my_production eyc:ssh
That will magically add or update a block like
# START StringReplacer my_production -- DO NOT MODIFY
# db_master
Host my_production-db_master
Hostname ec2-222-222-222-59.compute-1.amazonaws.com
User my_user
StrictHostKeyChecking no
# utility (1)
Host my_production-utility1
Hostname ec2-222-222-53-222.compute-1.amazonaws.com
User my_user
StrictHostKeyChecking no
# app_master
Host my_production-app_master
Hostname ec2-222-222-23-222.compute-1.amazonaws.com
User my_user
StrictHostKeyChecking no
# END StringReplacer my_production -- DO NOT MODIFY
Run that again as
cap my_staging eyc:ssh
... and it adds
# START StringReplacer my_staging -- DO NOT MODIFY
# app_master
Host my_staging-app_master
Hostname ec2-222-222-7-210.compute-1.amazonaws.com
User my_user
StrictHostKeyChecking no
# db_master
Host my_staging-db_master
Hostname ec2-222-222-52-8.compute-1.amazonaws.com
User my_user
StrictHostKeyChecking no
# END StringReplacer my_staging -- DO NOT MODIFY
This leaves you with lots of useful aliases:
ssh my_production-db_master
ssh my_production-app_master
ssh my_production-utility1
ssh my_staging-app_master
ssh my_staging-db_master
Note that the numbers after app [slaves], db [slaves], and utility [slaves] may change every time you run the task.
== Just dumping information about your instances
Once you've done the quickstart, try:
cap my_production eyc:app # gets a list of your app instances, including app_master
cap my_production eyc:utility # ditto for utility instances
cap my_production eyc:db # ditto for db instances
cap my_production eyc:all # gets a list of all your instances
== Using the EngineYardCloudInstance class inside Rails
I run a memcached server on every app instance, so I have this in config/environment.rb:
Rails::Initializer.run do |config|
[...]
config.cache_store = :mem_cache_store, EngineYardCloudInstance.app.map { |i| "#{i.private_dns_name}:11211" }
[...]
end
Or whatever you want:
>> all_app_instances = EngineYardCloudInstance.app
=> [#, #, #]
>> all_app_instances.first.dns_name
=> "ec2-67-201-47-30.compute-1.amazonaws.com"
>> pp all_app_instances.first.to_hash
=> {:block_device_mapping=>
[{:ebs=>
{:status=>"attached",
:volumeId=>"vol-26172ee8",
:deleteOnTermination=>"false",
:attachTime=>"2010-04-07T21:09:37.000Z"},
:deviceName=>"/dev/sdz2"},
{:ebs=>
{:status=>"attached",
:volumeId=>"vol-26172ee8",
:deleteOnTermination=>"false",
:attachTime=>"2010-04-07T21:09:37.000Z"},
:deviceName=>"/dev/sdz1"}],
:launch_time=>"2010-04-07T21:08:10.000Z",
:instance_type=>"c1.medium",
:private_dns_name=>"domU-44-44-44-44-A4-02.compute-1.internal",
:instance_state=>{:code=>"16", :name=>"running"},
:ami_launch_index=>"0",
:users=>
[{:password=>"hoppAugEv",
:username=>"deploy",
:uid=>"1000",
:comment=>"",
:gid=>"1000"}],
:environment=>
{:framework_env=>"production",
:name=>"my_staging",
:stack=>"nginx_passenger"},
:instance_id=>"i-50cf5838",
:group_id=>"ey-my_staging-XXXXXXXXXXXXXXXXXXXX",
:root_device_type=>"instance-store",
:private_ip_address=>"10.201.102.201",
:kernel_id=>"aki-9b00e5f2",
:placement=>{:availabilityZone=>"us-east-1a"},
:product_codes=>nil,
:image_id=>"ami-7044a419",
:reason=>nil,
:dns_name=>"ec2-67-201-47-30.compute-1.amazonaws.com",
:ip_address=>"199.99.99.99",
:architecture=>"i386",
:instance_role=>"solo",
:monitoring=>{:state=>"disabled"}}
== A note on caching and network needs
I tried to be smart about caching the results of network calls.
Stuff like the current instance id, which is pulled from an EC2 metadata server, is stored in
CURRENT_INSTANCE_ID_CACHE_PATH = File.expand_path '~/.ey_cloud_awareness/engine_yard_cloud_instance_id'
Please let me know if this causes problems.
== Copyright
Copyright (c) 2009 Seamus Abshere. See LICENSE for details.