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:
- 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.
- 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
- 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.
- 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.
- 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.
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:
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.
Thank you so much for posting this, and thank you twice as much for your patronage.
We’ve worked hard over the years to earn Rails developers’ trust. Seeing that hard work pay off tells us we’ve been doing the right things!
I’m very happy to hear that you’re enjoying your service. Feel free to contact me if there’s anything I can help you with.
We will be doing the actual migration this Saturday. Wish us luck.
[...] This post was mentioned on Twitter by jeremyhamel, Jana Boruta. Jana Boruta said: Really awesome blog post about a customer migrating from Aptana Cloud to Engine Yard AppCloud http://bit.ly/91UyZ6 [...]
We have successfully migrated over to Engine Yard AppCloud. It was nice and easy following the steps above.