NOTE: Meta-buildback is being deprecated
Changes to the core CloudFoundry lifecycle process are making it hard to guarantee on-going compatibility with meta-buildpack and decorators. Some of the use cases for decorators can now be solved by leveraging the new supply buildpack functionality. Some examples can be found at the bottom of this page.
If you are using meta-buildpack today and need to find an alternative, or have a use case that would have been addressed by decorators, please open an issue on this repo and we are happy to help you look for the right way to accomplish your task.
This is a Cloud Foundry buildpack that enables decomposition of buildpacks into "real" buildpacks (the ones that create a droplet from the submitted source), and "decorators" (buildpacks that inject other smarts into the droplet generated by the first buildpack).
The main objective of this buildpack is to reduce the NxM problem of having buildpacks for each programming language, and add-on features that support multiple languages. Specifically, I wanted to add Spring Cloud Config Service support to as many non-Java languages as possible, and prior to creating the meta-buildpack, I had to fork and modify the buildpack for each supported language in order to do that. The same issue applies to things like Application Performance Monitoring solutions that support multiple languages. If we separate the (N) language buildpacks from the (M) feature add-on buildpacks, we have reduced the problem to N+M instead.
It is entirely possible to do this without a meta-buildpack by including the recursive invocation of buildpacks in each decorator, and requiring decorators to be at the top of the list. But that's just plain ugly.
A decorator is a special Cloud Foundry buildpack. Unlike a "real" buildpack, a decorator doesn't produce a droplet from source. Instead, it "decorates" (hence the name) an already produced droplet to implement some kind of add-on feature. Good examples of such add-on features might be:
- Monitoring Agents
- Configuration Management
- Service Registration and Discovery
- Sidecar Applications like Gateways and Client-Side Routers
Basically anything that can be injected into containers with little or no dependency on what language the application was written in. Splitting out this functionality into decorators avoids the need to fork and modify "real" buildpacks to implement such add-on functionality for multiple languages.
How it works
The meta-buildpack should be pushed to the top of the list of installed buildpacks in Cloud Foundry
(the provided upload script places it there for you). It is thus always invoked before any other
buildpack, and is able to claim the build regardless of what language the submitted source is in.
The meta-buildpack will then proceed to invoke the "real" buildpacks just as they would have been
without the meta-buildpack present. The language buildpack will
detect and claim the build, and
compile step will produce a droplet like it normally would.
After the real buildpack runs, control passes back to the meta-buildpack, and it will then proceed
to invoke "decorator" buildpacks. Decorators are installed like any other buildpack (by convention
at the bottom of the list of buildpacks), but their
detect scripts always return false, and they
instead are identified by having a
decorate script that returns true if the decorator applies.
If any decorator returns true, its compile step is invoked to modify the droplet.
Unlike language buildpacks, decorators are not mutually exclusive. The meta-buildpack will invoke
all decorators that return true from their
decorate scripts, so any number of them can be applied
to a single droplet.
If your application requires you to specify a buildpack (either in the application manifest or
cf push), the meta-buildpack will not be invoked and thus no decorators will be invoked
either. If you are developing a custom decorator buildpack, you may want to provide an alternative
method for leveraging your buildpack's functionality in the case when an application requires a
specific buildpack to address this limitation.
How it should work
If this functionality is deemed useful by more people than just me, it should be implemented in the Cloud Foundry cloud controller, rather than requiring a special buildpack at the top of the list. But the meta-buildpack provides access to the feature before it's implemented in the core, so that we can prove the concept and gauge its appeal to other developers. Migrating support for this feature into Cloud Foundry later should have zero effect on decorators that have already been produced.
How to install the meta-buildpack
The meta-buildpack is continuously tested against all supported versions of Pivotal Cloud Foundry. Releases of the meta-buildpack are available both as a BOSH release (a .tgz file), and as a Pivotal Cloud Foundry tile (a .pivotal file). The latest release is available here:
For developers, to install the meta-buildpack directly from your clone of this repository to the top of the buildpack list, simply run the provided build and upload scripts. You must be logged in to Cloud Foundry with a role that allows buildpack installations.
git clone https://github.com/cf-platform-eng/meta-buildpack.git cd meta-buildpack ./build ./upload
How to write a decorator
A decorator is installed and invoked just like any other buildpack, with a couple of significant differences.
To prevent the decorator from being invoked as a buildpack, its
bin/detectscript should always return false. Here's a sample:
#!/usr/bin/env bash # bin/detect <build-dir> # We are a decorator, not a buildpack, so we always decline to build exit 1
Instead, the real detection for a decorator is done by the
bin/decoratescript. The presence of this script is what enables the meta-buildpack to identify decorators:
#!/usr/bin/env bash # bin/decorate <build-dir> BIN_DIR=$(cd $(dirname $0); pwd) ROOT_DIR=$(dirname $BIN_DIR) BUILD_DIR=$1 # Determine if the app meets the criteria to be decorated by this decorator # Exit 0 if you want the decorator to run, non-zero if not
Remember that the
decoratescript is invoked during the detect stage, so the compile step of the real buildpack has not yet been run. But the full application environment is available (including things like
VCAP_SERVICESto determine what services are bound to the application).
bin/decoratescript returns true (zero), the meta-buildpack will run the
bin/compilescript. The environment for that script looks exactly like it would for a real buildpack, except the real buildpack has already run, so the entire droplet is already present in
REMEMBER that any number of decorators may be invoked for the same droplet. While decorators are invoked in the order in which they are in the buildpack list, it is best to make no assumptions about the order in which yours will be invoked.
NOTE: Meta-buildback and the decorator pattern are being deprecated
Changes to the core CloudFoundry lifecycle process are making it hard to guarantee on-going compatibility with meta-buildpack and decorators. Some of the use cases for decorators can now be solved by leveraging the new supply buildpack functionality. The following repositories provide examples equivalent to the above, but using the new, supported, method of delivering supply buildpacks: