CloudFoundry Rails Deployment

Code Climate Build Status Test Coverage

cf-deploy is the tool you use to deploy your rails app to CloudFoundry providers like Pivotal. It works with rails 4.2 and older versions as far back as rails 3.

rake cf:deploy:production

cf-deploy makes it easy to:

  • Deploy your rails app with one rake command
  • Implement blue/green deployments
  • Run asset precompiles before deploying your app
  • Automate your rails deploys using jenkins, circle-ci, codeship

Getting Started

The functionality comes in the shape of generated rake tasks. You require this gem in your Rakefile and call the .rake_tasks! setup method.

require 'cf-deploy'
CF::Deploy.rake_tasks!

By default tasks will be created for each manifest in your manifests/ folder. If you have a staging.yml and production.yml you can now run the following commands:

bundle exec rake cf:deploy:staging
bundle exec rake cf:deploy:production

You now have rake tasks that run cf push -f manifests/staging.yml and cf push -f manifests/production.yml. Things start to get more exciting when you define your environments in your Rakefile along with their task dependencies just like normal rake task syntax.

require 'cf-deploy'

CF::Deploy.rake_tasks! do
  environment staging: 'assets:precompile'
  environment production: [:clean, 'assets:precompile']
end

Now when running cf:deploy:staging and cf:deploy:production the prerequisite tasks will be run first.

The next thing to talk about is route mapping. You can define a route in a an environment block like so:

require 'cf-deploy'

CF::Deploy.rake_tasks! do
  environment staging: 'assets:precompile' do
    route 'example.com', 'staging'
  end

  environment production: [:clean, 'assets:precompile'] do
    route 'example.com'
    route 'example.com', 'www'
    route 'example.com', 'www-origin'
    route 'example.com', 'admin'
  end
end

As soon as an environment with routes is pushed successfully each of it's routes will be mapped to all the applications defined in the environment's manifest.

And then things get super interesting when you start talking blue/green.

What is blue/green deployment?

Simply put, blue/green deployment allows you to deploy a new version of your app, test it on a private URL and then direct your traffic to the new version when you are ready.

You have two applications for one environment, say production. One version is called green, the other is blue. The first time you deploy your environment either green or blue can be deployed. Thereafter, any changes you want to deploy you deploy to the color that doesn't have your production domain pointed at it. You test it on a private URL and then when you're happy you flip your domain to point at that. If something then goes wrong you can then flip your domain back to the last working version.

This gem provides rake tasks for you to deploy using this methodology as well as the standard single app deployment process on a CloudFoundry provider.

An example of blue/green

Examples always help and this example is probably the most common use case. You might have a straight forward deployment for staging but use the blue/green strategy for production. Here is what your Rakefile might look like:

require 'cf-deploy'

CF::Deploy.rake_tasks! do
  environment staging: 'assets:precompile'

  environment production: 'assets:precompile' do
    route 'example-app.io', flip: true
    route 'example-app.io', 'www', flip: true
    route 'example-app.io', 'www-origin', flip: true

    route 'example-app.io', 'blue', blue: true
    route 'example-app.io', 'green', green: true
  end
end

You should also have three manifests defined:

  • manifests/staging.yml
  • manifests/production_blue.yml
  • manifests/production_green.yml

When you run cf:deploy:production for the first time (assuming neither production_blue.yml or production_green.yml are deployed) your blue app will be deployed and route setup.

Running cf:deploy:production thereafter will deploy which ever version isn't currently deployed. Your route(s) will not be mapped automatically this time. Nows your chance to checkout your new deployment using an alternate route. When you're happy and want to map your route across run:

bundle exec rake cf:deploy:production:flip

Installation

You need the cf command installed already. Grab the latest release from the CloudFoundry CLI repo on github.

You then need to install this gem in your project's Gemfile:

gem 'cf-deploy', '0.1.4'

Defining CloudFoundry details in your Rakefile

You can configure some or all of your CloudFoundry details when calling CF::Deploy.rake_tasks!.

require 'cf-deploy'

CF::Deploy.rake_tasks! do
  api 'api.run.pivotal.io'
  username '[email protected]'
  password 'SOMETHING'
  organisation 'Made'
  space 'development'

  environment staging: 'assets:precompile'

  environment production: 'assets:precompile' do
    route 'yourwebsite.com', 'www', flip: true
  end
end

All are optional. If you do not provide any you will be prompted when running the rake tasks.

Defining CloudFoundry details using ENV variables

Instead of defining your CloudFoundry login details in your Rakefile and committing them to your code repository you can instead provide them using ENV variables on your command line:

export CF_API=api.run.pivotal.io
export [email protected]
export CF_PASSWORD=SOMETHING
export CF_ORG=Made
export CF_SPACE=development

Now you can run any of the cf-deploy rake tasks providing you have called CF::Deploy.rake_tasks! in your Rakefile.

Commands

Deploying an environment

If you defined a staging environment in your Rakefile the following task will have been created:

bundle exec rake cf:deploy:staging

Run this to deploy out your staging environment.

Any environment you define will have a task created named cf:deploy:#{env}.

Deploy the next blue/green environment

If you have defined CloudFoundry manifest files matching manifests/*_blue.yml and manifests/*_green.yml you will be able to call rake cf:deploy:* without the _blue or _green. For example with production_blue.yml and production_green.yml you can call the following:

bundle exec rake cf:deploy:production

Running the deploy task for an env with blue and green manifests will trigger a lookup to see which env is currently deployed. The task will then start deploying the other production color, so if green is currently deployed then blue will be deployed. If neither is currently deployed, blue will be deployed first.

Once deployed your routing will still be pointing to the previous deployment. If you run the same task again, the same environment will be deployed. That is if green was deployed, and then you run the task, blue will be deployed, if you run the task again, blue will be deployed again. This is because we work out the current deployment based on where your routes are pointing and since the deploy command for blue green environments doesn't map routes the current deployment will not change.

First time proviso

This isn't the case for a first time deploy. The first time you deploy your blue environment will be deployed and any defined routes will be mapped to all apps defined in your blue manifest.

Switch routes over to new environment

In order to flip your routes from blue to green or vice-versa you need to run the following task.

bundle exec rake cf:deploy:production:flip

This will go ahead and map routes to whatever color the routes aren't mapped to and then unmap the other color. At this point your new production will be deployed and live.

Turn off idle app

Once your new production has been flipped you may want to turn off your idle application. There is a task for this too:

bundle exec rake cf:deploy:production:stop_idle

Credits

made

Developed and maintained by Made Tech. Key contributions:

License

Copyright © 2014 Made Tech Ltd. It is free software, and may be redistributed under the terms specified in the MIT-LICENSE file.