How Buildpacks Work
Page last updated:
This topic describes how buildpacks are structured and detected in Cloud Foundry.
Buildpack Scripts
A buildpack repository may contain the following five scripts in the bin
directory:
bin/detect
determines whether or not to apply the buildpack to an app.bin/supply
provides dependencies for an app.bin/finalize
prepares the app for launch.bin/release
provides feedback metadata to Cloud Foundry indicating how the app should be executed.bin/compile
is a deprecated alternative tobin/supply
andbin/finalize
.
The bin/supply
and bin/finalize
scripts replace the deprecated bin/compile
script. Older buildpacks may still use bin/compile
with the latest version of Cloud Foundry. In this case, applying multiple buildpacks to a single app is not supported. Similarly, newer buildpacks may still provide bin/compile
for compatibility with Heroku and older versions of Cloud Foundry.
The bin/supply
script is required for non-final buildpacks. The bin/finalize
(or bin/compile
) script is required for final buildpacks.
Note: In this topic, the terms non-final buildpack and final buildpack, or last buildpack, are used to describe the process of applying multiple buildpacks to an app. For example: cf push APP-NAME -b FIRST-BUILDPACK -b SECOND-BUILDPACK -b FINAL-BUILDPACK
.
Note: If you use only one buildpack for your app, this buildpack behaves as a final, or last, buildpack.
Note: When using multi-buildpack support, the last buildpack in order is the final buildpack, and is able to make changes to the app and determine a start command. All other specified buildpacks are non-final and only supply dependencies.
bin/detect
The detect
script determines whether or not to apply the buildpack to an app. The script is called with one argument, the build
directory for the app. The build
directory contains the app files uploaded when you run cf push
.
The detect
script returns an exit code of 0
if the buildpack is compatible with the app. In the case of system buildpacks, the script also prints the buildpack name, version, and other information to STDOUT
.
The following is an example detect
script that checks for a Ruby app based on the existence of a Gemfile
:
#!/usr/bin/env ruby
gemfile_path = File.join ARGV[0], "Gemfile"
if File.exist?(gemfile_path)
puts "Ruby"
exit 0
else
exit 1
end
Optionally, the buildpack detect
script can output additional details provided by the buildpack developer. This includes buildpack versioning information and a list of configured frameworks and their associated versions.
The following is an example of the detailed information returned by the Java buildpack:
java-buildpack=v3.0-https://github.com/cloudfoundry/java-buildpack.git#3bd15e1 open-jdk-jre=1.8.0_45 spring-auto-reconfiguration=1.7.0_RELEASE tomcat-access-logging-support=2.4.0_RELEASE tomcat-instance=8.0.21 tomcat-lifecycle-support=2.4.0_RELEASE ...
Note: Cloud Foundry detects only one buildpack by default. When multiple buildpacks are desired, you must explicitly specify them.
For more information, see Buildpack Detection.
bin/supply
The supply
script provides dependencies for the app and runs for all buildpacks. All output sent to STDOUT
is relayed to the user through the Cloud Foundry Command Line Interface (cf CLI).
The script is run with four arguments:
- The
build
directory for the app - The
cache
directory, which is a location the buildpack can use to store assets during the build process - The
deps
directory, which is where dependencies provided by all buildpacks are installed - The
index
, which is a number that represents the ordinal position of the buildpack
The supply
script stores dependencies in deps
/index
. It may also look in other directories within deps
to find dependencies supplied by other buildpacks.
The supply
script must not modify anything outside of the deps
/index
directory. Staging may fail if such modification is detected.
The cache
directory provided to the supply
script of the final buildpack is preserved even when the buildpack is upgraded or otherwise changes. The finalize
script also has access to this cache directory.
The cache
directories provided to the supply
scripts of non-final buildpacks are cleared if those buildpacks are upgraded or otherwise change.
The following is an example of a simple supply
script:
#!/usr/bin/env ruby
#sync output
$stdout.sync = true
build_path = ARGV[0]
cache_path = ARGV[1]
deps_path = ARGV[2]
index = ARGV[3]
install_ruby
private
def install_ruby
puts "Installing Ruby"
# !!! build tasks go here !!!
# download ruby
# install ruby
end
bin/finalize
The finalize
script prepares the app for launch and runs only for the last buildpack. All output sent to STDOUT
is relayed to the user through the cf CLI.
The script is run with four arguments:
- The
build
directory for the app - The
cache
directory, which is a location the buildpack can use to store assets during the build process - The
deps
directory, which is where dependencies provided by all buildpacks are installed - The
index
, which is a number that represents the ordinal position of the buildpack
The finalize
script may find dependencies installed by the supply
script of the same buildpack in deps
/index
. It may also look in other directories within deps
to find dependencies supplied by other buildpacks.
The cache
directory provided to the finalize
script is preserved even when the buildpack is upgraded or otherwise changes. The supply
script of the same buildpack also has access to this cache directory.
The following is an example of a simple finalize
script:
#!/usr/bin/env ruby
#sync output
$stdout.sync = true
build_path = ARGV[0]
cache_path = ARGV[1]
deps_path = ARGV[2]
index = ARGV[3]
setup_ruby
private
def setup_ruby
puts "Configuring your app to use Ruby"
# !!! build tasks go here !!!
# setup ruby
end
bin/compile (Deprecated)
The compile
script is deprecated. It encompasses the behavior of the supply
and finalize
scripts for single buildpack apps by using the build
directory to store dependencies.
The script is run with two arguments:
- The
build
directory for the app - The
cache
directory, which is a location the buildpack can use to store assets during the build process
During the execution of the compile
script, all output sent to STDOUT
is relayed to the user through the cf CLI.
bin/release
The release
script provides feedback metadata to Cloud Foundry indicating how the app should be executed. The script is run with one argument, the build
directory. The script must generate a YAML file in the following format:
default_process_types:
web: start_command.filetype
default_process_types
indicates the type of app being run and the command used to start it. This start command is used if a start command is not specified in the cf push
or in a Procfile.
At this time, only the web
type of apps is supported.
Note: To define environment variables for your buildpack, add a Bash script to the .profile.d
directory in the root folder of your app.
The following example shows what a release
script for a Rack app might return:
default_process_types:
web: bundle exec rackup config.ru -p $PORT
Note: The web
command runs as bash -c COMMAND
when Cloud Foundry starts your app.
Droplet Filesystem
The buildpack staging process extracts the droplet into the /home/vcap
directory inside the instance container and creates the following filesystem tree:
app/
deps/
logs/
tmp/
staging_info.yml
The app
directory includes the contents of the build
directory, and staging_info.yml
contains the staging metadata saved in the droplet.
Buildpack Detection
When you push an app, Cloud Foundry uses a detection process to determine a single buildpack to use. For general information about this process, see the How Diego Stages Buildpack Apps section of the How Apps Are Staged topic.
During staging, each buildpack has a position in a priority list. You can retrieve this position by running cf buildpacks
.
Cloud Foundry checks if the buildpack in position 1 is a compatible buildpack. If the position 1 buildpack is not compatible, Cloud Foundry moves on to the buildpack in position 2. Cloud Foundry continues this process until the correct buildpack is found.
If no buildpack is compatible, the cf push
command fails with the following error:
None of the buildpacks detected a compatible application Exit status 222 Staging failed: Exited with status 222 FAILED NoAppDetectedError
For a more detailed account of how Cloud Foundry interacts with the buildpack, see Sequence of Interactions.
Sequence of Interactions
This section describes the sequence of interactions between the Cloud Foundry platform and the buildpack. The sequence of interactions differs depending on whether the platform skips or performs buildpack detection.
No Buildpack Detection
Cloud Foundry skips buildpack detection if the developer specifies one or more buildpacks in the app manifest or in the cf push APP-NAME -b BUILDPACK-NAME
cf CLI command.
If you explicitly specify buildpacks, Cloud Foundry performs the following interactions:
For each buildpack except the last buildpack, the platform:
- Creates the
deps
/index
directory. - Runs
/bin/supply
with thebuild
,cache
, anddeps
directories and the buildpackindex
. - Accepts any modification of the
deps
/index
directory. - Accepts any modification of the
cache
directory. - May disallow modification of any other directories.
- Creates the
For the last buildpack, the platform:
- If
/bin/finalize
is present:- Creates the
deps
/index
directory if it does not exist. - If
/bin/supply
is present, runs/bin/supply
with thebuild
,cache
, anddeps
directories and the buildpackindex
. - Accepts any modification of the
deps
/index
directory. - May disallow modification of the
build
directory. - Runs
/bin/finalize
with thebuild
,cache
, anddeps
directories and the buildpackindex
. - Accepts any modification of the
build
directory.
- Creates the
- If
/bin/finalize
is not present:- Runs
/bin/compile
with thebuild
andcache
directories. - Accepts any modification of the
build
directory.
- Runs
- Runs
/bin/release
to determine staging information.
- If
At the end of this process, the deps
directory is included at the root of the droplet, adjacent to the app
directory.
Buildpack Detection
Cloud Foundry performs buildpack detection if the developer does not specify one or more buildpacks in the app manifest or in the cf push APP-NAME -b BUILDPACK-NAME
cf CLI command.
Note: Cloud Foundry detects only one buildpack to use with the app.
If the platform performs detection, it:
Runs
/bin/detect
for each buildpack.Selects the first buildpack with a
/bin/detect
script that returns a zero exit status.If
/bin/finalize
is present:- Creates the
deps
/index
directory if it does not exist. - If
/bin/supply
is present, runs/bin/supply
with thebuild
,cache
, anddeps
directories and the buildpackindex
. - Accepts any modification of the
deps
/index
directory. - May disallow modification of the
build
directory. - Runs
/bin/finalize
on thebuild
,cache
, anddeps
directories. - Accepts any modification of the
build
directory.
- Creates the
If
/bin/finalize
is not present:- Runs
/bin/compile
on thebuild
andcache
directories. - Accepts any modification of the
build
directory.
- Runs
Runs
/bin/release
to determine staging information.
At the end of this process, the deps
directory is included at the root of the droplet, adjacent to the app
directory.