Heroku DevOps with Heroku Builder

Heroku Builder can be leveraged two ways to improve your development and deploy workflow on Heroku: Config Variable management, and full app setup and management. As it’s far more likely you have an existing application, let’s start by looking at Config Variable management.

Before we begin, let’s install Heroku Builder. Add it to your Gemfile:

gem 'heroku_builder'

And install:

$ bundle install

Now, generated a configuration file (it will be placed in config/heroku.yml):

$ rake builder:init

Open up the config/heroku.yml file, and take a look. The contents will look something like this:

staging:
  app:
    name: my-heroku-app-name-staging
    git_branch: staging
  config_vars: []
  addons: []
  resources:
    web:
      count: 1
      type: Free

production:
  app:
    name: my-heroku-app-name
    git_branch: master
  config_vars: []
  addons: []
  resources:
    web:
      count: 1
      type: Free

As we’re only managing Config Variables, remove addons and resources. You should end up with something like:

staging:
  app:
    name: my-heroku-app-name-staging
    git_branch: staging
  config_vars: []

production:
  app:
    name: my-heroku-app-name
    git_branch: master
  config_vars: []

Update the staging app name and production app name to be that of your staging and production Heroku applications. If you don’t use ‘staging’ and ‘master’ for your staging and production branches, you should also update the git branches to match yours. If the staging application is called ‘foo-staging’ and the production application is called ‘foo’, your config/heroku.yml file should look something like this:

staging:
  app:
    name: foo-staging
    git_branch: staging
  config_vars: []

production:
  app:
    name: foo
    git_branch: master
  config_vars: []

Now let’s look at how you might use Heroku Builder to implement a feature flag. As a silly example, let’s look at using a feature flag to redirect to the index view rather than the show view after an object is created:

class BarsController < ApplicationController
  ...
  def create
    @bar = Bar.new(bar_params)

    if @bar.save
      redirect_to redirect_path
    else
      render :new, :status => :unprocessable_entity
    end
  end

  ...

  private

  def redirect_to_path
    if ENV.fetch('REDIRECT_TO_INDEX', 'false').match(/true|on/)
      bars_path
    else
      bar_path
    end
  end
end

So now we have our feature completed, and tests (not included here) written, as well as had the code reviewed. Let’s make sure our feature flag is set in the heroku.yml:

staging:
  app:
    name: foo-staging
    git_branch: staging
  config_vars:
    - REDIRECT_TO_INDEX: on

production:
  app:
    name: foo
    git_branch: master
  config_vars:
    - REDIRECT_TO_INDEX: on

The advantage to keeping environment configuration in source code is twofold. First, it allows configuration changes to be reviewed as part of the pull request development flow. The second advantage is that you can couple configuration changes with the code that requires it. When you deploy your code, you also deploy the configuration that code requires.

Assuming this code has been merged into our staging branch, let’s deploy it!

$ rake builder:staging:apply

This will set the Heroku Config Variables and deploy code from the head of your staging branch to the foo-staging app on Heroku. Be aware that prior to pushing code to Heroku (using git push), Heroku Builder will pull changes from the remote branch you’ve defined in the config file.

When it’s ready, deploying to production follows a similar pattern:

$ rake builder:production:apply

We can still do a bit of cleanup on our config/heroku.yml file to DRY it up. Let’s use YAML node anchors to let us define common configuration:

config_defaults: &config_defaults
  REDIRECT_TO_SHOW: on
  SUPER_SECRET_KEY: <%= ENV['LOCAL_SECRET_KEY'] %>

staging:
  app:
    name: foo-staging
    git_branch: staging
  config_vars:
    <<: *config_defaults

production:
  app:
    name: foo
    git_branch: master
  config_vars:
    <<: *config_defaults

Now as our list of Config Variables grows, we don’t need to update them under each environment, we can set the global ones under config_defaults and optionally override them in a particular environment. ERB tags are evaluated in the YAML file, so secret credentials can be stored locally without checking them into source control.

Hopefully this has given you a little insight into Heroku Builder and how you can use it to include project configuration in your project code base. In the next post, we’ll look at using Heroku Builder to create a multi-environment application on Heroku.

This entry was posted in deployment, dev ops, Heroku, ruby. Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *