Buildpacks are at the core of the Cloud Foundry architecture and we’ve recently made significant improvements to the Cloud Foundry Java Buildpack. As the lead developer of the buildpack, I’d like to give you some insight into the design principles behind it, how to use, configure, and extend it, and what the future holds.
Design Principles
The primary objective of the Java buildpack is to be the easiest way to run a Java application.1 The word easiest can mean a lot of things, but to me it means that a developer can push an application and have an “it just works™” experience. An application developer shouldn’t have to mess about with details like memory settings or configuring the container to work with a bound service. Much of what the buildpack does is inferring these and other details automatically, which saves developers time and effort.
One secondary objective of the Java buildpack is to be easily extensible. There’s no way that the Cloud Foundry Java Experience team can have the expertise or time to support every container, JRE, and service integration. Instead, we designed the buildpack such that others can extend what exists and integrate upstream changes with minimum fuss. This design also allows us to integrate community contributions (which we love!) back into the code base easily.
The other secondary objective of the Java buildpack is to be aggressively up-to-date with security fixes by default. Many application deployment strategies require developers or operators to notice that a security fix has been released, and then change their application or runtime environment in some way to become safe. Developers and operators no longer have to worry about this for the infrastructure dependencies managed by the buildpack (e.g. Java, Tomcat, Groovy). The buildpack chooses the latest and safest versions of these dependencies each time an application is pushed.2 If you’re concerned that this model doesn’t suit your application, don’t worry, it’s configurable.
Using the Buildpack
As of today, the Java Buildpack is available to any application running on the Pivotal CF hosted service. The version available by default will be nice and stable, gaining features as they become mature, but at the same time staying up to date with infrastructure dependency releases. If you’re the kind of person that wants to live on the edge, you can specify the latest version of the buildpack when pushing3:
cf push --buildpack https://github.com/cloudfoundry/java-buildpack
The buildpack’s documentation describes what kinds of applications can be run. Today that list consists of web applications (including Grails), Java main()
applications, Groovy applications, and Play Framework applications.
Configuring the Buildpack
It might initially come as a shock, but the general recommendation is that developers should not configure the environment that an application uses when running in Cloud Foundry. Now, I understand that this is a scary statement for most Java developers, but give it a chance. We’ve put a lot of effort into making the buildpack “just work”4. If your application doesn’t work out of the box, please let us know and we’ll try to improve the buildpack so that it does.
If, after giving the no-configuration recommendation a go, you decide that your application requires custom configuration, it’s time to slip into the operator role. Configuration of the buildpack is managed centrally, and is composed of a collection of YAML files corresponding to the different components contained in the buildpack. To change this configuration you fork the buildpack5, edit the configuration and use the new repository when pushing your application6. A buildpack fork should be viewed as the configuration for a class of applications rather than the configuration for a particular application. That class might have only a single application in it, but if you find yourself creating a number of forks, it’s wise to step back and re-evaluate the situation.
A guiding design principle is that a developer can expect a push to “just work” because it is the responsibility of the operator to provide a buildpack (default or custom) that ensures this is true.
Extending the Buildpack
The buildpack is comprised of a bunch of coordination functionality and a collection of containers, JREs and frameworks. To add to this collection, simply create a new Ruby class with the desired functionality and add it to the list of components. Each component type (containers, JREs and frameworks) has a well-defined contract, runs in isolation from the rest of the components, and uses a whiteboard pattern to communicate its contributions.
Another guiding design principle is that extension of the buildpack must be an additive exercise, not a mutative one. The major benefit of this principle is that upstream changes can be easily integrated into a fork because the only possible point of conflict is a simple YAML file. This same benefit comes into play when the community contributes changes back to us.
Take a look at the collection of forks for some great examples of people adding support for Jonas, DropWizard, and Karaf. And of course I’d be remiss if I didn’t mention IBM’s Liberty Buildpack. If you create a component that you think is useful to other users of the buildpack, think about letting us know and contributing it back to the community.
The Future
Next on the list is support for additional containers, and automated integration with the Marketplace services available on the Pivotal CF hosted service. Beyond that the future is up to you; customer demand drives the feature list for the buildpack, so have your say. You can also chat with me at Platform, the Cloud Foundry conference, September 8-9 2013. I’ll be there talking about buildpacks and the Java experience on Cloud Foundry.
About the Author
Ben Hale is a Senior Software Engineer at VMware, leading the Java Experience on Cloud Foundry. He can be found on the vcap-dev group and via issues opened in the java-buildpack
project. He will also be speaking at the Platform and SpringOne 2GX conferences in September 2013.
- To be more precise, the buildpack aims to support anything that will run on the JVM. This currently includes Java, Groovy (including Grails), and Scala (including the Play Framework). ↩
- The buildpack currently exposes information about the infrastructure dependencies it contributes to the Cloud Foundry Cloud Controller. In the future that kind of information can be used to notify application owners of potential vulnerabilities and perhaps even automatically update running applications in order to stay safe. ↩
- The
--buildpack
switch can also be used to push an application with the buildpack on any instance of Cloud Foundry V2, whether or not the buildpack is installed by default. ↩ - One of the features we’re most proud of is the work the buildpack does to intelligently size the different memory regions of the JRE. ↩
- Developers who are not familiar with GitHub may not realize exactly how easy forking a repository is. Using GitHub’s fork-and-edit functionality you can create a fork with your custom configuration in only two clicks! ↩
- The URI of the buildpack to be used when pushing an application is stored on the Cloud Foundry server so you don’t have to specify it every time you push. In addition, if you maintain a
manifest.yml
file in source control, you can specify the buildpack there so it never has to be declared on the command line. ↩