Previous parts of this blog post series have provided an overview of Cloud Foundry from a number of different perspectives; including the high-level concepts, vendor lock-in, and the Pivotal Web Services marketplace services. In this part, we'll look at how Cloud Foundry makes it trivial to perform zero-downtime deployments.
As a quick introduction to this topic, imagine that you have a Java web application running somewhere. A simple way to upgrade that application to a new version is to stop the application, update the relevant deployment artifacts (e.g. a .JAR or .WAR file), and then restart it. Some web application servers provide support for hot-swapping applications, but the principle is the same. Although this works, users of your application are likely to encounter downtime because the application will be unavailable for a short period of time. Over the years, we've created a number of techniques to deal with this issue, one of the most popular being Blue-Green Deployments, where a (physical or virtual) router is used to switch traffic from one running instance of your application to another. Although this might sound like an advanced technique, tools like Cloud Foundry make this feasible for teams of any size to achieve.
- Resolve dependencies.
- Initialize build directories, increment build number, etc.
- Compile code (production and tests).
- Run unit/class tests.
- Run integration/component tests.
- Create deployment artifacts (e.g. .WAR files).
- Push the API Application to Pivotal Web Services.
- Run e2e/system tests on the API Application.
- Push the Web Application to Pivotal Web Services.
- Run e2e/system tests on the Web Application.
- Make the API Application live.
- Make the Web Application live.
- Generate and publish new software architecture diagrams and documentation.
Push Applications to Pivotal Web Services
Assuming that the build and tests were successful, the build process will push each of the API and Web Applications to Pivotal Web Services. The Cloud Foundry command line interface is installed on the build server, and the build script simply uses the "cf push" command to push the .WAR files. The "--no-start" flag is used so that the application is pushed, but not started, and this is done so that application environment variables (e.g. configuration) can be set using the "cf env" command. Once the configuration has been set, the "cf scale" command is used to set the desired number of instances and RAM, before actually starting the application. At this point, the applications are running but only accessible using a temporary URL that includes the build number (e.g. "https://structurizr-web-123.cfapps.io").
With the applications running, the build script can now run a series of end-to-end tests (a mixture of "smoke tests" and system tests), in order to verify that the new versions of the applications are running as expected. These tests include scenarios such as signing in, getting/putting software architecture models, etc.
Making the New Versions Live
If the end-to-end tests pass, the next step is to make these new versions of the applications live. This involves using the Cloud Foundry command line interface to map the live URL to the new versions of the applications ("cf map-route"), while removing it from the old versions ("cf unmap-route"). This process makes use of the Cloud Foundry router, which allows you to configure the URLs that are used to access running applications. If everything is successful, finally, the previous versions of the applications are deleted. The whole build process takes less than 10 minutes. Here is some more information about how to do Blue-Green Deployments if you're interested.
The process of switching the live URLs to the new versions of the applications is what allows a zero-downtime deployment. The small caveat here is that any information that only resides in the memory space of the old versions of the applications is lost, of course. As an example, if HTTP session state is only stored in memory, users will be signed out once their requests are directed to a new instance of Apache Tomcat. There are a number of ways to deal with this problem (including session replication), but Structurizr makes use of Spring Session in conjunction with Redis, to instead store HTTP session information outside of the Apache Tomcat server instances, so that session information is retained during the deployment process.
And that's it ... a zero-downtime deployment process using nothing more than the Cloud Foundry command line interface. In part 5, I'll briefly discuss how to customize the deployment environment using Java buildpacks. Comments or questions? Tweet me at @simonbrown.