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: