Here at Isotope11, we've been working on making our clients' server setups fault tolerant and just all around better. We've been having problems with our current cloud server provider, and so we decided to seek out the best possible solution for our clients. To do this we sought out a full failover setup using Amazon's AWS services.
Why should I use a failover with Amazon?
As of today, Amazon has dropped their prices is one reason. Not only can you spawn up servers in two different regions with Amazon EC2 under the traditional master/slave setup and have Capistrano deploy to both of these servers, but you can also have an Amazon RDS instance between the two to make sure everything in the database stays in sync. Now where things get tricky is keeping your file uploads in sync. This can be easily accomplished with a FUSE-based file system backed by Amazon S3.
How do I do all of this?
Easy. I'll show you. First you'll need to sign up for Amazon's AWS.
Here is the list of services you'll need to sign up for:
- Some type of DNS Failover service.
- Amazon's Elastic Compute Cloud in two separate Regions. (i.e. US East and US West)
- Amazon's Multi-AZ Relational Database Service (Reserved).
- Amazon's Simple Storage Service.
Setting up the DNS Failover
You'll have to check with your current DNS provider (if you have one) to
see if they offer a DNS failover service. I'll just show you how it's done
with TZO-HA. In the master/slave relationship of
failover server setup, we'll use TZO's Failover Switch-Back which will
perform DNS failover to the slave in the event of master going down and
automatically switch back DNS Failover to master when the master comes back
on online.
Observe:

There isn't much left to explain here. Further information can be found on your DNS provider's website.
Setting up your EC2 Instances
Once you've signed up for AWS then you'll be ready to spin up your EC2
instances. You'll have to take into consideration what type of EC2 instance
you'll need depending on how much your application will be used and how big
your application actual is. If you have a large application with high
traffic, then you'll probably want to go with the m1.large instance. If
you're Google, FaceBook,
or Twitter you'll want to look into something
more extreme.
Launching different regional instances
Once you're in the AWS Management Console on the EC2 tab you'll need to
figure out (depending on where most of your traffic comes from) which will
be the master and which will be the slave server. In our case most of
the traffic comes from the US East region, so I will use that as the
master for this example. We'll also be using Official Ubuntu 11.10 AMD64
Server AMIs.
Master Instance:
- Select
Region: US East (Virginia)under theNavigation - On the
EC2 DashboardunderGetting Startedclick onLaunch Instance - Use the
Classic Wizardand clickContinue - On the next step select the
Community AMIstab - In the
Searchfield enterami-baba68d3(this is the Official Ubuntu 11.10 amd64 Server AMI forus-east-1) and clickSelect - Choose an
Instance Type,Availability Zoneand clickContinue - Select
aki-825ea7ebfrom theKernel IDdrop-down menu (this is the official Ubuntu 11.10 amd64 Server AKI), leave the rest as is and clickContinue - Fill in
KeyandValueon the next step to add tags for easier administration of your EC2 infrastructure. - Now you'll need to create a
Key Pairby filling in the required fields, then clickCreate & Download your Key Pairas it's required for SSH access your EC2 instance, and clickContinue - Now we'll want to create a new security group in the next step. Give this
a good
Group NameandGroup Description. UnderInbound RulesandCreate a new rule:selectSSH,HTTPand any other protocol you may need followed by clickingContinue - Review that everything looks correct to your needs and click
Launch
Note: Slave instance is almost identical, just note the Region,
AMI and AKI.
Slave Instance:
- Select
Region: US West (N. California)under theNavigation - On the
EC2 DashboardunderGetting Startedclick onLaunch Instance - Use the
Classic Wizardand clickContinue - On the next step select the
Community AMIstab - In the
Searchfield enterami-6da8f128(this is the Official Ubuntu 11.10 amd64 Server AMI forus-west-1) and clickSelect - Choose an
Instance Type,Availability Zoneand clickContinue - Select
aki-8d396bc8from theKernel IDdrop-down menu (this is the official Ubuntu 11.10 amd64 Server AKI), leave the rest as is and clickContinue - Fill in
KeyandValueon the next step to add tags for easier administration of your EC2 infrastructure. - Now you'll need to create a
Key Pairby filling in the required fields, then clickCreate & Download your Key Pairas it's required for SSH access your EC2 instance, and clickContinue - Now we'll want to create a new security group in the next step. Give this
a good
Group NameandGroup Description. UnderInbound RulesandCreate a new rule:selectSSH,HTTPand any other protocol you may need followed by clickingContinue - Review that everything looks correct to your needs and click
Launch
Connect To your EC2 Instance for the First Time
From the AWS Management Console under the EC2 tab Select the Region
in which your instance lives and click Instances Under the Navigation.
Right click on your instance and click Connect. This will give you more
instructions on connecting to your instances for the first time. All you'll
need to do is the following:
chmod 400 /path/to/your/private_key.pem
ssh -i /path/to/your/private_key.pem ubuntu@your_public_dns
Setting Up the Servers for Production
Once your instances have launched and are ready, the instructions posted here will be the same for both servers. We'll take it step by step to get your instances set up. For both servers, observe the instructions and follow the steps:
Setup your user account you'll be deploying with
sudo su
adduser deployer
visudo
After running visudo just add deployer ALL=(ALL) ALL somewhere in that
file and save it.
Setup Password Authentication for SSH
After doing the following you'll be able to login to your server with
deployer
sudo su
sed -i 's,PasswordAuthentication no,PasswordAuthentication yes,' /etc/ssh/sshd_config
sudo /etc/init.d/ssh restart
Setting up Ruby + Rails
Since installing Ruby and Ruby on Rails is not really the topic of the blog post, I am
going to leave it up to you to decide which versions of Ruby and Ruby on Rails you
need on your production server. I will note that you should compile your
version of Ruby from source and then you can
gem install rails, also make sure apt dependencies are met
Installing apt Dependencies.
If you're choosing to run [Ubuntu] for your EC2 Instance, the following
will meet most apt dependencies for Ruby and
Ruby on Rails applications.
sudo apt-get update && sudo apt-get install build-essential openssl libreadline6 libreadline6-dev libcurl4-openssl-dev curl git-core zlib1g zlib1g-dev libssl-dev libyaml-dev libsqlite3-0 libsqlite3-dev sqlite3 libxml2-dev libxslt-dev autoconf libc6-dev ncurses-dev automake libtool bison subversion apache2-mpm-prefork apache2-prefork-dev libapr1-dev libaprutil1-dev mysql-server
Setting Up RDS
You'll need to make sure your DB engine is supported by RDS. In this example we'll be using MySQL.
- Under
AWS Management Consoleselect the RDS tab and then clickLaunch DB Instance - Press
Selectnext tomysql - Select a
DB Engine Version(research may be required depending on your apps specifications, 5.1.61 will work for most instances) - Choose your
DB Instance Class(research may be required depending on how big your application's database is going to be) - Select
YesforMulti-AZ Deployment - Select an option for
Auto Minor Version Upgrade(research may be required, selectNoif your application will be heavily dependent on the selected version) - Fill in an
Allocated Storagesize (Minimum: 5 GB, Maximum 1024 GB) - Fill in your
DB Instance Identifier - Fill in a
Master User Name - Fill in a
Master User Passwordand selectContinue - Fill in a
Database Name(e.g. mydb) - Choose a
Database Portyou'd like to use - Choose
Not in VPSforChoose a VPCand clickContinue - Choose your preferred
Backup Retention Period,Backup WindowandMaintenance Windowand clickContinue - Now finally click
Launch DB Instance
Under DB Security Groups check your default security group then select
CIDR/IP and add your the IP Address of your two EC2 Instances to give
them access to your database.
Setting up your application on the RDS
This can be accomplished in your database.yml file by setting the host
to the Endpoint of your DB Instance, found under DB Instances under the
RDS tab of the AWS Management Console.
Observe:
production:
adapter: mysql
host: mydb.cuw5icb3qk2p.us-east-1.rds.amazonaws.com
reconnect: false
database: mydb_production
username: mydb_user
password: <YOUR SECRET PASSWORD>
Mounting S3 as a remote Drive:
Under the AWS Management Console select the S3 tab, and click Create
Bucket. You'll need to give it Bucket Name (with no capital letters) and
select a Region and click create.
Make sure you have your Access Key ID and Secret Access Key available
from Security Credentials under your user menu at the top right of the
AWS Management Console.
Now use the following to mount your remote S3 bucket as a remote drive:
sudo apt-get install fuse-utils s3cmd
wget http://s3fs.googlecode.com/files/s3fs-1.61.tar.gz
tar xvzf s3fs-1.61.tar.gz
cd s3fs-1.61/
./configure --prefix=/usr
make
sudo make install
s3cmd --configure
sudo usermod -aG fuse deployer
sudo su
touch /etc/passwd-s3fs && chmod 640 /etc/passwd-s3fs && echo 'AccessKey:SecretKey' > /etc/passwd-s3fs
echo 's3fs#my_bucket /mnt/s3 fuse allow_other,uid=deployer,umask=777,url=https://s3.amazonaws.com 0 0' >> /etc/fstab
mount /mnt/s3
Now you can just setup your application's deploy scripts to deploy to both
servers, and symlink all your public files from /mnt/s3 to /path/to/your/apps/current/public with
ln -s /mnt/s3/public /path/to/your/apps/current/public
and all files should be uploaded and downloaded from your S3 instance.
Conclusion
This system is not perfect. There are still SPoFs. For instance, if
your DNS provider that runs the DNS Failover ever goes down (worst case)
or Amazon's S3 region goes down (still pretty bad) you'll experience
problems. In the worst case, if the DNS Failover service ever goes down
it will not fail over to the slave server if master goes down. In the
case that Amazon's S3 service goes down you'll experience not being able
to upload or download files to the Rails public directory. In contrast,
this is a much more fault tolerant setup than having your clients'
applications and databases hosted on one server and hoping it never goes
down.