It’s been a few years since I wrote a short HOW-TO on working with EC2 , but recently I tried to migrate the backend of Trading Floor – Facebook and iOS game I have been developing to EC2. So I am documenting the steps for setting up the EC2 for Rails 3.0.
Pre-requisites
I assume you already signed up for EC2, otherwise go to http://aws.amazon.com/ec2/ to signup. Also, you will need Java 5.0 or above, which you can download it from Oracle.
Download EC2 API Tools
First, download EC2 from http://developer.amazonwebservices.com/connect/entry.jspa?externalID=351 and uncompress it in your root directory.
Create a X.509 Certificate
Next, create a X.509 certificate from the AWS Account section. You can then download your certificate and key safely, e.g. I saved them in .ec2 directory under my home directory. Note that you will not be able to download the key again, so don’t lose it.
Environment Variables
Next, I changed my shell as:
export EC2_HOME=~/ec2-api-tools-1.4.2.4 export PATH=$PATH:$EC2_HOME/bin export EC2_KEY_DIR=~/.ec2 export EC2_PRIVATE_KEY=$EC2_KEY_DIR/pk-HFG55OCFPZARA6YHW5JGIE6JFD7EQE72.pem export EC2_CERT=$EC2_KEY_DIR/cert-HFG55OCFPZARA6YHW5JGIE6JFD7EQE72.pem
Where EC2_PRIVATE_KEY and EC2_CERT points to the X.509 key and certificate I downloaded from the Amazon.
Create a Key-Pair
Then I created a pair of keys as:
ec2-add-keypair plexobject
Create a Security Group
I then created a security group for the server
ec2-add-group web -d 'Web Server' ec2-authorize web -P tcp -p 22 -s 0.0.0.0/0 ec2-authorize web -P tcp -p 80 -s 0.0.0.0/0 ec2-authorize web -P tcp -p 443 -s 0.0.0.0/0
Finding a basic Ubuntu based AMI
Previously I used S3 based AMI, but Amazon now supports EBS based AMIs that has advantage that any changes to the root survive instances of EC2. I launched EC2 instance with basic Ubuntu 11.0 Natty from http://alestic.com/ as:
ec2-run-instances ami-06ad526f --instance-count 1 --instance-type m1.small \ --key plexobject --group web -z us-east-1d -m
Where -z describes the availability zone and -m turns on monitoring.
Installing Ubuntu Packages
I then proceeded to install basic packages such as Java, Curl, Git, Build, Ruby (1.8.7) and Rails (3.0.3) based on Rails/Ubuntu docs such as:
sudo apt-get install openjdk-6-jdk sudo apt-get install mercurial sudo apt-get install curl git-core build-essential zlib1g-dev libssl-dev libreadline5-dev sudo apt-get install libcurl4-openssl-dev sudo apt-get install ruby sudo apt-get install rubygems1.8 sudo gem install rubygems-update sudo update_rubygems sudo gem install rails
I then edited /etc/profile /etc/bash.bashrc and added environment variables
export PATH=$PATH:/var/lib/gems/1.8/bin/ export JAVA_HOME=/usr/lib/jvm/java-1.6.0-openjdk/
Next, I installed Sqlite and Mysql:
sudo apt-get install sqlite3 libsqlite3-dev sudo gem install sqlite3-ruby sudo apt-get install mysql-server mysql-client sudo apt-get install libmysql-ruby libmysqlclient-dev
Next, I installed Apache and Passenger:
sudo apt-get install apache2 apache2-mpm-prefork apache2-prefork-dev sudo apt-get install apache2-dev libapr1-dev libaprutil1-dev sudo gem install passenger sudo /var/lib/gems/1.8/gems/passenger-3.0.7/bin/passenger-install-apache2-module*
I then edited /etc/apache2/apache2.conf and added:
LoadModule passenger_module /var/lib/gems/1.8/gems/passenger-3.0.7/ext/apache2/mod_passenger.so PassengerRoot /var/lib/gems/1.8/gems/passenger-3.0.7 PassengerRuby /usr/bin/ruby1.8
and then restarted apache
/etc/init.d/apache2 restart
Creating EBS Volume for Data
Next, I created an EBS volume to store all data such as database tables and Rails application from the AWS Console and then attached it to the instance as:
ec2-stop-instances i-73ab181d ec2-attach-volume vol-612eaa0a -i i-73ab181d -d /dev/sdf ec2-start-instances i-73ab181d
Note that you have to create the EBS volumen in the same availability zone as your instance. I then logged into my machine using
ssh -i plexobject.pem ubuntu@ec2-50-19-134-251.compute-1.amazonaws.com
and then formatted the newly built EBS volume as:
sudo fdisk -l sudo mkfs -t ext4 /dev/xvdf
I then edited /etc/fstab and added
/dev/xvdf /data auto defaults,nobootwait,noatime 0 0
and then rebooted machine
sudo reboot
Moving Mysql Data Directory
Mysql installs data directory on the root volume in /var/lib/mysql directory, which I wanted to move to newly created volume. So I created a directory /data/mysql so I stopped mysql:
sudo /etc/init.d/mysql stop
I then copied mysql data directory such as:
sudo cp -R -p /var/lib/mysql/mysql /data/mysql sudo chown -R mysql:mysql /data/mysql/
I didn’t copy entire mysql directory, only mysql subdirectory. Next I edited /etc/mysql/my.cnf and changed datadir to /data/mysql directory and then edited /etc/apparmor.d/usr.sbin.mysqld and changed all /var/lib/mysql to /data/mysql. Finally I restarted AppArmor profiles as:
sudo /etc/init.d/apparmor reload
Then restarted mysql:
sudo /etc/init.d/mysql restart
I changed my root password and created a local mysql user as
mysql> SET PASSWORD FOR 'root'@'localhost' = PASSWORD('mypass'); mysql> GRANT ALL PRIVILEGES ON *.* TO 'tfuser'@'localhost' IDENTIFIED BY 'mypass' WITH GRANT OPTION; mysql> GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, INDEX, ALTER, CREATE TEMPORARY TABLES, LOCK TABLES ON dbname.* TO 'tfuser'@'localhost' IDENTIFIED BY 'mypass';
I copied my app to /data/trading_floor and changed permissions of all files to www-data
sudo chown -R www-data:www-data /data/trading_floor
Then created /etc/apache2/sites-available/tf with
ServerAdmin shahbhat@gmail.com ServerName tf.plexobject.com DocumentRoot /data/trading_floor/public/ AllowOverride all Options -MultiViews RailsEnv production
Finally, I restarted apache
/etc/init.d/apache2 restart
Creating Elastic IP address
I wanted a permanent IP address for the server so I created EIP using AWS Console. Then associated my instance with the new IP address:
ec2-associate-address 50.19.248.7 -i i-73ab181d
It rebooted your machine with the new IP address. I then changed DNS zone and pointed tf.plexobject.com to 50.19.248.7 (this may take hours to propagate). Next, I changed my Facebook app’s configuration and iOS app’s configuration to point to tf.plexobject.com.
Creating my EBS Image
Once I was happy with the server configuration, I created EBS image for future use. First, I detached data volume and then created image as follows:
ec2-stop-instances i-f97ca197 ec2-detach-volume vol-3f65d954 ec2-create-image i-f97ca197 -n tf-20110601 -d 'Trading Floor Application Server'
I terminated my previous instance as
ec2-terminate-instances -i i-f97ca197
and created instance with the new image
ec2-run-instances ami-80837ae9 --instance-count 1 --instance-type m1.small --key tf --group web -z us-east-1d -m
After the launch, you would have to reattach the data volume
ec2-stop-instances i-73ab181d ec2-attach-volume vol-612eaa0a -i i-73ab181d -d /dev/sdf ec2-start-instances i-73ab181d
Summary
Voila, I had my game application running on the cloud. In order to cut per/hour cost I reserved instances for entire year. I am not quite done with my server and am now working on application specific configuration and adding better monitoring/backup. As, we have learned from recent Amazon Cloud outage that deploying your app on the cloud is only half the work, making it performant, scalable and fault tolerant is other half which is still manual work. Finally, I plan to release the Facebook app for Trading Floor and submit iOS app in a couple of weeks, be sure to try it and send me your suggestions.