This post will explain how to deploy a Java application to CloudFoundry using Gradle.

But let’s step back for a moment to see what a blue/green deployment means:

  1. You run two copies of your production environment („blue“ and „green“).
  2. You route all traffic to the active blue environment by mapping production URLs to it.
  3. You deploy and test any changes to the application in the green environment.
  4. Then you switch by mapping URLs onto green and unmapping them from blue. Green becomes active, blue is inactive.

Prepare your build script

Performing blue/green deployments using the CLI is pretty neat but it’s not automated. It requires to have the CLI tools installed. So let’s use something that you need anyway as your build tool. I stick to Gradle and the CloudFoundry Gradle Plugin as it allows to define more easily conditional configuration.

The most basic configuration requires to include the CloudFoundry Gradle plugin and to configure it in your build.gradle file:

buildscript {
  …
  dependencies {
  …
    classpath('org.cloudfoundry:cf-gradle-plugin:1.1.3')
  }
}

apply plugin: 'cloudfoundry'

cloudfoundry {
  application = "my-application"
  domain = "cfapps.io"
  host = "my-application"
  variants = ['-blue', '-green']
}

This setup gives you the possibility to run

gradle build cfDeploy cfSwapDeployed

to build, deploy, and perform the blue/green switch of your application.

The plugin will scan for applications and always deploy to the inactive variant. It will also create applications on CloudFoundry if they do not exist.

Conditional Blue/Green Deployment

In some cases there are stages in your environment that do not have blue/green deployment set up, maybe because you don’t need them. These cases require adjustments to your build which isn’t always great. So let’s take blue/green deployments to the next level by using Groovy power.

The piece which maps nicely to a stage is called in CloudFoundry a space. Spaces are groups for multiple application instances. It does not matter whether a space contains only one or multiple applications, even of a different kind. That said we need to create a link between space and stage including the configuration differences.

apply plugin: 'cloudfoundry'

cloudfoundry {
  application = "my-application"
  domain = "cfapps.io"
  host = "my-application"
  variants = ['-blue', '-green']
}

task deploy(dependsOn: [build]) {
  description = 'Deploys the project to a Cloud Foundry space (specified with -Pspace=<targetspace>)'
  dependsOn 'cfDeploy'

  if(project.getProperty(TARGET_SPACE) == 'production') {
    // only needed when variants are set up.
    dependsOn 'cfSwapDeployed'
  }
}

if (project.hasProperty("space")) {
  cloudfoundry {
    space = project.getProperty("space")
    host = "my-application-${space}"
    uris = (space == "production" ? ["my-application.cfapps.io"] : [ "$application-${space}.cfapps.io" ])
  }

  if (space == "production") {
    cloudfoundry {
      variants = ['-blue', '-green']
    }
  }
}

The script is now conditional. It has blue/green variants set up only for the production space. The magic happens in the newly added deploy task which requires us to start the script a bit differently:

gradle build deploy -Pspace=production

deploy depends on build and performs then the deployment. Blue/green deployment is only activated for the production space. Any other space leads to a regular, single-instance/single-variant deployment.

The space parameter is now required, but it’s a good thing. Parameters do not always require to be provided from the command line. Parameters for Gradle builds can also be taken from environment variables (ORG_GRADLE_PROJECT_space=...) or the gradle.properties file, which may be located within the repository. Or even determined by the build script itself.

Level 9000

Let’s take Blue/Green deployments to another level. When working with Git, there’s always a leading master repository. Builds usually run from there and are sometimes deployed to a stage. How about not only having blue/green deployments for production but also use this tooling to feed all other stages?

Let’s add TravisCI to the stack. Travis builds add a variety of environment variables to the build. One of the more interesting variables could be the current branch. master is known to be the production-ready branch. So we could define, all successful builds on master get deployed to production, build on staging branches, prefixed with staging- get deployed into a staging space.

def travisBranch = System.getenv().get("TRAVIS_BRANCH")

if (!project.hasProperty("space") && travisBranch != null) {
  if (travisBranch =~ '^master$') {
    project.ext.setProperty("space", "production")
  } else if (travisBranch =~ '^stage-.*') {
    project.ext.setProperty("space", "staging")
  }
}

Adding this snippet to your build.gradle file will deploy builds of stage- prefixed branches to the staging space and you’re no longer required to specify the space property for the build, just run

gradle build deploy in your TravisCI build.

You can get the code from Github at mp911de/blue-green-demo-application. It contains the full build file with some cleanups.

Fast Rollback

Blue/green deployments have even more benefits than just zero-downtime. A blue/green setup provides an infrastructure to roll back easily at any given time you notice thet new deployment should be rolled back. The inactive blue variant is running and known to be working. To roll back, map the production URLs from the active green to the inactive blue variant and remove the production URL mapping from the blue variant. The rollback procedure switches green to inactive and blue to active again.

You can get the code from Github at mp911de/blue-green-demo-application. It contains the full build file with some cleanups.

This script is derived from the Sagan reference app and Pivotal CLA which are both deployed with zero dowtime to Pivotal CloudFoundry using Github and TravisCI.