Monday, January 28, 2008

Client for nettica dns service

One of the drawbacks of EC2 is that there are no static IPs to be had, so short of using an external (to ec2) solution, the only way to have redundant load balancers is to use dns round robin.  If a load balancer instance goes down, we should ideally remove it from the round robin so that clients don't continue to use the dead IP.

Nettica is one of the few dns providers that has an API that allows changes to round robin records.  They have a reference implementation in Java, but since I'm a ruby fanboy these days, I figured it would be nice to have a ruby version instead, so I added one to rubyforge:  nettica ruby client.  I did it as a gem, so assuming I released it correctly, you should be able to do a "sudo gem install nettica" and then run the simple test script "nettica -u my_user -p my_secret -c list_zones".  This script still needs to be expanded to exercise the full api.

One thing that blocked me for the longest time was that the nettcia API required the password to be sent in Base64 encoding, which I was doing, but for some reason the ruby Base64.encode64() method was adding a newline to the end of the encoded string.  Once I stripped that out, it all seems to work fine.

Deploying Rails Apps to EC2 with Capistrano

I've created yet another system for deploying rails apps to ec2 using capistrano.  None of the others were doing it for me, primarily because I needed a way to deploy/configure/scale-up to multiple instances as needed.
  What makes this system different?

  • Role and/or host based configuration of instances

  • All configuration for your instances lives in your project's source tree and gets applied on deploy

  • Configuration system handles dynamically adding instances

  • Configuration templates for sharing deployment scenarios

  • Start with a single instance and scale up as needed without editing config

  • Use whatever AMIs you want (so long as they are debian based :)


You can find the README file in subversion on rubyforge (project rubber).  You can install the framework from subversion as a rails plugin in the usual way - the README walks you through a demo using the plugin on a dummy rails app, and there is no need to check anything into subversion to do the demo.

This is still very much a work in progress, so don't use it in production, and expect things to drastically change requiring you to reinstall and reconfigure.

Any feedback appreciated, but check the TODO first :)

Saturday, January 26, 2008

Using Capistrano without source control

I'm in the process of writing some capistrano recipes to make deploying to Amazon's Elastic Compute Cloud (ec2) easier. Since I'm making this project available for general consumption, I wanted a way to make it easy for someone to try it out without having to check something into source control.

Fortunately, the capistrano code is nicely organized, and that made it easy for me to add a "noscm" provider that will work with the "copy" deploy strategy to simply copy the projects directory tree to a remote server rather than trying to check it out from the remote server. You can get the code here: http://rubber.rubyforge.org/svn/trunk/lib/capistrano/noscm.rb and then add the following lines to your deploy script to get it to work:


require 'capistrano/noscm'
set :scm, :noscm
set :deploy_via, :copy
set :copy_strategy, :export


This works for my limited use case, YMMV - things like "cap deploy:pending:diff" definately won't work as all I've implemented from the capistrano scm interface is the "export" ability.

Mounting Xen DomU LVM disk in Dom0

I setup a xen based system for our production environment at work. I'm using LVM throughout for all the benefits it provides (resizing, snapshot backups, etc). Each domU gets its own logical volume on dom0's volume group. This logical volume actually looks like an entire physical disk to the domU, and the domU then further partitions it into a boot partition and a nested LVM partition (swap + root fs). Aren't the layers of unix file abstractions a thing of beauty to behold? :)

In retrospect I probably should have mapped LVM logical volumes direct from dom0 as partitions in domU rather than having domU add the extra LVM layer on top - though reading around shows that this _may_ not be supported in the future, so...Recently I completely horked our mysql db slave replica and needed to re-replicate the master to the db. Since our DB is ~ 60GB, I didn't want to shut down (read lock) our master DB for the length of time it would take to copy it over to the slave. The solution to this would be to use an LVM snapshot. This way I could read lock the master db, create the LVM snapshot (very quick - a few seconds at most), unlock the master, then copy the data from the snapshot to the slave at my leisure, letting standard db replication do the catch up later.

For those not in the know about DB repication, one has to make a copy of the master and record the position in its transaction log at that point in time - this way the slave can know where in the transaction log to start repicating from once it comes up with the copy of the data up to that point.

Ok, so, now knowing what I needed to do, I just needed to do it - not as easy as I thought it would be due to the extra layer of LVM.

Fortunately, googling around found me my solution, which I'm recording here for the next time I need to do it :)

Basically, the trick is two fold, frst we have to use kpartx to map the partitions from our virtual disk into partition devices in /dev. Then we have to tell LVM to rescan these devices to find our embedded LVM partition, and activate the logical volumes on there so that we can then mount them as regular filesystems.

lvcreate --size 1G --snapshot --name ss_dbmaster /dev/vol1/dbmaster

kpartx -av /dev/vol1/ss_dbmaster

vgscan

lvscan inactive '/dev/VolGroup00/LogVol00'

[61.84 GB] inherit inactive '/dev/VolGroup00/LogVol01' [2.00 GB] inherit

lvchange -ay /dev/VolGroup00/LogVol00

lvscan ACTIVE '/dev/VolGroup00/LogVol00' [61.84 GB] inherit

mount -t ext3 /dev/VolGroup00/LogVol00 /tmp/dbmaster/

Lets hope I don't have to do that again anytime soon! I just think its cool how unix can have these layers of abstractions between files and partitions, with files in partitions and partitions in files :)