Deploying Ruby on Rails in Windows Azure using the Linux Command-Line Tools (Part 1)

In this blog post in two parts, I will show you how to deploy a set of Linux Virtual Machines running in Windows Azure, running the Ruby on Rails stack with a MongoDB back-end. The challenge is to do it without ever touching a Windows client machine, and using only the Linux command-line tools. Let's go!

On your Linux client machine, you will need to install the Azure command-line tools. You can find a detailed tutorial there: https://www.windowsazure.com/en-us/manage/linux/other-resources/command-line-tools/

But in summary, all you need is to install Node.JS and the Windows Azure Node.JS module, using a recent version of Node (> 0.6.15). This should do it (on Ubuntu):

To install Node:

 $ curl -O https://nodejs.org/dist/v0.8.12/node-v0.8.12.tar.gz
$ tar xzf node-v0.8.12.tar.gz
$ cd node-v0.8.12/
$ ./configure
$ make
$ sudo make install

To install npm:

 $ curl https://npmjs.org/install.sh | sudo sh

And finally the Windows Azure command-line tools themselves:

 $ sudo npm install azure -g

You are now ready to use the command-line tools. Just type "azure" to check everything is in place and working nicely!

Next, you need to import your "publish settings" in order to be able to communicate with the Windows Azure platform. As instructed in the tutorial, use the "azure download" command followed by "azure import" in order to import the details of your Windows Azure account. You should then be able to run a simple command like this and receive a result:

 $ azure vm image list

This will retrieve and display a list of available Linux distributions so you can choose the one you want to use.

Now we can start creating our virtual machines!

You can pick the Linux image you prefer; I am going to use Ubuntu, this mean I will use the following image name in my commands:

 CANONICAL__Canonical-Ubuntu-12-04-amd64-server-20120528.1.3-en-us-30GB.vhd

Now, you can list the available Windows Azure locations in order to decide where you want to host your platform:

 $ azure vm location list

I am going to use "West Europe" in my case.

Now we are going to create our first VM, keeping in mind that we want to add another VM afterwards for the database. They key concept to understand here is one of a Cloud Service: if we create two VMs withing the same Cloud Service, then they will be "connected" to each other, meaning that they will be able to communicate via TCP/IP. Otherwise, each VM deployed in a separate Cloud Service is isolated from all others.

The first parameter you pass to the "vm create" commands is actually the Cloud Service name (or DNS prefix). This will become the public URL for your virtual machines, in the form of "dns-name.cloudapp.net". All the VMs in the same Cloud Service will share this same public address.

When creating the VM, we pass a --location parameter containing the name of the Windows Azure location we want, and a --vm-name parameter to give the VM a specific name.

 $ azure vm create testruby \
"CANONICAL__Canonical-Ubuntu-12-04-amd64-server-20120528.1.3-en-us-30GB.vhd" \
tom "password" \
--location "West Europe" \
--vm-name web1 --ssh

Then, we can create the second VM. We "connect" it to the first so that they can communicate with each other. Since we already allocated port 22 to the first VM, we have to specify another port for this one, since both VMs share the same public address.

 $ azure vm create testruby \
"CANONICAL__Canonical-Ubuntu-12-04-amd64-server-20120528.1.3-en-us-30GB.vhd" \
tom "password" \
--connect web1 \
--vm-name mongodb --ssh 23

Once both commands have finished running, you can try connection to the virtual machines:

 $ ssh tom@testruby.cloudapp.net
$ ssh -p 23 tom@testruby.cloudapp.net

Now let's install Ruby on the Web front-end (as root):

 # apt-get install ruby-full
# apt-get install rubygems
# gem install rails

We will also need Node.JS:

 # apt-get install nodejs

Let's create a dummy Rails application just to test our front-end (as a regular user). We will just skip the Active Record stuff for now, we just want to run a quick static test.

 $ rails new test1 --skip-active-record
$ cd test1
$ rails server
=> Booting WEBrick
=> Rails 3.2.8 application starting in development on https://0.0.0.0:3000
=> Call with -d to detach
=> Ctrl-C to shutdown server
[2012-10-15 14:01:04] INFO  WEBrick 1.3.1
[2012-10-15 14:01:04] INFO  ruby 1.8.7 (2011-06-30) [x86_64-linux]
[2012-10-15 14:01:04] INFO  WEBrick::HTTPServer#start: pid=13213 port=3000

Our Rails server is running on default port 3000, and we can test it locally:

 $ curl https://localhost:3000

However it would be much better to access it from the outside world, don't you think? Let's go back to the Azure Command Line Tools and add an endpoint to our Cloud Service:

 $ azure vm endpoint create web1 80 3000

This will open TCP port 80 (HTTP) to the outside, routing requests to port 3000 on the virtual machine called "web1".

You should now be able to reach your service from the outside:

https://testruby.cloudapp.net/

See you in part two for the installation of MongoDB!