This document specifies the interface between a single lifecycle and one or more buildpacks.
A lifecycle is a program that uses buildpacks to transform application source code into an OCI image containing the compiled application.
This is accomplished in four phases:
The ENTRYPOINT of the OCI image contains logic implemented by the lifecycle that executes during the Launch phase.
Additionally, a lifecycle can use buildpacks to create a containerized environment for developing or testing application source code.
This is accomplished in two phases:
The following specifies the interface implemented by executables in each buildpack. The lifecycle MUST invoke these executables as described in the Phase sections.
| Mark | Meaning |
|---|---|
| A | Single copy provided for all buildpacks |
| E | Different copy provided for each buildpack |
| I | Image repository for storage |
| C | Cache for storage |
| R | Read-only |
| * | Buildpack-specific content |
| # | Platform-specific content |
Executable: /bin/detect, Working Dir: <app[AR]>
| Input | Description |
|---|---|
/dev/stdin |
Merged plan from previous detections (TOML) |
| Output | Description |
|---|---|
| [exit status] | Pass (0), fail (100), or error (1-99, 101+) |
/dev/stdout |
Updated plan for subsequent detections (TOML) |
/dev/stderr |
Detection logs (all) |
Executable: /bin/build <platform[AR]> <cache[EC]> <launch[EI]>, Working Dir: <app[AI]>
| Input | Description |
|---|---|
/dev/stdin |
Build plan from detection (TOML) |
<platform>/env/ |
User-provided environment variables for build |
<platform>/# |
Platform-specific extensions |
| Output | Description |
|---|---|
| [exit status] | Success (0) or failure (1+) |
/dev/stdout |
Logs (info) |
/dev/stderr |
Logs (warnings, errors) |
<cache>/<layer>/bin/ |
Binaries for subsequent buildpacks |
<cache>/<layer>/lib/ |
Libraries for subsequent buildpacks |
<cache>/<layer>/include/ |
C/C++ headers for subsequent buildpacks |
<cache>/<layer>/pkgconfig/ |
Search path for pkg-config |
<cache>/<layer>/env/ |
Env vars for subsequent buildpacks |
<cache>/<layer>/* |
Other cached content |
<launch>/launch.toml |
Launch metadata (see File: launch.toml) |
<launch>/<layer>.toml |
Layer content metadata (see Layer Caching) |
<launch>/<layer>/bin/ |
Binaries for launch |
<launch>/<layer>/lib/ |
Shared libraries for launch |
<launch>/<layer>/profile.d/ |
Scripts sourced by bash before launch |
<launch>/<layer>/* |
Other content for launch |
Executable: /bin/develop <platform[A]> <cache[EC]>, Working Dir: <app[A]>
| Input | Description |
|---|---|
/dev/stdin |
Build plan from detection (TOML) |
<platform>/env/ |
User-provided environment variables for build |
<platform>/# |
Platform-specific extensions |
| Output | Description |
|---|---|
| [exit status] | Success (0) or failure (1+) |
/dev/stdout |
Logs (info) |
/dev/stderr |
Logs (warnings, errors) |
<cache>/develop.toml |
Development metadata (see File: develop.toml) |
<cache>/<layer>/bin/ |
Binaries for subsequent buildpacks & app |
<cache>/<layer>/lib/ |
Libraries for subsequent buildpacks & app |
<cache>/<layer>/include/ |
C/C++ headers for subsequent buildpacks |
<cache>/<layer>/pkgconfig/ |
Search path for pkg-config |
<cache>/<layer>/env/ |
Env vars for subsequent buildpacks & app |
<cache>/<layer>/* |
Other content for subsequent buildpacks & app |
| Output | Description |
|---|---|
<app>/.profile |
Script sourced by bash before launch |
The purpose of detection is to find an ordered group of buildpacks to use during the build phase. These buildpacks must be compatible with the app.
GIVEN:
For each buildpack in each group in order, the lifecycle MUST execute /bin/detect.
IF the exit status of /bin/detect is non-zero and the buildpack is not marked optional, \
THEN the lifecycle MUST proceed to the next group or fail detection completely if no more groups are present.
IF the exit status of /bin/detect is zero or the buildpack is marked optional,
IF the buildpack is not the last buildpack in the group, \ THEN the lifecycle MUST proceed to the next buildpack in the group.
IF the buildpack is the last buildpack in the group,
IF no exit statuses from /bin/detect in the group are zero \
THEN the lifecycle MUST proceed to the next group or fail detection completely if no more groups are present.
IF at least one exit status from /bin/detect in the group is zero \
THEN the lifecycle MUST select this group and proceed to the analysis phase.
The selected group MUST be filtered to only include buildpacks with exit status zero. The order of the buildpacks in the group MUST otherwise be preserved.
The /bin/detect executable in each buildpack, when executed:
stderr.stdin.stdout.For each /bin/detect, the Build Plan received on stdin MUST be a combined map derived from the output of all previous /bin/detect executables.
The lifecycle MUST construct this map such that the top-level values from later buildpacks override the entire top-level values from earlier buildpacks.
The lifecycle MUST NOT include any changes in this map that are output by optional buildpacks that returned non-zero exit statuses.
The final Build Plan is the complete combined map that includes the output of the final /bin/detect executable.
The lifecycle MAY execute each /bin/detect within a group in parallel.
Therefore, reading from stdin in /bin/detect MUST block until the previous /bin/detect in the group closes stdout.
The lifecycle MUST run /bin/detect for all buildpacks in a group on a common stack.
The lifecycle MUST fail detection if any of those buildpacks does not list that stack in buildpack.toml.
The purpose of analysis is to retrieve <launch>/<layer>.toml files that buildpacks may use to optimize the build and export phases.
Each <launch>/<layer>.toml file represents a remote filesystem layer that the buildpack may keep, replace, or remove during the build phase.
The lifecycle SHOULD attempt to locate a reference to an OCI image from a previous build that:
The lifecycle MUST skip analysis and proceed to the build phase if no such image can be located.
GIVEN:
For each buildpack in the group,
<launch>/<layer>.toml files that were present at the end of the build of the previously created OCI image are retrieved.<layer>.toml files are placed on the filesystem so that they appear in the buildpack’s <launch>/ directory during the build phase.The lifecycle MUST NOT download any filesystem layers from the previous OCI image.
After analysis, the lifecycle MUST proceed to the build phase.
The purpose of build is to transform application source code into runnable artifacts that can be packaged into a container.
During the build phase, typical buildpacks might:
<launch>/<layer>.<cache>/<layer>.<launch>/launch.toml.The purpose of separate <layer> directories is to:
This is achieved by:
GIVEN:
<launch>/<layer>.toml files placed on the filesystem during the analysis phase, and<cache> directories from a build of a version of the application source code,For each buildpack in the group in order, the lifecycle MUST execute /bin/build.
IF the exit status of /bin/build is non-zero, \
THEN the lifecycle MUST fail the build.
IF the exit status of /bin/build is zero,
IF there are additional buildpacks in the group, \
THEN the lifecycle MUST proceed to the next buildpack’s /bin/build.
IF there are no additional buildpacks in the group, \ THEN the lifecycle MUST proceed to the export phase.
For each /bin/build executable in each buildpack, the lifecycle:
stdin of /bin/build./bin/build as defined in the Buildpack Interface section.<cache> directory if the platform does not make it available.Correspondingly, each /bin/build executable:
<app> directory.stdin.<launch>/launch.toml in launch.toml format.<cache>/<layer> directories.<launch>/<layer> directories and create corresponding <launch>/<layer>.toml files.<layer> directories without restrictions except those imposed by the filesystem.<app> directory to store provided dependencies.<launch>/<layer> directories to other buildpacks.The buildpack SHOULD use the contents of a given pre-existing <launch>/<layer>.toml file to decide:
<launch>/<layer> directory that will replace a remote layer during the export phase.<launch>/<layer>.toml file to delete a remote layer during the export phase.<launch>/<layer>.toml file for the next build.To make this decision, the buildpack should consider:
<app> directory are sufficiently similar to the previous build.<cache> directories are sufficiently similar to the previous build.The purpose of export is to create an new OCI image using a combination of remote layers, local <launch>/<layer> layers, and the processed <app> directory.
GIVEN:
<launch> directories provided to each buildpack during the build phase,<app> directory processed by the buildpacks during the build phase,<launch>/<layer>.toml files that were retrieved during the analysis phase, andIF the run image, old OCI image, and new OCI image are not all present in the same image store, \ THEN the lifecycle SHOULD fail the export process or inform the user that export performance is degraded.
For each <launch>/<layer>.toml file,
<launch>/<layer> directory is present locally, \
THEN the lifecycle MUST
<launch>/<layer> is preserved in the transferred layer.<launch>/<layer> directory is not present locally, \
THEN the lifecycle MUST
<launch>/<layer>.toml file so that
Subsequently,
<app>, the lifecycle MUST
<launch>/<layer> filesystem layers transferred by the lifecycle,<launch>/<layer> filesystem layers from the old OCI image,<app> filesystem layers,launch.toml files such that process types from later buildpacks override identical process types from earlier buildpacks,ENTRYPOINT set to an executable component of the lifecycle that implements the launch phase.The lifecycle MUST NOT access the contents of any filesystem layers from the previous OCI image.
The purpose of launch is to modify the running app environment using app-provided or buildpack-provided logic and start a user-provided or buildpack-provided process.
GIVEN:
PACK_PROCESS_TYPE, andWhen the OCI image is launched,
<launch>/<layer>/profile.d directory using the same Bash shell process,
/bin/build execution used to construct the OCI image.In the Bash shell process used to source the profile.d scripts, the lifecycle MUST source <app>/.profile if it is present.
If CMD in the container configuration is not empty, the lifecycle MUST join each argument with a space and execute the resulting command in the container using the Bash shell process used to source the profile.d scripts.
CMD in the container configuration is empty,
PACK_PROCESS_TYPE environment variable is set,
IF the value of PACK_PROCESS_TYPE corresponds to a process in <launch>/launch.toml, \
THEN the lifecycle MUST execute the corresponding command in the container using the Bash shell process used to source the profile.d scripts.
IF the value of PACK_PROCESS_TYPE does not correspond to a process in <launch>/launch.toml, \
THEN launch fails.
PACK_PROCESS_TYPE environment variable is not set,
IF there is a process with a web process type in <launch>/launch.toml, \
THEN the lifecycle MUST execute the corresponding command in the container using the Bash shell process used to source the profile.d scripts.
IF there is not a process with a web process type in <launch>/launch.toml, \
THEN launch fails.
When executing a process with Bash, the lifecycle SHOULD replace the Bash process in memory with the resulting command process if possible.
The purpose of development setup is to create a containerized environment for developing or testing application source code.
During the development setup phase, typical buildpacks might:
<cache>/<layer>.<cache>/develop.toml.<cache>/develop.toml.GIVEN:
<cache> directories from a development setup of a version of the application source code, andFor each buildpack in the group in order, the lifecycle MUST execute /bin/develop.
IF the exit status of /bin/develop is non-zero, \
THEN the lifecycle MUST fail the development setup.
IF the exit status of /bin/develop is zero,
IF there are additional buildpacks in the group, \
THEN the lifecycle MUST proceed to the next buildpack’s /bin/develop.
IF there are no additional buildpacks in the group, \
THEN the lifecycle MUST launch the process type specified by PACK_PROCESS_TYPE.
For each /bin/develop executable in each buildpack, the lifecycle:
stdin of /bin/develop./bin/develop as defined in the Buildpack Interface section.<cache> directory if the platform does not make it available.Correspondingly, each /bin/develop executable:
stdin.<cache>/<layer> directories.<layer> directories without restrictions except those imposed by the filesystem.<app> directory to store provided dependencies.After the last /bin/develop finishes executing,
PACK_PROCESS_TYPE environment variable is set,
IF the value of PACK_PROCESS_TYPE corresponds to a process in <cache>/develop.toml, \
THEN the lifecycle MUST execute the corresponding command in the container using Bash.
IF the value of PACK_PROCESS_TYPE does not correspond to a process in <cache>/develop.toml, \
THEN the lifecycle MUST fail development setup.
PACK_PROCESS_TYPE environment variable is not set,
IF there is a process with a web process type in <cache>/develop.toml, \
THEN the lifecycle MUST execute the corresponding command in the container using Bash.
IF there is not a process with a web process type in <cache>/develop.toml, \
THEN the lifecycle MUST fail development setup.
When executing a process with Bash, the lifecycle SHOULD replace the Bash process in memory with the resulting command process if possible.
The following environment variables MUST be set by the lifecycle in order to make buildpack dependencies accessible.
During the build phase, each variable designated for build MUST contain absolute paths of all previous buildpacks’ <cache>/<layer>/ directories.
When the exported OCI image is launched, each variable designated for launch MUST contain absolute paths of all buildpacks’ <launch>/<layer>/ directories.
In either case,
<layer> paths to reflect the order of the buildpack group.<layer> paths provided by a given buildpack alphabetically ascending.: on Linux).| Env Variable | Layer Path | Contents | Build | Launch |
|---|---|---|---|---|
PATH |
/bin |
binaries | [x] | [x] |
LD_LIBRARY_PATH |
/lib |
shared libraries | [x] | [x] |
LIBRARY_PATH |
/lib |
static libraries | [x] | |
CPATH |
/include |
header files | [x] | |
PKG_CONFIG_PATH |
/pkgconfig |
pc files | [x] |
The following additional environment variables MUST NOT be overridden by the lifecycle.
| Env Variable | Description | Detect | Build | Launch |
|---|---|---|---|---|
PACK_STACK_ID |
Chosen stack ID | [x] | [x] | |
BP_* |
User-specified variable for buildpack | [x] | [x] | |
BPL_* |
User-specified variable for profile.d | [x] | ||
HOME |
Current user’s home directory | [x] | [x] | [x] |
The lifecycle MUST provide any user-provided environment variables as files in <platform>/env/ with file names and contents matching the environment variable names and contents.
The lifecycle MUST NOT set user-provided environment variables in the environment of /bin/build directly.
Buildpacks MAY use the value of PACK_STACK_ID to modify their behavior when executed on different stacks.
The environment variable prefix PACK_ is reserved.
It MUST NOT be used for environment variables that are not defined in this specification or approved extensions.
During the build phase, buildpacks MAY write environment variable files to <cache>/<layer>/env/ directories.
For each file written to <cache>/<layer>/env/ by /bin/build, the lifecycle MUST modify an environment variable in subsequent executions of /bin/build.
The lifecycle MUST set the name of the environment variable to the name of the file up to the first period (.) or to the end of the name if no periods are present.
If the environment variable has no period-delimited suffix, then the value of the environment variable MUST be a concatenation of the file contents and the contents of other identically named files in other <cache>/<layer>/env/ directories delimited by the OS path list separator.
Within that environment variable value,
If the environment variable file name ends in .append, then the value of the environment variable MUST be a concatenation of the file contents and the contents of other identically named files in other <cache>/<layer>/env/ directories without any delimitation.
Within that environment variable value,
If the environment variable file name ends in .override, then the value of the environment variable MUST be the file contents or the contents of another identically named file in another <cache>/<layer>/env/ directory.
For that environment variable value
In all cases, file contents MUST NOT be evaluated by a shell or otherwise modified before inclusion in environment variable values.
A lifecycle may be used by a multi-tenant platform. On such a platform,
Therefore, the following assumptions and requirements exist to prevent malicious buildpacks or applications from gaining unauthorized access to external resources.
Allowed:
Prohibited:
The lifecycle MUST be implemented so that the detection and build phases do not have access to OCI image store credentials used in the analysis and export phases. The lifecycle SHOULD be implemented so that each phase may run in a different container.
Buildpacks SHOULD be packaged as gzip-compressed tarballs with extension .tgz.
Buildpacks MUST:
/buildpack.toml and /bin/detect./bin/build and /bin/develop.[buildpack]
id = "<buildpack ID>"
name = "<buildpack name>"
version = "<buildpack version>"
[[stacks]]
id = "<stack ID>"
build-images = ["<build image tag>"]
run-images = ["<run image tag>"]
[metadata]
# buildpack-specific data
Buildpack authors MUST choose a globally unique ID, for example: “io.buildpacks.ruby”.
The buildpack ID MUST contain at least one period (.).
Stack authors MUST choose a globally unique ID, for example: “io.buildpacks.mystack”.
The stack ID MUST contain at least one period (.).
The stack build-images and run-images are suggested sources of the image for platforms that are unaware of the stack ID.
[[processes]]
type = "<process type>"
command = "<command>"
Buildpacks MUST specify:
launch.toml file.[[processes]]
type = "<process type>"
command = "<command>"
Buildpacks MUST specify:
develop.toml file.[<dependency name>]
version = "<dependency version>"
provider = "<buildpack ID>"
[<dependency name>.metadata]
# buildpack-specific data
For a given dependency, the buildpack MAY specify: