- Name: Export to OCI format
- Start Date: 2022-02-22
- Author(s): Juan Bustamante (@jjbustamante)
- Status: Approved
- RFC Pull Request: rfcs#203
- CNB Pull Request: (leave blank)
- CNB Issue: N/A
- Supersedes: (put "N/A" unless this replaces an existing RFC, then link to that RFC)
Add the capability to the Exporter
phase to save the image to disk in OCI Layout format.
- A Platform uses a lifecycle, Buildpacks (packaged in a builder), and application source code to produce an OCI image.
- A Lifecycle orchestrates Buildpacks execution, then assembles the resulting artifacts into a final app image.
- A Daemon is a service, popularized by Docker, for downloading container images, and executing and managing containers from those images.
- A Registry is a long-running service used for storing and retrieving container images.
- An image reference refers to either a tag reference or digest reference.
- A tag reference refers to an identifier of form
<registry>/<repo>:<tag>
which locates an image manifest in an OCI Distribution Specification compliant registry. - A digest reference refers to a content addressable identifier of form
<registry>/<repo>@<digest>
which locates an image manifest in an OCI Distribution Specification compliant registry. - A image Manifest provides a configuration and set of layers for a single container image for a specific architecture and operating system.
- The layer diffID is the hash of the uncompressed layer
- The layer digest is the hash of the compressed layer.
- An OCI Image Layout is the directory structure for OCI content-addressable blobs and location-addressable references.
Lifecycle translates an application source code into an OCI image, in order to do this, it can be configured to interact with a docker daemon (using daemon
flag) or with an OCI registry.
The OCI Image Layout is the directory structure for OCI content-addressable blobs and location-addressable references.
The current process, executed by the lifecycle, does not take into consideration cases where a platform implementor may require to pass through the inputs or want to save the final application image on disk using OCI Image Layout format.
Exporting to OCI Image Layout will enable new user's workflows on top of this functionality. For example:
- It provides a mechanism to reduce the Lifecycle complexity by removing the interaction with the Daemon in the future.
- Solve the problem of losing information when the image is saved into the Daemon, keeping the image on disk along with the metadata generated by the Lifecycle. The OCI Image can be used as input for other tools to offer more capabilities to the end users.
- This feature will help to unblock uses cases like
Lifecycle will be capable of exporting the application image into disk in OCI Image Layout format. The image saved on disk could have the following considerations:
- The
blobs
directory MAY be missingbase image
orrun image
blobs. These layers may not be needed on disk as they could be already accessible in a blob store. - The
blobs
directory SHOULD always have buildpacks generatedblobs
.
The proposal is to add a new capability to the lifecycle (enabled by configuration) to resolve any image reference (input or output) to a disk location in OCI Image Layout format. It means, instead of interacting with a daemon or registry lifecycle will interact against the filesystem to read or write any image reference.
The target personas affected by this change are:
- Platform implementors: they will have to take care of the responsibility of creating a store resource on disk in OCI Image Layout format and pass it through the lifecycle during the phases execution.
The process of writing any image on disk in OCI Image Layout format could be expensive in terms of hard drive space or IO operation (compressing or uncompressing layers). In order to provide flexibility for the implementation, the analyzer
or exporter
binaries only require the Image Manifest and the Image Config to execute their operations on the previous image and run image; based on this, we proposed the Lifecycle can be configured to work with a partial representation of the images on disk, meaning that some blobs MAY be missing (which is ok according to the OCI Image Layout format). The missing blobs SHOULD be those that are already available in a daemon or registry.
Let's see some examples of the proposed behavior
Lifecycle will converts image references into local paths following define rules and the content must be in OCI Image Layout format.
Let's suppose a platform implementor creates a directory with the following structure:
layout-repo
└── index.docker.io
├── cnb
│ ├── my-full-stack-run:bionic
│ │ └── bionic
│ │ └── blobs
│ │ ├── sha256
│ │ │ ├── 1f59...944a // manifest
│ │ │ ├── 6388...af5a // config
│ │ │ ├── 824b...f984e
│ │ │ ├── f5f7...5b38
│ │ │ └── 870e...f1b09
│ │ ├── index.json
│ │ └── oci-layout
│ └── my-partial-stack-run:bionic
│ └── bionic
│ ├── blobs
│ │ └── sha256
│ │ ├── 1f59...944a // manifest
│ │ └── 6388...af5a // config
│ ├── index.json
│ └── oci-layout
└── bar
└── my-previous-app
└── latest
├── blobs
│ └── sha256
│ ├── 4bcd5..x // app image manifest
│ ├── 5f789..d // app image config
│ ├── 624b...f984e // run layer
│ └── 4g234..f // buildpack layer
├── index.json
└── oci-layout
The images named cnb/my-full-stack-run and cnb/my-partial-stack-run represents the same image but the partial one has missing blobs
, those blobs
are the layers that are already available in the store from it came from.
For each example case, I will present two ways of enabling the new capability:
- Using an environment variables
- Using the new
-layout
andlayout-dir
flags
In any case the expected output is the same.
> export CNB_USE_LAYOUT=true
> export CNB_LAYOUT_DIR=/layout-repo
> /cnb/lifecycle/analyzer -run-image cnb/my-full-stack-run:bionic my-app-image
# OR
> /cnb/lifecycle/analyzer -layout -layout-dir /layout-repo -run-image cnb/my-full-stack-run:bionic my-app-image
expected analyzed.toml output
[run-image]
reference = "/layout-repo/index.docker.io/cnb/my-full-stack-run/bionic@sha256:fab3bb83de466ed29d7e9dcfdbee5b5fb2ff90e91bc849af85b261b4c2062a7a"
> export CNB_USE_LAYOUT=true
> export CNB_LAYOUT_DIR=/layout-repo
> /cnb/lifecycle/analyzer -run-image cnb/cnb/my-partial-stack-run:bionic my-app-image
# OR
> /cnb/lifecycle/analyzer -layout -layout-dir /layout-repo -run-image cnb/cnb/my-partial-stack-run:bionic my-app-image
expected analyzed.toml output
[run-image]
reference = "/layout-repo/index.docker.io/cnb/my-partial-stack-run@sha256:fab3bb83de466ed29d7e9dcfdbee5b5fb2ff90e91bc849af85b261b4c2062a7a"
> export CNB_USE_LAYOUT=true
> export CNB_LAYOUT_DIR=/layout-repo
> /cnb/lifecycle/analyzer -run-image cnb/my-full-stack-run:bionic -previous-image bar/my-previous-app my-app-image
# OR
> /cnb/lifecycle/analyzer -layout -layout-dir /layout-repo -run-image cnb/my-full-stack-run:bionic-previous-image bar/my-previous-app my-app-image
expected analyzed.toml output
[run-image]
reference = "/layout-repo/index.docker.io/cnb/my-partial-stack-run/bionic@sha256:fab3bb83de466ed29d7e9dcfdbee5b5fb2ff90e91bc849af85b261b4c2062a7a"
[previous-image]
reference = "/layout-repo/index.docker.io/bar/my-previous-app/latest@sha256:aa0cf7fc8f161bdb96166c1644174affacd70d17f372373ca72c8e91116e2d43"
> export CNB_USE_LAYOUT=true
> export CNB_LAYOUT_DIR=/layout-repo
> /cnb/lifecycle/analyzer -run-image cnb/bad-run-image my-app-image
# OR
> /cnb/lifecycle/analyzer -layout -layout-dir /layout-repo -run-image cnb/bad-run-image my-app-image
# expected output
ERROR: the run-image could not be found at path: /layout-repo/index.docker.io/cnb/bad-run-image/latest
> export CNB_USE_LAYOUT=true
> export CNB_LAYOUT_DIR=/layout-repo
> /cnb/lifecycle/analyzer my-app-image
# OR
> /cnb/lifecycle/analyzer -layout -layout-dir /layout-repo my-app-image
# expected output
ERROR: -run-image is required when OCI Layout feature is enabled
> export CNB_USE_LAYOUT=true
> /cnb/lifecycle/analyzer -run-image cnb/bad-run-image my-app-image
# OR
> /cnb/lifecycle/analyzer -layout -run-image cnb/bad-run-image my-app-image
# expected output
ERROR: defining a layout directory is required when OCI Layout feature is enabled. Use -layout-dir flag or CNB_LAYOUT_DIR environment variable
Let's also check some examples when the export phase is executed
> export CNB_USE_LAYOUT=true
> export CNB_LAYOUT_DIR=/layout-repo
> /cnb/lifecycle/exporter my-app-image
# OR
> /cnb/lifecycle/exporter -layout -layout-dir /layout-repo my-app-image
The output will be written into the repository folder described above and it should looks like this:
layout-repo
└── index.docker.io
├── cnb
│ └── my-full-stack-run:bionic
│ └── bionic
│ └── blobs
│ ├── sha256
│ │ ├── 1f59...944a // manifest
│ │ ├── 6388...af5a // config
│ │ ├── 824b...f984e
│ │ ├── f5f7...5b38
│ │ └── 870e...f1b09
│ ├── index.json
│ └── oci-layout
└── library
└── my-app-image
└── latest
├── blobs
│ └── sha256
│ ├── 1bcd5..x // app image manifest
│ ├── 2f789..d // app image config
│ ├── 824b...f984e // run layer
│ ├── f5f7...5b38 // run layer
│ ├── 870e...f1b09 // run layer
│ └── 3g234..f // buildpack layer
├── index.json
└── oci-layout
As we can see, the application image my-app-image
contains a full copy of the layers in its blobs
folder.
> export CNB_USE_LAYOUT=true
> export CNB_LAYOUT_DIR=/layout-repo
> /cnb/lifecycle/exporter my-app-image
# OR
> /cnb/lifecycle/exporter -layout -layout-dir /layout-repo my-app-image
Expected output:
layout-repo
└── index.docker.io
├── cnb
│ └── my-partial-stack-run:bionic
│ └── bionic
│ ├── blobs
│ │ └── sha256
│ │ ├── 1f59...944a // manifest
│ │ └── 6388...af5a // config
│ ├── index.json
│ └── oci-layout
└── library
└── my-app-image
└── latest
├── blobs
│ └── sha256
│ ├── 1bcd5..x // app image manifest
│ ├── 2f789..d // app image config
│ └── 3g234..f // buildpack layer
├── index.json
└── oci-layout
As we can see, the application image my-app-image
has missing blobs
because they were not provided as input and the lifecycle just skip writing those layers on disk.
Any combination of using multiple sources or sinks in the Lifecycle invocation of phases should throw an error to the user. For example:
> export CNB_USE_LAYOUT=true
> export CNB_LAYOUT_DIR=/layout-repo
> /cnb/lifecycle/exporter -daemon -run-image cnb/my-full-stack-run:bionic my-app-image
# OR
> /cnb/lifecycle/exporter -layout -layout-dir /layout-repo -daemon -run-image cnb/my-full-stack-run:bionic my-app-image
ERROR: exporting to multiple targets is unsupported
The lifecycle phases affected by this new behavior are:
At a high level view the proposed solution can be summarized with the following system landscape diagram from the C4 model
Notice that we are relying on the OCI format Specification to expose the data for Platforms
The following new inputs are proposed to be added to these phases
Input | Environment Variable | Default Value | Description |
---|---|---|---|
<layout> |
CNB_USE_LAYOUT |
false | Enables the capability of resolving image from/to in OCI layout format on disk |
<layout-dir> |
CNB_LAYOUT_DIR |
Path to a directory where the images are saved in OCI layout format |
In the previous examples one key element was how to translate an image reference into a path, let's define those rules.
Considering an image reference refers to either a tag reference or digest reference. It could have the following formats
- A name reference refers to an identifier of form
<registry>/<repo>/<image>:<tag>
- A digest reference refers to a content addressable identifier of form
<registry>/<repo>/<image>@<algorithm>:<digest>
The image look up will be done following these rules:
- WHEN
the image points to a name reference
- Lifecycle will load/save the image from/to disk in OCI Image Layout format at
<layout-dir>/<registry>/<repo>/<image>/<tag>
- Lifecycle will load/save the image from/to disk in OCI Image Layout format at
- WHEN
the image points to a digest reference
- Lifecycle will load the image from disk in OCI Image Layout format at
<layout-dir>/<registry>/<repo>/<image>/<algorithm>/<digest>
- Lifecycle will load the image from disk in OCI Image Layout format at
- WHEN
<registry>
is not provided default value will be index.docker.io- IF
<repo>
is not also provided, then default value will be library
- IF
In all the examples the new feature is enabled by the use of the new flag -layout
or by setting
the new environment variable CNB_USE_LAYOUT
to true.
Let's review some previous examples
Command:
> export CNB_USE_LAYOUT=true
> export CNB_LAYOUT_DIR=/layout-repo
> /cnb/lifecycle/analyzer -run-image cnb/my-full-stack-run:bionic my-app-image
# OR
> /cnb/lifecycle/analyzer -layout -layout-dir /layout-repo -run-image cnb/my-full-stack-run:bionic my-app-image
Arguments received:
run-image
:cnb/my-full-stack-run:bionic
image
:my-app-image
The <layout-dir>
is set with the value /layout-repo
Lifecycle applies the rules for looking up the images:
- It takes the tag reference
cnb/my-full-stack-run:bionic
, applies the conversion rules and gets/index.docker.io/cnb/my-full-stack-run/bionic
- It will append the
<layout-dir>
at the beginning, getting the following path:/layout-repo/index.docker.io/cnb/my-full-stack-run/bionic
- It will look for an image saved on disk in OCI Image Layout format at path
/layout-repo/index.docker.io/cnb/my-full-stack-run/bionic
. - In case of the application image it will look at path
/layout-repo/index.docker.io/library/my-app-image/latest
Because both images are found, the phase is executed as usual and the analyzed.toml
file will be updated. The run-image.reference
added into the analyzed.toml
will contain the path resolved by the lifecycle plus the digest reference to the image with the following format [path]@[digest]
. In case of this example, it will look like this:
[run-image]
reference = "/layout-repo/index.docker.io/cnb/my-partial-stack-run/bionic@sha256:fab3bb83de466ed29d7e9dcfdbee5b5fb2ff90e91bc849af85b261b4c2062a7a"
Command received:
> export CNB_USE_LAYOUT=true
> /cnb/lifecycle/analyzer -run-image cnb/cnb/my-partial-stack-run:bionic my-app-image
# OR
> /cnb/lifecycle/analyzer -layout -run-image cnb/cnb/my-partial-stack-run:bionic my-app-image
Arguments received:
run-image
:cnb/my-full-partial-run:bionic
image
:my-app-image
The <layout-dir>
is set with the default value /layout-repo
Noticed the structure of the run-image
provided
layout-repo
└── index.docker.io
└── cnb
└── my-partial-stack-run:bionic
└── bionic
├── blobs
│ └── sha256
│ ├── 1f59...944a // manifest
│ └── 6388...af5a // config
├── index.json
└── oci-layout
Similar to the previous example, Lifecycle applies the rules for looking up the images and look at path /layout-repo/index.docker.io/cnb/my-partial-stack-run/bionic
and it determines a partial image was provided and execute the phase with the information from the Image Manifest and the Image Config
The output analyzed.toml
will also include the new run-image.reference
field the path and the digest of the run image.
[run-image]
reference = "/layout-repo/index.docker.io/cnb/my-partial-stack-run/bionic@sha256:fab3bb83de466ed29d7e9dcfdbee5b5fb2ff90e91bc849af85b261b4c2062a7a"
Command received:
> export CNB_USE_LAYOUT=true
> /cnb/lifecycle/analyzer -run-image cnb/my-full-stack-run:bionic -previous-image bar/my-previous-app my-app-image
# OR
> /cnb/lifecycle/analyzer -layout -run-image cnb/my-full-stack-run:bionic -previous-image bar/my-previous-app my-app-image
Arguments received:
run-image
:cnb/my-full-stack-run:bionic
previous-image
:bar/my-previous-app
image
:my-app-image
The <layout-dir>
is set with the default value /layout-repo
run-image
and image
arguments are treated in the same way as previous examples, and for previous-image
argument the looking up images rules are applied and Lifecycle will look at path /index.docker.io/bar/my-previous-app
for a image in OCI Image Layout format.
The analyzed.toml
file es expected to be updated with the previous-image.reference
containing the path and the digest of the previous-image
[run-image]
reference = "/layout-repo/index.docker.io/cnb/my-full-stack-run/bionic@sha256:fab3bb83de466ed29d7e9dcfdbee5b5fb2ff90e91bc849af85b261b4c2062a7a"
[previous-image]
reference = "/layout-repo/index.docker.io/bar/my-previous-app/latest@sha256:aa0cf7fc8f161bdb96166c1644174affacd70d17f372373ca72c8e91116e2d43"
Let's check how the export
examples works on detailed
Pre-conditions:
The following directories are accessible by the lifecycle
/
├── layout-repo
│ └── index.docker.io
│ └── cnb
│ └── my-full-stack-run:bionic
│ └── bionic
│ └── blobs
│ ├── sha256
│ │ ├── 1f59...944a // manifest
│ │ ├── 6388...af5a // config
│ │ ├── 824b...f984e
│ │ ├── f5f7...5b38
│ │ └── 870e...f1b09
│ ├── index.json
│ └── oci-layout
└── layers
└── analyzed.tom
The /layers/analyzed.toml
file contains the following data:
[run-image]
reference = "/layout-repo/index.docker.io/cnb/my-full-stack-run/bionic@sha256:fab3bb83de466ed29d7e9dcfdbee5b5fb2ff90e91bc849af85b261b4c2062a7a"
Command executed:
> export CNB_USE_LAYOUT=true
> /cnb/lifecycle/exporter my-app-image
# OR
> /cnb/lifecycle/exporter -layout my-app-image
Arguments received:
image
:my-app-image
The <layout-dir>
is set with the default value /layout-repo
Lifecycle:
- It will read the
[run-image]
section in theanalyzed.toml
, it will parsereference
attribute using the@
separator and load therun-image
image saved on disk in OCI Image Layout format at path/layout-repo/index.docker.io/cnb/my-full-stack-run/bionic
. - Lifecycle could also validate the digest of the image loaded is the same as the one established by the
reference
. - Lifecycle will execute the export steps and at the end of the process it will write the application image at path
/layout-repo/index.docker.io/library/my-app-image/latest
in OCI Image Layout format
The output image will be written at:
layout-repo
└── index.docker.io
└── library
└── my-app-image
└── latest
├── blobs
│ └── sha256
│ ├── 1bcd5..x // app image manifest
│ ├── 2f789..d // app image config
│ ├── 824b...f984e // run layer
│ ├── f5f7...5b38 // run layer
│ ├── 870e...f1b09 // run layer
│ └── 3g234..f // buildpack layer
├── index.json
└── oci-layout
In order to validate the feasibility of the proposed feature, we developed a proof of concept with one of the most important side effects this capability can add into the project: Removing the Daemon Support. You can also check a recording with the demo in the following link
As mentioned earlier, if we want to remove the daemon support in the Lifecycle, then all the responsibility to deal with it goes into the platforms implementors, that means, for example:
- Pull the require dependencies (runtime image for example), save them on disk in OCI layout format and pass it through the lifecycle using the
<layout-dir>
parameter - Push the application image (exported in OCI layout format) into the Daemon, because that is what users are expecting.
During the proof of concept implementation I choose to use skopeo tool to solve the problem of interacting with the Daemon. The reason to do it was simplicity for the PoC developed but we believe this is a good subject to talk about with the community.
The following workflow was developed:
- Pack download the skopeo image, similar as it is downloading the other dependencies (Lifecycle, Buildpacks)
- Pack executes skopeo copy command in a container
- Copy image from the Daemon into the filesystem, in OCI layout format, before running Lifecycle
- Copy image from filesystem into the Daemon after the export phase was executed
The following Dynamic Diagram from the C4 model, can give a little idea of the pieces implemented during the Poc
In order to have an idea on how much is affected the performance of exporting to the Daemon using the OCI layout format, the following metrics were taken.
Using a local workstation with the following specifications:
- (MacOS 12.3.1 / 2,4 GHz 8-Core Intel Core i9 / 32 GB 2667 MHz DDR4 / 1 TB APFS SSD HD)
We built 5 times the Java, Kotlin and Ruby samples codes from our repository and took the building's average time using the Daemon and the OCI layout format approaches.
The table above summarized the results we got.
Times are expressed in seconds and the first thing we noticed is for Java and Kotlin the build time
can be affected by the network and the availability of maven repositories, so I decided to take the same build time
to compare both approaches.
Here are my thoughts about these results:
- Java and Kotlin behavior are very similar, exporting only to OCI format increases 5% the time compared to Daemon approach, and from user perspective it represents a 5 seconds increase of time.
- On the other hand for the Ruby application, exporting to OCI format represents a 20% increase of the time but from user perspective it is only 1.5 seconds which is probably difficult to notice from user perspective.
- When the time spent for Pack to prepare the environment for the lifecycle execution (downloading the run-image from a registry to OCI format) and loading the OCI image from disk to the Daemon (which is the expected behavior from Users) is added, then:
- The Java and Kotlin applications time increases was 13%, representing +13 seconds from user perspective
- The Ruby application increases 82% but from user's side it represents +7 seconds
Let's take a look on what happened when we execute a build for the second time, the table below summarized the results
On these cases we can see the behavior is consistent compared with the previous case, Java and Kotlin application shows a 5% increase of time but Ruby application, because it's process time is smaller the sensibility to variation is bigger (23%) but in reality it represents a +1 second of difference for the User. Also, when the pre and post processing time is added the variations are bigger for all the applications. As mentioned, skopeo tool was used here and most of the time spent goes into this category.
I think, this PoC demonstrate that adding the exporting to OCI layout format is a valuable feature for the project, it opens the door to deprecate the use of Daemon but it will requires that platform implementors to prepare and post-process the output on disk on a smart way to reduce the performance penalties to users.
- No breaking changes were identified
- We could increase the disk space if we do not manage the duplication of saving the layers on disk. The proposal suggests to use symbolic links to reference layers on disk and avoid duplication.
-
What other designs have been considered?
- Doing nothing, just keep exporting only to Daemon or Registry
-
What other designs have been considered for removing the Daemon support?
- Instead of exporting to OCI layout format, the other approach considered is exporting to registry only. In this case, the Lifecycle only interacts with registries.
As part of the PoC, I took some metrics to compare impact of using a ephemeral registry to publish the application image. The strategy done to capture the metrics was:
- I used a script to set up a local container registry before executing the
pack build
command - For the first build metrics, the registry was destroyed/re-created before each execution
pack build
command was configure to--publish
in the local registry- I didn't use the skopeo in these cases to complete the pushing into the Daemon
- I used a script to set up a local container registry before executing the
Here are the results:
- The results are actually very similar to exporting to OCI layout format for Java and Kotlin, but Ruby application is actually worst.
- Second build is actually better compared with the export to OCI in disk, Java and Kotlin increases the time just by 2%, but Ruby again is worst
Some thoughts about this approaches
- Process Management: Platforms must now manage a parallel process (registry in the daemon). This would entail ensuring that the registry is started and cleaned up appropriately.
- Networking: There are additional network complications in order to route images to the ephemeral registry. For example, network drivers, proxy and DNS configuration, host name resolution, and TLS certificates to name a few.
- Instead of exporting to OCI layout format, the other approach considered is exporting to registry only. In this case, the Lifecycle only interacts with registries.
As part of the PoC, I took some metrics to compare impact of using a ephemeral registry to publish the application image. The strategy done to capture the metrics was:
-
Why is this proposal the best? OCI Image Layout format is a standard from which other tools can create a OCI Runtime Specification bundle exporting to this format enables Platforms to implement any feature in the top of this format, for example, exporting to containerd has been requested by the community and it could be implemented if we can get the application image exported in OCI Image Layout format.
-
What is the impact of not doing this? Probably will never remove the Daemon support in the Lifecycle
- Discussion around removing the Daemon support RFC
-
What parts of the design do you expect to be resolved before this gets merged?
- Tools like umoci used to create a runtime bundle from an image in OCI layout format, requires the annotation
org.opencontainers.image.ref.name
to be present. Also tools like skopeo when an image iscopy
in oci format the annotation is included. We are not adding the annotation as part of the Buildpacks Specification, but in this case this could make our output incompatible with some other tooling.- Answer: we agreed on adding
org.opencontainers.image.ref.name
annotation
- Answer: we agreed on adding
- Exporting to a tarball can be handled on this RFC or a new one must be created?
- Answer: this can be handled on a different RFC
- Tools like umoci used to create a runtime bundle from an image in OCI layout format, requires the annotation
-
What parts of the design do you expect to be resolved through implementation of the feature?
- Handle symbolic links to the blobs in the
<layout-dir>
repository, this could be more efficient on hard drive space- Answer: this can be handled on the implementation side
- Handle symbolic links to the blobs in the
The Platform Interface Specification must be updated to include the following inputs to the Create, Analyze and Export phases
Input | Environment Variable | Default Value | Description |
---|---|---|---|
<layout> |
CNB_USE_LAYOUT |
false | Enables the capability of resolving image from/to in OCI layout format on disk |
<layout-dir> |
CNB_LAYOUT_DIR |
Path to a directory where the images are saved in OCI layout format |
Also the analyzed.toml
file will be updated to include the reference
format in case of layout is being used.
[image]
reference = "<image reference>"
[run-image]
reference = "<image reference>"
[previous-image]
reference = "<image reference>"
Where
[image|run-image|previos-image].reference
MUST be either:- A digest reference to an image in an OCI registry
- The ID of an image in a docker daemon
- The path to an image in OCI layout format