Posted on Oct 18, 2010

Migrating from Aptana Cloud ( Joyent ) to Engine Yard AppCloud

We’ve been a happy user of Aptana Cloud for over a year.  For those of you who are not familiar with Aptana Cloud, it was a service provided through Aptana IDE that allowed you to deploy a Ruby on Rails (as well as other framework) application to a Joyent SmartMachine in a couple of clicks, without having to know a lot about Linux and server administration in general.  For us, it was a great value – we were and still are avid users of Aptana IDE so going to Aptana Cloud for hosting was a natural thing to do.  Unfortunately, Aptana has recently announced that it is shutting down its Aptana Cloud offering on October 31st, 2010.  So we were faced with a “fun” exercise of finding a new hosting provider for our Rails application – Switchboard.

The first avenue we took was looking at Joyent directly, since Switchboard was already running on their platform.  Given their special offer of $75 per month for a 1GB SmartMachine for former Aptana Cloud customers, going to Joyent looked pretty appealing.  We’ve worked with a Joyent representative on a plan of action for the migration, who was very helpful.  However, when it was all said and done hosting on Joyent was just too complicated.  We have to say that we know very little about server administration and tunning (be that Linux or Solaris) and having to set everything up from scratch and configure it properly ended being too much of an effort for us.  Working with Solaris in the past, which is the OS that Joyent uses, was also somewhat of an issue, since there are a lot less resources and documentation on the web available in regards to Ruby on Rails and Solaris as opposed to good old Linux.

We’ve always wanted to give Engine Yard a try.  These guys are well known in the Ruby on Rails community as one of the best hosting providers around.  The issue however has always been cost.  Fairly recently Engine Yard released a service, called AppCloud, that allows you to deploy a Ruby on Rails application on Amazon Web Services infrastructure, using the robust and nicely tuned Ruby on Rails/Linux stack that Engine Yard has developed over the years.  The service is a lot more affordable than the more exclusive xCloud offering from Engine Yard.  In the end, Engine Yard AppCloud is the hosting solution that we decided to go with for the following main reasons:

  1. AppCloud requires minimal knowledge of Linux server administration.  It comes with a proven Ruby on Rails stack and the rest 99% of server administration can be done from the web console of Engine Yard website.
  2. You pay hourly for what you use, meaning that when you bring the server down (not delete it completely though) you don’t actually pay anything.  This was extremely helpful during the migration process.  You can bring your instances up and down as many times as you wish
  3. Duplicating your instances is super easy.  This is great for having staging environments, whereas with Joyent we had to share our 1GB SmartMachine for both, which sometimes lead to resource problems.  With AppCloud we can duplicate our production environment with a couple of clicks, bring it up for a few hours or days to do testing, and then bring it down, paying only for the hours that we used.
  4. Using LoadImpact we actually achieved much better response time (2-3 fold) on the smallest AppCloud instance (m1.small) than our Joyent 1GB SmartMachine. This could be totally due to the setup of the Aptana Cloud configuration on Joyent, but given the fact that we are not that proficient in server administration, this was certainly a huge advantage.
  5. Although AppCloud is currently only running on AWS, Engine Yard seems to be working on providing other cloud infrastructures in the future, given their involvement in the fog project.  This should result in greater flexibility for us going forward.

Preparation

The following steps were performed ahead of time to get ready for the migration.

Register with EngineYard.com and create an environment with an application.

Add ruby gems along with versions in AppCloud dashboard.

Add unix packages in AppCloud dashboard.  For example – sphinx, imagemagick

Boot instance

Install engineyard gem on local dev machine

Going forward you can just “ey deploy” to push git repo to AppCloud.

Add custom recipes from EY cookbook

http://docs.engineyard.com/appcloud/howtos/customizations/custom-chef-recipes

Adjust sphinx recipe

Change the appname, choose thinking_sphinx flavor, set cron interval to 59 minutes.

delayed_job recipe changes

Add reporting to AppCloud dashboard and chmod /app_name/current/script/runner (otherwise worker will not start), this can be added right at beginning of app loop.

http://community.engineyard.com/discussions/problems/1485-delayed_job-worker-not-starting-permission-denied

ey_cloud_report "DelayedJob" do
  message "configuring delayed_job"
end

file "/data/#{app_name}/current/script/runner" do
   owner node[:owner_name]
   group node[:owner_name]
   mode 0755
end

Enable sphinx, ssmtp and delayed_job recipes in cookbook/main/recipes/default.rb

git commit and push these changes to appcloud instance via

ey recipes upload -e appname_production
ey recipes apply -e appname_production

Link SSH key through AppCloud dashboard

More Options > Edit Environment > Advanced Options > SSH Keys

SSH to server with deploy user

Upload credentials .yml files to /data/appname/shared/config.

This is an optional step.  We have some credentials files that are not part of the git repository and have to be uploaded and symlinked manually on the server

Create the ssmtp.conf file

You cannot send e-mails from AWS instance directly (via postfix for example), because AWS ips are typically blacklisted.  So you have to use an external SMTP service (free Google Mail if less than 500 e-mails per day, or SendGrid for a commercial service).  We are using SendGrid below.

cd /data/ssmtp
sudo nano ssmtp.conf
mailhub=smtp.sendgrid.com

rewriteDomain=mydomain.com

FromLineOverride=YES

UseSTARTTLS=YES

AuthUser=username
AuthPass=password
AuthMethod=LOGIN
sudo chown deploy:deploy /data/ssmtp/ssmtp.conf

Setup cron jobs in AppCloud dashboard

http://docs.engineyard.com/appcloud/guides/environments/adding-cron-jobs

Create a new local and remote git branch for testing out the migration

git checkout -b engineyard
git push origin origin:refs/heads/engineyard

Create ey.yml file in your /config folder locally

This should be changed to the master branch when you are about to go live.

environments:
  appname_production:
  branch: engineyard
    copy_exclude:
      - .git

Create before_migrate hook for ey deployment

rails_app/deploy/before_migrate.rb

Create all your symlinks like so:

run "ln -nfs #{shared_path}/config/amazon_s3.yml #{release_path}/config/amazon_s3.yml"

Create the after_restart hook for ey deployement

rails_app/deploy/after_restart.rb

For example, to restart delayed_job workers:

run "sudo monit -g dj_appname restart all"

Create the before_restart hook for ey deployment

rails_app/deploy/before_restart.rb

For example, to avoid delayed_job permission errors:

run "sudo chmod 755 #{release_path}/script/runner"

Change the production smtp setup

rails_app/config/environments/production.rb

Had to remove the localhost postfix smtp settings and replace with:

ActionMailer::Base.delivery_method = :sendmail

This will send to SendGrid via the ssmtp setup on AWS instance

Deploy the app to EngineYard

git push
ey deploy

Update the domain in AppCloud application settings to *.mytestingdomain.com

We have a separate domain for our staging environment so we used it here to test out the setup.  Make sure DNS (at your DNS provider, for example GoDaddy) has A “*” record pointing to static IP address for AppCloud.  Must rebuild the instance afterwards (click Rebuild on dashboard).

Add SSL certificate via Engine Yard dashboard (if you are using SSL)

Can use a test one if necessary.  Must rebuild the instance afterwards (click Rebuild on dashboard)

Bring over MySQL database content (mysqldump)

http://docs.engineyard.com/appcloud/howtos/databases/dump-and-load-your-mysql-database

Lookup the DB password for deploy user from /data/appname/current/config/database.yml

General notes

Had to remove sphinx.yml from git repo as it was conflicting with sphinx recipe which creates it.

Had to make maintenance page static and put it into public/maintenance.html.  Can change the wording in there with each deploy if necessary.  This is only if you are already using a typical capistrano maintenance page.

Go-live steps

These steps are performed during the actual migration/conversion during go-live:

Point www.mytestingdomain.com back to Aptana Cloud IP address (OPTIONAL)

This is to ensure nobody will access your application on Engine Yard until you are ready to go live.  Done via DNS provider (for example GoDaddy.com)

Change the domain on EngineYard environment via their dashboard to *.myrealdomain.com (this is to allow use of any subdomains)

Applications > Appname > Edit

We are just changing the config on Engine Yard, but have not actually pointed the DNS record to AppCloud yet.

Start up EngineYard instance

Medium instances are really nice but will run roughly $160 per month.  A small instance is surprisingly capable too at roughly $80 per month when used 24/7.

Ship latest version of your Rails app from master git branch

Applications > Appname > Ship-it

Verify that the instance is running

Access via IP address assigned to the environment (can’t go via domain as it hasn’t been assigned yet)

Put the maintenance page up on production aptana cloud site

We already had a capistrano maintenance page setup for that on Aptana Cloud

From local dev machine:

git branch aptanacloud
apcloud public deploy:web:disable

Check that the page is disabled by going to www.yourdomain.com

Stop delayed_job workers (if you have any)

From aptanacloud server (ssh):

cd public/web/current
script/delayed_job stop production

Stop thinking_sphinx process (just to be paranoid here)

From aptanacloud server (ssh):

cd public/web/current
sudo rake thinking_sphinx:stop RAILS_ENV=production

Remove all cron jobs (if you have any)

From aptanacloud server (ssh):

crontab -e

dd (several times to delete all lines)

:wq (save and quit)

Kill all DB connections

From aptanacloud server (ssh):

mysql -u aptanacloud_username -p
(enter password)
SHOW PROCESSLIST;
KILL X;

where x is ID of process, repeat for all active processes

Dump the database into a file

From aptanacloud server (ssh):

cd ~/mysql_dump
mysqldump -u aptanacloud_username -p appname_public > mysql_dump_201010161107.sql
gzip -v mysql_dump_201010161107.sql

Copy to database dump to local machine and then to EngineYard (since I don’t have ssh keys for EngineYard maintained directly on aptanacloud server)

From local dev machine:

scp aptanacloud_username@yourdomain.com:~/mysql_dump/mysql_dump_201010161107.sql.gz ~/Downloads
cd ~/Downloads
scp mysql_dump_201010161107.sql.gz appname_ey:~

have appname_ey setup as known SSH host

http://docs.engineyard.com/appcloud/guides/environments/ssh-keys-and-configuration#manage-keys

Load the mysqldump into MySQL database on Engine Yard

From EngineYard server (ssh):

cd ~
gunzip -v mysql_dump_201010161107.sql.gz
mysql -u deploy -p appdbname < mysql_dump_201010161107.sql
enter password

can be found /data/appname/current/config/database.yml on EngineYard server

Index the new data in Sphinx (if you use Sphinx)

From EngineYard server (ssh):

cd /data/appname/current/
rake thinking_sphinx:index RAILS_ENV=production

Verify data has been loaded correctly into DB

SSH to both EY AppCloud and Aptana Cloud servers and compare counts within database, which can be done via script/console for example:

ruby script/console production
Something.all.size
SomethingElse.all.size

Migrate the SSL certificate to the Engine Yard server (OPTIONAL)

Good overview guide, although does not include the re-keying step:

http://community.engineyard.com/discussions/problems/117-ssl-certificate-fails-tls-fqdn-cnames-csrs-all-the-tlas-makin-my-head-spin

First you need to generate the CSR file:

http://docs.engineyard.com/appcloud/guides/applications/ssl-certificates

Use the information from GoDaddy (or other SSL provider) for myrealdomain.com to get current Common Name, Organization and Organization Unit.  Need to use EXACT same ones when generating CSR on Engine Yard server.

Then re-key the SSL certificate at GoDaddy using the new CSR file:

http://help.godaddy.com/article/4976

Download the new SSL certificate to local dev machine.

Open the 2 files from GoDaddy and the certificate you generated on Engine Yard using your favorite editor (for example gedit).

Paste the SSL Certificate, SSL Certificate Key and the SSL chain in Engine Yard dashboard.

Attach the SSL cert to application via EY dashboard

Point the www.myrealdomain.com domain to EngineYard IP address

Via DNS provider (for example GoDaddy.com).  Make sure to use the lowest TTL (1/2 hour).

WE ARE LIVE!!!

Test your site under the www.myrealdomain.com

Delete the AptanaCloud site before Oct 31st, 2010 (from Aptana Cloud panel in Aptana Studio IDE)

And there you have it folks.

4 Comments