Skip to main content

Mobomo webinars-now on demand! | learn more.

Recently, I deployed a client project to Heroku, using the Heroku instance as an internal demo server. The project is based on Ruby 2.0 and Rails 4. I was surprised to find that the deployment to Heroku is not as smooth as it was before.

Here are the tricks and tips I learned to help you overcome the learning curve and get your Rails 4 apps deployed to Heroku.

Rails 4 Specific Tricks

  • Heroku forces you to specify your ruby version in Gemfile, it's supported by bundler from 1.2 version, so just add below line into your Gemfile:
#specify ruby version to enable the deploy to Heroku instance. ruby '2.0.0' 

Rails4 gets rid of plugin system. In order to use features such as static asset serving and logging on Heroku, you should add the following gems to your Gemfile:

gem 'rails_log_stdout',           github: 'Heroku/rails_log_stdout' gem 'rails3_serve_static_assets', github: 'Heroku/rails3_serve_static_assets' 

Use puma as the web server, you want to add a Procfile file and add below line in it:

web: bundle exec puma -p $PORT 

Below http basic auth doesn't work as what I did before for non-rails4 app on Heroku.

config.middleware.insert_after(::Rack::Lock, "::Rack::Auth::Basic", "Production") do |u, p|   [u, p] == [USER, PASSWORD] end 
# Error message when pushing to Heroku... -----> Preparing app for Rails asset pipeline        Running: rake assets:precompile        rake aborted!        No such middleware to insert after: Rack::Lock 

Actually, Rails 4 is thread safe by default, you do not have the overhead of including the Rack::Lock middleware in each request. So just use Rack::Auth::Basic directly as there is no Rack::Lock middleware any more when you using a web server such as puma:

config.middleware.use '::Rack::Auth::Basic' do |u, p|   [u, p] == [USER, PASSWORD] end 

Heroku Related Tips

In my case, I need to transfer PG database between local and Heroku. Firstly, I need to find the URL to my db on Heroku:

$ heroku config:get DATABASE_URL postgres://bla:sth@ec2-17-21-12-11.compute-1.amazonaws.com:5432/123 

Then transfer from the Heroku db to your local db (switch -t to and -f from versus):

$ heroku plugins:install https://github.com/ddollar/heroku-pg-transfer $ heroku pg:transfer -t postgres://localhost/dbname -f postgres://bla:sth@ec2-17-21-12-11.compute-1.amazonaws.com:5432/123 

Since the heroku-pg-transfer tool utilizes postgres's native pg_dump facility it is a much more predictable and resilient tool. Check out a related blog for more details.

There is another needs in my case, I have to deploy development branch to Heroku, but Heroku default is to deploy master branch to their instance, use below command to specify a branch for deployment.

# deploy a specific branch to Heroku git push heroku other-barnch:master 

Resources

https://devcenter.heroku.com/articles/rails4
http://blog.remarkablelabs.com/2012/12/rails-4-is-thread-safe-by-default-rails-4-countdown-to-2013

Categories
Author

I'm a huge fan of Heroku. I mean I'm a huge fan of Heroku. Their platform is much closer to exactly how I would want things to work than I ever thought I would get. However in the past few weeks Heroku has had a number of serious outages...enough to the point where I started thinking that maybe we needed to start working out a backup plan for when our various Heroku-hosted applications were down. That's when I realized a big problem, and it's not just a problem with Heroku but with any Platform-as-a-Service:

The moment you need to have failovers or fallbacks for a PaaS app is the moment that it loses 100% of its value.

Think about it: to have a backup for a Heroku app, you're going to need to have a mirror of your application (and likely its database as well) running on separate architecture. You will then need to (in the best case) set up some kind of proxy in front of Heroku that can detect failures and automatically swap over to your backup architecture, or (in the easiest case) have the backup architecture up and ready to go and be able to flip a switch and use it.

The backup architecture is obviously going to have to be somewhere else (preferrably not on EC2) to maximize the chance that it will be up when Heroku goes down which leaves you with the glaring problem that if you have to mirror your apps architecture on another platform, all of the ease of deployment and worry-free infrastructure evaporates. This leaves you with two options:

  1. Put your faith in your PaaS provider and figure that they will (in general) be able to do a better job of keeping your site up than you could without hiring a team of devops engineers.
  2. Scrap PaaS entirely and go it on your own.

A "PaaS with fallback" simply doesn't work because it's easier to mirror your architecture across multiple platforms than you control than it is to mirror it from a managed PaaS to a platform you control.

Don't Panic

Note that I'm not telling anyone to abandon Heroku or the PaaS concept; quite the opposite. My personal decision is to take choice #1 and trust that while Heroku may have the occasional hiccup (or full-on nosedive) they are still providing high levels of uptime and a developer experience that is simply unmatched.

Heroku has done a great job of innovating the developer experience for deploying web applications, but what they need to do next is work on innovating platform architecture to be more robust and reliable than any other hosting provider. Heroku should be spread across multiple EC2 availability zones as a bare minimum and in the long run should even spill over into other cloud providers when necessary.

If they can nail reliability the way they've nailed ease-of-use even the most skeptical of developers would have to take a look. If they could say with confidence "Your app will be up even if all of EC2 is down" that's yet another powerful selling point for an already powerful system.

The Third Option

There is actually a third option: if your PaaS is available as open source then you will be able to run their architecture on someone else's systems, giving you a backup that is at least a middleground between the ease of PaaS and the reliability of Do-it-Yourself. The two current players in this arena are Cloud Foundry and OpenShift.

While Heroku currently has them beat for developer experience (in my opinion) and the addon ecosystem makes everything just oh-so-easy, it might be worth exploring these as a potential middleground. Of course, if Heroku would open source their architecture (or even a way to simply get an app configured for Heroku up and running on a third-party system with little to no hassle) that would be great as well.

In the end I remain a die-hard fan of PaaS. It's simply amazing that, merely by running a single command and pushing to a git repo, I can have a production environment for whatever I'm toying with available in seconds. After the past few weeks, however, I am spending a little more time worrying about whether those production environments will be up and running when I need them to be. And that's the problem with PaaS.

Categories
Author

There have been several methods to deploy an Ruby on Rails application. Until recently, the most popular is to run Apache and proxy balance to multiple Mongrel instances that are running simultaneously.

Passenger, developed by Phusion, is the new kid entering the Rails deployment market. Everyone has been using the Apache PHP module for years and deploying a PHP applications is a snap. This has not been possible with Rails until Passenger. It is extremely easy, and you can still use Capistrano to automate deployment. I will show you how I get it to work on Ubuntu.

sudo gem install passenger passenger-install-apache2-module 

Update: Phusion just released Passenger 2.0 RC 1. You can download this version and do gem install passenger-1.9.0.gem instead. But I had an error compiling it on Mac OS X Leopard. hongli pointed me to use the version from GitHub that has the fix and it works like a charm. Thanks Phusion guys.

To get it from GitHub:

git clone git://github.com/FooBarWidget/passenger.git 

I created a separate /etc/apache2/mods-available/passenger.load and it contains the following:

For 1.0.5:

LoadModule passenger_module /usr/local/lib/ruby/gems/1.8/gems/passenger-1.0.5/ext/apache2/mod_passenger.so RailsSpawnServer /usr/local/lib/ruby/gems/1.8/gems/passenger-1.0.5/bin/passenger-spawn-server RailsRuby /usr/local/bin/ruby 

For the GitHub version (Of course the path will look different depending on where your git clone is):

LoadModule passenger_module /home/rlaw/downloads/passenger/ext/apache2/mod_passenger.so PassengerRoot /home/rlaw/downloads/passenger PassengerRuby /usr/local/bin/ruby 

I then tell Apache to load the Passenger module:

a2enmod passenger 

Now, I create a virtual host configuration for one of my Rails app in /etc/apache2/sites-available/myapp:

<VirtualHost *:80>   ServerAdmin webmaster@myapp.com   ServerName myapp.com    DocumentRoot /home/deploy/apps/myapp/current/public    <Directory /home/deploy/apps/myapp/current/public>     Options FollowSymLinks     AllowOverride None     Order allow,deny     Allow from all   </Directory>    LogLevel warn   ErrorLog /var/log/apache2/myapp/error.log   CustomLog /var/log/apache2/myapp/access.log combined </VirtualHost> 

I then restart Apache:

sudo /etc/init.d/apache2 reload 

When you need to restart your application because you have changed some code that Rails does not reload in production, just do:

touch /home/deploy/apps/myapp/current/tmp/restart.txt 

I have not tried their Ruby Enterprise Edition yet. They claim substantial memory and speed improvement at RailsConf 2008, so it will be interesting to see how that develops.

Categories
Author
1
Subscribe to Deployment