Migrating to the Celadon Cedar-14 Stack from Bamboo

Last Updated: 31 March 2015

bamboo cedar

Table of Contents

The Cedar-14 stack is the default runtime stack on Heroku and is the successor to Bamboo. It includes support for multiple languages, flexible process types and HTTP/1.1 and WebSockets. This article outlines the decisions and steps required to perform a manual migration from Bamboo to Cedar-14.

This article demonstrates how to move an app from Bamboo to Cedar-14. If you’re already on Cedar, but want to upgrade to Cedar-14, check out this article.

Here’s a rough outline of the steps required:

  1. Decide whether to upgrade Ruby version and virtual machine used by app
  2. Prep local workstation for Ruby development
  3. Update app to run on Cedar-14
  4. Change app stack to Cedar-14

Major changes to an application, including stack migrations, should always be executed in a staging environment first. It’s highly recommended that you try pushing your app to a temporary Heroku app to test the migration process and the new environment, so that you can make any changes necessary to run on the new stack without affecting your production environment. Once your code runs cleanly, you can update the stack and push changes to your production app.

Prerequisites

Decide on Ruby version

Two flavors of Ruby were available on the Bamboo stack:

  • 1.8.7 REE
  • 1.9.2 MRI

Both these Ruby VMs have been EOL’ed by their maintainers (Phusion and Ruby Core, respectively). This means they are no longer receiving security updates and other critical maintenance. That makes Ruby 1.8.7 and 1.9.2 unsuited for use by production apps. When moving apps from Bamboo to Cedar-14, you highly recommend that you update to Ruby 2.0 or later. The guide below has details on how to perform this update.

Using a Ruby version that is EOL is dangerous and should not be done for production apps. EOL Ruby versions may contain known, exploitable security vulnerabilities that can expose app source code, secrets and user data. Production apps should use updated Ruby versions when running on Heroku.

If you choose to use an EOL version of Ruby when you migrate from Bamboo to Cedar-14, you cannot use the default Ruby buildpack because it does not support legacy Ruby versions. Instead, you must configure your app to use the correct legacy branch of the Ruby buildpack for the Ruby version you want to use.

For Ruby 1.8.7 use:

$ heroku buildpack:set https://github.com/heroku/heroku-buildpack-ruby#legacy-ruby-1.8.7

For Ruby 1.9.2 use:

$ heroku buildpack:set https://github.com/heroku/heroku-buildpack-ruby#legacy-ruby-1.9.2

Heroku will not update legacy branches of the Ruby buildpack. If you encounter problems or have suggestions for improvements to legacy buildpack versions, then please direct those to the fork in the Legacy Buildpacks GitHub Organization.

Getting app source code ready for Cedar-14

This section describes the changes you have to make to your app source code to make it ready to run on the Cedar-14 stack.

Get app source code

If, for any reason, you don’t have the source code for your Heroku app handy, you can fetch if from Heroku:

$ heroku git:clone --ssh-git -a app-name

Note that HTTP Git doesn’t work with apps on the Bamboo stack, so you need to use SSH git to clone.

Create git topic branch

Any changes made in preparation for migrating to Cedar should be stored in a separate cedar topic branch for better code organization.

$ git checkout -b cedar
Switched to a new branch 'cedar'

Commits made to this topic branch will stay independent from the production-ready master branch which contains the Bamboo-compatible codebase.

Configure and update to new Ruby

Depending on what choice of Ruby version you made for running on Cedar, you must now specify your desired version. A number of Ruby versions are supported on Cedar. The default version is 2.0.0, but in order to specify a legacy version, you should add the ruby declaration in your Gemfile. For instance, to use Ruby 1.8.7:

source "https://rubygems.org"
ruby "1.8.7"
# ...

The ruby declaration will only apply once the app is pushed to Cedar-14.

If you chose to upgrade from 1.8.7 or 1.9.2 to a newer version, you must now update your app to work on on the new Ruby version. Ruby versions are often not backwards compatible, so major changes may be required. Here are some resources to get you started:

Whatever Ruby version you specify in your Gemfile, you will likely need to have that Ruby version working on your local machine to run bundle install and to debug your app. You can use ruby-install and chruby to manage multiple Ruby versions on your development machine. Other alternatives for managing multiple Ruby versions are rvm and rbenv.

Specify dependencies

It’s important to create a Gemfile to specify the dependencies of your app. You can also use this Gemfile to install the necessary gems locally.

Use Bundler

If you’re already using Bundler to manage your gems on Bamboo then you won’t need to do anything new here. If you’re not, however, you’ll want to migrate to it and declare any gems that you need. Bamboo had pre-installed gems. On Cedar-14, all gems must be declared in the Gemfile.

Create Procfile

The Procfile is new to Cedar-14 and specifies what processes Heroku should run for an application. Apps that don’t use background workers on Bamboo should create a new Procfile at the application root with a single web process type.

web: bundle exec puma -C config/puma.rb

The above example uses the Puma web server. This is recommended web server for production Ruby apps.

worker is only a suggested process type. Non-web process types can have custom labels to more accurately reflect their role.

If the application is using Bamboo’s background worker support then a worker process type should be specified in the Procfile as well.

web: bundle exec puma -C config/puma.rb
worker: bundle exec rake jobs:work

The Procfile is not a Heroku-specific manifest. It can be used to orchestrate an application’s dyno formation during local development as well with Foreman, installed as part of the Heroku Toolbelt.

Variables saved in the .env file of a project directory will be added to the environment when run by Foreman. Set the RACK_ENV to development in your environment. Do not commit the .env file to source control it should only be used for local configuration.

$ echo "RACK_ENV=development" >>.env
$ echo ".env" >> .gitignore

