Migrating Ruby on Rails app from Heroku to OpenShift
OpenShift is Red Hat’s Platform-as-a-Service (PaaS) that allows developers to quickly develop, host, and scale applications in a cloud environment similar to Heroku. OpenShift also supports deploying of application with simple git push just like Heroku. OpenShift supports a variety of technologies through use of cartridges, including Java (Wildfly, JBossEAP, Tomcat), PHP, Node.js, Python, Perl, MySQL, PostgreSQL, MongoDB, Jenkins, Cron, and JBoss xPaaS Services (Fuse, BPM Suite, BRMS, Data Virtualization, Aerogear, and more).
Why OpenShift?
The free version of OpenShift, OpenShift Online, has many advantages over free tier of Heroku:
- If application is not accessed for an hour on Heroku, web dyno goes to sleep mode making the next request take up to 30 seconds to serve leading users to abandon the site visit. OpenShift’s idling time is 24 hours and, as of my personal experience, it takes around 10 seconds for next request to serve.
-
The free database tier on Heroku allows only 10,000 rows to be stored. There is no such limitation in OpenShift.
-
Heroku lacks persistent storage, its file system is read only and hence it doesn’t allow file upload from application, e.g. user avatars. OpenShift provides 1GB of persistent storage with free tier which can be used to store the assets.
-
OpenShift provides SSH access to control the application which is lacking in Heroku.
-
OpenShift also provides port-forwarding feature which lets one connect to the database using locally installed client.
-
OpenShift provides support for deployment hooks which can be used for running custom scripts before or after deployment.
Getting Started
Sign up for a free account of OpenShift at https://www.openshift.com
and set up the rhc
client tool as documented here.
Create the Ruby Application
Create the Ruby application by logging in to web console or via rhc
client tool by issuing following command:
1
$ rhc app create myapp ruby-2.0 postgresql-9.2
Here myapp is the name of the application, and ruby-2.0 and postgresql-9.2 are the cartridges. Once the application is created, it will output the git repository path. Take a note of this path as this would be used to push the code to OpenShift.
Setup git remote
Navigate to the existing rails application directory and add the OpenShift remote as below:
1
$ git remote add openshift ssh://[email protected]/~/git/myapp.git/
Now pull the remote changes by issuing following command:
1
$ git pull openshift master
It will result a conflict in config.ru
. Just abandon the content created by OpenShift. Below is the default config.ru
file for the reference which is generated by rails:
1
2
3
4
# This file is used by Rack-based servers to start the application.
require ::File.expand_path('../config/environment', __FILE__)
run Rails.application
Modify Gemfile and .gitignore
OpenShift uses an old version of bundler and hence if ruby version is specified in Gemfile, as shown below, it breaks.
1
2
3
4
5
source 'https://rubygems.org'
ruby '2.0.0' # Causes problem in OpenShift
gem 'rails', '4.0.8'
Also, as recommended by OpenShift, using their Ruby mirror http://mirror.ops.rhcloud.com/mirror/ruby/
can quicken the installation of gems.
And at last, if application was deployed on Heroku, it’s high chance that database.yml
was added to .gitignore
file as Heroku creates it’s own database.yml file during deployment. If it’s the case, remove the database.yml
line from the .gitignore
file.
Database configuration
Add following section in database.yml
file:
1
2
3
4
5
6
7
8
9
production:
adapter: postgresql
encoding: unicode
pool: 5
database: <%=ENV['OPENSHIFT_APP_NAME']%>
host: <%=ENV['$OPENSHIFT_POSTGRESQL_DB_HOST']%>
port: <%=ENV['$OPENSHIFT_POSTGRESQL_DB_PORT']%>
username: <%=ENV['OPENSHIFT_POSTGRESQL_DB_USERNAME']%>
password: <%=ENV['OPENSHIFT_POSTGRESQL_DB_PASSWORD']%>
Deployment hook
To run the database migrations, create a deployment hook by adding following lines to .openshift/action_hooks/deploy
file:
1
2
3
4
5
6
#!/bin/bash
pushd ${OPENSHIFT_REPO_DIR} > /dev/null
echo "Running migrations"
bundle exec rake db:migrate RAILS_ENV="production"
popd > /dev/null
In above script, pushd
will put the current working directory on the directory stack and switch to the directory path in the ${OPENSHIFT_REPO_DIR}
environment variable and popd
will retrieve the directory from the stack and set it again as the current one. This is because bundle should be executed in the application’s directory, and then come back to the original directory, in order not to disrupt anything that may be executed afterwards.
Publishing the application
To publish the application on OpenShift, just issue the git push command as below:
1
$ git push openshift master
Import database from Heroku
Importing and exporting PostgresSQL databases on Heroku is well documented here. Firstly, we need to add pgbackup addon to our Heroku app:
1
$ heroku addons:add pgbackups
To export the data from Heroku PostgresSQL database, create a new backup and use any number of download tools, such as curl or wget, to store the backup locally.
1
2
$ heroku pgbackups:capture
$ curl -o latest.dump `heroku pgbackups:url`
Restore database on OpenShift
To restore the database on OpenShift, we need to know the value of OPENSHIFT_POSTGRESQL_DB_USERNAME
environment variable. Issue following commands to get this information:
1
2
3
$ rhc ssh myapp
$ env| grep OPENSHIFT_POSTGRESQL_DB_USERNAME
$ exit
Take a note of the output and start port forwarding as below:
1
$ rhc port-forward myapp
It will give output similar to following:
1
2
3
4
5
6
7
8
9
10
11
12
Checking available ports ... done
Forwarding ports ...
To connect to a service running on OpenShift, use the Local address
Service Local OpenShift
---------- --------------- ---- ----------------
httpd 127.0.0.1:8080 => x.x.x.x:8080
postgresql 127.0.0.1:5432 => x.x.x.x:5432
ruby 127.0.0.1:32036 => x.x.x.x:32036
Press CTRL-C to terminate port forwarding
Now issue following commang to restore the database:
1
$ pg_restore –verbose –clean –no-acl –no-owner -h localhost -U OPENSHIFT_POSTGRESQL_DB_USERNAME -d myapp latest.dump
Replace OPENSHIFT_POSTGRESQL_DB_USERNAME
with the output from command at the start of this section.
And that’s it. Now visit the application and make sure everything is working as expected.
Epilogue
Heroku is a great platform for developing and deploying Rails application. I started looking for alternatives of Heroku because once I enabled rails_admin
gem in my application, Heroku was not able to serve the requests. I started getting intermittent application error. Once I migrated to OpenShift, these errors went away.