Blue-Green Deployment with CloudFoundry
Blue-Green Deployment with CloudFoundry
Blue-green deployments are a powerful technique to achieve zero-downtime deployments. With the CloudFoundry CLI, it is super easy to execute a blue-green deployment - even from a CI server. In a nutshell, a blue-green deployment spins up a whole new production environment with the new application version and once that is done, switches over the traffic from the old version to the new version. If you are unfamiliar with blue-green deployments be sure to read this article by Martin Fowler.
Deployment Configuration
The blue-green deployment I describe here has been setup in Codeship CI to continuously deploy updates of an application to CloudFoundry. It requires certain environment variables to be configured, namely:
CF_API
: URL to the CloudFoundry API, e.g.api.run.pivotal.io
CF_USER
: the username to authenticate withCF_PASSWORD
: the password to authenticate withCF_ORG
: the organization to deploy toCF_SPACE
: the space to deploy toCF_APPLICATION
: the name of the application to deployCF_DOMAIN
: the domain used to serve the applicationCF_HOSTNAME
: the hostname used to serve the application (optional)
The following sections describe the script in detail, if you are familiar with the CF CLI commands, you may see the full script at the end of this blog post.
Authenticate
It is necessary to authenticate with the CloudFoundry API from the CLI. Additionally, it is required to target the organization and space to which the application will be deployed:
cf api "${CF_API}"
cf auth "${CF_USER}" "${CF_PASSWORD}"
cf target -o "${CF_ORG}" -s "${CF_SPACE}"
It is recommended to add a new “deployment” user to your CloudFoundry space, as the credentials must be specified on the CI server.
Push Green
We can leverage the cf push
command to push the new version to CloudFoundry. Make sure to set common deployment options for your app in the mainfest.yml file, such as the amount of memory to be used by each instance.
Executing cf push
without further arguments will spin up a single instance of your application. If you leverage the auto-scaling capabilities of CloudFoundry, the number of instances would be reset to a single instance on each fresh deploy. Switching over the traffic would not be a good idea, right? So lets determine the current number of instances in use with the CloudFoundry CLI and push the green version with the same number of instances.
INSTANCES=$(cf app $CF_APPLICATION|grep ^instances|awk '{print $2}'|awk -F/ '{print $2}')
cf push "${CF_APPLICATION}-green" -i ${INSTANCES}
Next, we’ll need to map the existing route to the app to start handling traffic over to the fresh green version. Depending on whether the app runs with a hostname or not, we’ll need to execute different commands. Right after the route was added to the green version we can safely remove the route from the old version of the application. Users will then immediately have the new version of your application. Make sure to safely persist your sessions in a persistent service, as otherwise your users will lose their current session during the deployment.
if [ -z "CF_HOSTNAME" ]; then
cf map-route "${CF_APPLICATION}-green" ${CF_DOMAIN}
cf unmap-route "${CF_APPLICATION}" ${CF_DOMAIN}
else
cf map-route "${CF_APPLICATION}-green" ${CF_DOMAIN} -n "${CF_HOSTNAME}"
cf unmap-route "${CF_APPLICATION}" ${CF_DOMAIN} -n "${CF_HOSTNAME}"
fi
Remove Blue
As we now do not need the blue (i.e. old) version of the application anymore, we can safely remove the old application. After the application was removed, we’ll rename the ${CF_APPLICATION}-green
application to ${CF_APPLICATION}
in order to make sure this script updates the application properly on the next run.
cf delete "${CF_APPLICATION}" -f
cf rename "${CF_APPLICATION}-green" "${CF_APPLICATION}"
Ideally, you include some monitoring and smoke tests to make sure the new version handles the traffic correctly before removing the old version. That allows you to rollback in case of failure.
The Blue-Green Deployment Script for CloudFoundry
Merging the pieces, here is the full deployment script:
# authenticate
cf api "${CF_API}"
cf auth "${CF_USER}" "${CF_PASSWORD}"
cf target -o "${CF_ORG}" -s "${CF_SPACE}"
# push green
INSTANCES=$(cf app $CF_APPLICATION|grep ^instances|awk '{print $2}'|awk -F/ '{print $2}')
cf push "${CF_APPLICATION}-green" -i ${INSTANCES}
if [ -z "CF_HOSTNAME" ]; then
cf map-route "${CF_APPLICATION}-green" ${CF_DOMAIN}
cf unmap-route "${CF_APPLICATION}" ${CF_DOMAIN}
else
cf map-route "${CF_APPLICATION}-green" ${CF_DOMAIN} -n "${CF_HOSTNAME}"
cf unmap-route "${CF_APPLICATION}" ${CF_DOMAIN} -n "${CF_HOSTNAME}"
fi
# remove blue
cf delete "${CF_APPLICATION}" -f
cf rename "${CF_APPLICATION}-green" "${CF_APPLICATION}"
Note: When using Codeship to setup the pipeline make sure to use the
cf6
command instead ofcf
. See their documentation for more information.
Use this script as a baseline to define your own blue-green deployment pipeline for zero-downtime deployments on CloudFoundry.