You can run your app locally using the environment variables in your .env, the settings in your Procfile, and Foreman by running.

$ foreman start
10:01:59 web.1      | started with pid 3484
10:01:59 worker.1   | started with pid 3485

Once the application is running locally with Foreman commit the Procfile to the topic branch.

$ git add Procfile
$ git commit -a -m "Added Procfile to define app's process-formation on Heroku/Cedar"

Postgres

If the application utilizes a Postgres database, then first ensure that you install Postgres locally, and then ensure that you specify the pg gem in the Gemfile, since it is not auto-injected on the Cedar-14 stack.

gem 'pg'

The database credentials will still be configured automatically: at slug compile time, a config/database.yml that parses the DATABASE_URL from the environment will be written into the app.

The database.yml file is really an ERB file that is parsed at runtime to create the expected YAML-formatted file. To parse the file yourself run it through ERB before loading into YAML: YAML.load(ERB.new(File.read('config/database.yml')).result)

New Relic

Bamboo auto-injected the New Relic plugin and auto-created the config/newrelic.yml file. In Cedar-14, this is no longer the case.

If the application is using New Relic on Bamboo, manually add the newrelic_rpm gem to the application Gemfile.

gem 'newrelic_rpm'

And create the config/newrelic.yml file from New Relic’s template.

$ curl https://gist.githubusercontent.com/rwdaigle/2253296/raw/newrelic.yml > config/newrelic.yml

Sendgrid

Further documentation and support for other frameworks can be found in the Sendgrid documentation.

Sendgrid add-on configuration is also no longer automatically provisioned on Cedar-14. Rails applications relying on Sendgrid to deliver emails will need to add a mail initializer at config/initializers/mail.rb.

$ curl https://gist.githubusercontent.com/rwdaigle/1690653/raw/mail.rb > config/initializers/mail.rb

Memcache

If you are using memcache in your app you might be using a gem that requires c-bindings. The libraries to bind to memcache are not present by default on the Cedar-14 stack. To get around this you can use the Dalli gem or memcache-client both of which should work on all versions and implementations of Ruby and require no c-bindings. We recommend the Dalli gem, but it is not compatible with Rails 2.x. To change over you will need to add the new gem to your Gemfile.

gem "dalli"

If you were using the rails cache store you can configure Dalli to be used here by setting this value in your config/production.rb

config.cache_store = :dalli_store

If you are on Rails 2.x and have to use MemcacheClient first add it to your Gemfile.

gem 'memcache-client', :require => 'memcache'

Then you can set it to be your cache store:

config.cache_store = :mem_cache_store

If you were manually calling memcache clients you may need to replace calls from other libraries to call to Dalli::Client for Dalli, or MemCache for memcache-client.

Commit dependencies

At this point there may be several changes made to the application source to ready it for deployment to the Cedar stack, including modified gem dependencies.

Run bundler to install any newly required gems.

$ bundle install
Fetching source index for https://rubygems.org/
Using rake (0.8.7)
...

Add any new files to git.

$ git add config/newrelic.yml

Commit changes.

$ git commit -a -m "Modified application dependencies for Heroku/Cedar compatibility"

Create Cedar-14 app

Before you push directly to your bamboo application to change it’s stack, it’s recommended that you first test this out on a Cedar-14 app that is not getting production traffic. Naming the remote git repository heroku-cedar will differentiate between the Bamboo and Cedar versions of the application.

$ heroku create --remote heroku-cedar cedar-app
Creating cedar-app... done, stack is cedar-14
http://cedar-app.herokuapp.com/ | git@heroku.com:cedar-app.git
Git remote heroku-cedar added

Deploy to your Cedar Staging App

Deploying the modified codebase to the Cedar application will not affect the currently running app on Bamboo. It will merely stage the application and provide the opportunity to verify functionality.

Push the Cedar-compatible source from the cedar topic branch to the master branch of the heroku-cedar remote repository to deploy.

$ git push heroku-cedar cedar:master
Counting objects: 67, done.
...
-----> Heroku receiving push
-----> Rails app detected
...

Once the app is deployed, you should verify that it is working correctly on the Cedar-14 stack, and if not, make any required changes.

Upgrading the production app to Cedar

Once you have verified that the updated source code works correctly on the Cedar staging app, you are ready to update the production app from Bamboo to Cedar-14.

First, set stack on the production app to Cedar:

$ heroku stack:set cedar-14
stack set, next release on oregon-dev will use cedar-14
Run `git push heroku master` to create a new release on cedar-14

This does not immediately change the runtime stack of the app, but the next release created will be deployed on Cedar. To create a release, merge the cedar branch you have been working on, and push to your production app:

$ git checkout master
$ git merge cedar
$ git push heroku master

Your production app is now running on Cedar-14, and you should verify that everything is working as expected.

The migration is now complete.

Reverting to Bamboo

If the production app is not working after you changed the stack from Bamboo to Cedar-14, you can temporarily revert back to the Bamboo stack until you debug and resolve the issue. Set the stack to Bamboo and push the Git commit revision that was successfully running on Bamboo before you started the process of switching to Cedar-14:

$ heroku stack:set bamboo-ree-1.8.7   # Note: bamboo-mri-1.9.2 for 1.9.2 apps
...
$ git push heroku <commit-id>:master

Notes

Timezones

It should be noted that the system timezone on Bamboo dynos is Pacific Time (US & Canada) whereas on Cedar-14 dynos it is UTC. Any logic relying on non-normalized system time should be updated to account for this disparity.

File compression

On Bamboo, responses were automatically compressed using gzip. On Cedar-14 no such compression is done on your behalf. To add response compression to your application use middleware such as Rack::Deflater.

DNS

You should check that your Bamboo apps are configured to use the latest routing stack.