From fc19b12708556d5c414169845eaec2ba642860a5 Mon Sep 17 00:00:00 2001 From: Domenico Luciani Date: Thu, 20 Jul 2023 15:45:13 +0200 Subject: [PATCH 1/5] RFC Flatten builders and buildpacks Signed-off-by: Domenico Luciani --- text/XXX-flatten-feature.md | 325 ++++++++++++++++++++++++++++++++++++ 1 file changed, 325 insertions(+) create mode 100644 text/XXX-flatten-feature.md diff --git a/text/XXX-flatten-feature.md b/text/XXX-flatten-feature.md new file mode 100644 index 000000000..779be67bd --- /dev/null +++ b/text/XXX-flatten-feature.md @@ -0,0 +1,325 @@ +# Meta +[meta]: #meta +- Name: Flatten builders and buildpacks +- Start Date: 2023-07-13 +- Author(s): @jjbustamante, @dlion +- Status: Draft +- RFC Pull Request: (leave blank) +- CNB Pull Request: (leave blank) +- CNB Issue: (leave blank) +- Supersedes: (put "N/A" unless this replaces an existing RFC, then link to that RFC) + +# Summary +[summary]: #summary + +We propose to add new capabilities to the Pack tool that allow end users to reduce the number of Buildpack's layers in an OCI image by flattening according to their requirements. + +# Definitions +[definitions]: #definitions + +- Buildpack: A buildpack is a set of executables that inspects your app source code and creates a plan to build and run your application. +- Builder: A builder is an image that contains all the components necessary to execute a build. A builder image is created by taking a build image and adding a lifecycle, buildpacks, and files that configure aspects of the build including the buildpack detection order and the location(s) of the run image + +# Motivation +[motivation]: #motivation + +- Why should we do this? + +There is a limit in the number of layer an image can have, at least on Docker, which is *127*, this feature has being request by the community, issue [#1595](https://github.com/buildpacks/pack/issues/1595), as a workaround to solve error thrown by docker when the limit is reached + +- What use cases does it support? + +Buildpacks provider like Paketo have composite buildpacks with several layers, when they pull many of those together into a builder, hitting the layer limit for a container image happens very often. A feature for the Buildpack author to group the buildpacks by any attribute will allow them to squash those groups into one layer and reduce their total number of layers, avoiding the layer limit. + +- What is the expected outcome? + +When Buildpacks Authors execute commands like: + +`pack builder create ... ` or +`pack buildpack package ... ` + +The final OCI image artifact (A) SHOULD contain layers blobs with more than *one* buildpack according to the configuration provided by the user. If we compare an artifact (B) created *without* `` then: + +$numberOfBuildpackLayers(A) \leq numberOfBuildpackLayers(B)$ + +A and B MUST be otherwise interchangeable, only differing by their number of layers. + + +# What it is +[what-it-is]: #what-it-is + +The proposal is to include new experimental flags to the following commands on pack: + +- `pack builder create` +- `pack buildpack package` + +The new flags will move from experimental status to supported status when maintainers deem it appropriate. + +The new flags to be included are: + +- `--flatten` will flatten all the Buildpacks in one layer +- `--flatten --depth=` If there are composite buildpack to be flatten, `depth` is the high in the buildpack dependency tree to start flattening the buildpacks +- `--flatten --flatten-exclude=` will flatten all the Buildpacks in one layer excepts the ones specified under the `flatten-exclude` flag +- `--flatten --flatten-include=` will flatten the Buildpacks specified after the `flatten-include` flag into a single layer. Can be used more than once, with each use resulting in a single layer. + +We also need to define how a platform implementor needs to consume a flatten buildpackpage or builder. + +- When a platform consumes an OCI image artifact, they will need to inspect each buildpack layer blob and determine if the blob contains more than one buildpack, in such as case, they will need to process those buildpacks correctly. + + +# How it Works +[how-it-works]: #how-it-works + +Let's say we have a composite buildpack (CB1) with the following dependency tree: +```mermaid +flowchart TD + A[CB1] + A --> B[G1] + A --> C[G2] + B --> BPA[BP1] + B --> BPFOO[BP2] + B --> BPC[BP4] + C --> BPD[BP1] + C --> BPBAR[BP3] + C --> BPE[BP4] +``` + +Until now, when a buildpack like this is being shipped into an OCI image every individual buildpack is being saved in one layer, as a result we will have: + +$$ + layer_1 = [CB_1] \\ + layer_2 = [G_1] \\ + layer_3 = [BP_1] \\ + layer_4 = [BP_2] \\ + layer_5 = [BP_4] \\ + layer_6 = [G_2] \\ + layer_7 = [BP_3] \\ + total = \text{7 layers} +$$ + +Noticed that duplicated buildpacks are cleaned up. + +We can use the new `flatten` flag to reduce the number of OCI image layers used by the buildpacks in different ways. + +* `--flatten`: +Will flatten all buildpacks into one layer, the result will be: + +```mermaid +classDiagram + class Layer1 { + CB1 + G1 + BP1 + BP2 + BP4 + G2 + BP3 + } +``` + + +$$ + total = \text{1 layer} +$$ + +--- +* `--flatten --flatten-exclude=` i.e. `--flatten-exclude=` +Will flatten all buildpacks in 1 layer except for`BP2`, the result will be + +```mermaid +classDiagram + class Layer1 { + CB1 + G1 + BP1 + BP4 + G2 + BP3 + } + class Layer2 { + BP2 + } +``` + +$$ + total = \text{2 layers} +$$ + +--- + +* `--flatten --depth=0` +Will flatten all layers at the root (0) level, which is similar to flatten all, the result will be: + +```mermaid +classDiagram + class Layer1 { + CB1 + G1 + BP1 + BP2 + BP4 + G2 + BP3 + } +``` + +$$ + total = \text{1 layer} +$$ + +--- +Increasing the depth number will allow to flatten the tree deeper, +for example setting `--depth=1`, the result will be: + +```mermaid +classDiagram + class Layer1 { + CB1 + } + class Layer2 { + G1 + BP1 + BP2 + BP4 + } + class Layer3 { + G2 + BP3 + } +``` + + +$$ + total = \text{3 layers} +$$ + + +--- + +* `--flatten --flatten-include=` i.e. `--flatten --flatten-include= --flatten-include=` + +Will group the given buildpacks into one layer and keep the other ones as single layers buildpacks, the result will be: + +```mermaid +classDiagram + class Layer1 { + CB1 + } + class Layer2 { + G1 + } + class Layer3 { + BP1 + BP2 + } + class Layer4 { + G2 + } + class Layer5 { + BP3 + BP4 + } +``` + + +$$ + total = \text{5 layers} +$$ + + +# Migration +[migration]: #migration + +The current [distribution spec](https://github.com/buildpacks/spec/blob/main/distribution.md#buildpackage) defines: + +``` +Each buildpack layer blob MUST contain a single buildpack at the following file path: + +/cnb/buildpacks/// +``` + +A Buildpackage flattened with this new feature would not be consumable by older platform implementations because they are not expecting to find more than one buildpack on a blob layer. + + + +# Drawbacks +[drawbacks]: #drawbacks + +Why should we *not* do this? + +Distributing a buildpackage with more than one buildpack in a layer blob adds complexity to platform implementors because they will need to do the opposite process when consuming the OCI images. + +It will add complexity to Buildpack Authors processes because they will need to think how to group their buildpacks together in a layer blob in an efficient way avoiding for example network issues when pulling new blobs from a registry. Size, frequency of change and other variables must be taken into consideration when buildpacks are flatten. + +It will create artifacts that are not consumable by older platforms. + + +# Alternatives +[alternatives]: #alternatives + +- What other designs have been considered? + +Some other alternatives mentioned are: squashing by the buildpack size or squashing a CNB Builder when the number of layers is reaching the limit, but those ideas, do not deal with the main problems of distributing more than one buildpack in a layer blob. + + +- Why is this proposal the best? + +Not sure if it is the best, but way to solve the `layer limit error` is to optimize the uses of the layer in a OCI image. + +- What is the impact of not doing this? + +Buildpack Authors and Platform Operators will keep seeing the layer limit error. + +# Prior Art +[prior-art]: #prior-art + +Discuss prior art, both the good and bad. + +# Unresolved Questions +[unresolved-questions]: #unresolved-questions + +- What parts of the design do you expect to be resolved before this gets merged? + +We think the `--depth` command MAY not be helpful, after implementing a PoC. Should we get rid of this flag? + + + + +# Spec. Changes (OPTIONAL) +[spec-changes]: #spec-changes + +Maybe, but it's not clear about this. + + + +# History +[history]: #history + +% \ No newline at end of file From c33e34be8340f4715c8dc1c3c8f4970eb5f585a2 Mon Sep 17 00:00:00 2001 From: Domenico Luciani Date: Tue, 1 Aug 2023 15:41:47 +0200 Subject: [PATCH 2/5] Renamed rfc Signed-off-by: Domenico Luciani --- text/{XXX-flatten-feature.md => 0000-flatten-feature.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename text/{XXX-flatten-feature.md => 0000-flatten-feature.md} (100%) diff --git a/text/XXX-flatten-feature.md b/text/0000-flatten-feature.md similarity index 100% rename from text/XXX-flatten-feature.md rename to text/0000-flatten-feature.md From 61e166c3b7111acffb87f9ad8684a0f0f79ff14c Mon Sep 17 00:00:00 2001 From: Domenico Luciani Date: Tue, 1 Aug 2023 17:11:53 +0200 Subject: [PATCH 3/5] Updated the RFC based on the feedback we got from our stakelholders Signed-off-by: Domenico Luciani --- text/0000-flatten-feature.md | 143 +++++------------------------------ 1 file changed, 20 insertions(+), 123 deletions(-) diff --git a/text/0000-flatten-feature.md b/text/0000-flatten-feature.md index 779be67bd..19924580d 100644 --- a/text/0000-flatten-feature.md +++ b/text/0000-flatten-feature.md @@ -38,7 +38,7 @@ When Buildpacks Authors execute commands like: `pack builder create ... ` or `pack buildpack package ... ` -The final OCI image artifact (A) SHOULD contain layers blobs with more than *one* buildpack according to the configuration provided by the user. If we compare an artifact (B) created *without* `` then: +The final OCI image artifact (A) SHOULD contain layers blobs with more than *one* buildpack according to the configuration provided by the user. If we compare an artifact (B) created *without* `` then: $numberOfBuildpackLayers(A) \leq numberOfBuildpackLayers(B)$ @@ -57,10 +57,7 @@ The new flags will move from experimental status to supported status when mainta The new flags to be included are: -- `--flatten` will flatten all the Buildpacks in one layer -- `--flatten --depth=` If there are composite buildpack to be flatten, `depth` is the high in the buildpack dependency tree to start flattening the buildpacks -- `--flatten --flatten-exclude=` will flatten all the Buildpacks in one layer excepts the ones specified under the `flatten-exclude` flag -- `--flatten --flatten-include=` will flatten the Buildpacks specified after the `flatten-include` flag into a single layer. Can be used more than once, with each use resulting in a single layer. +- `--flatten=` will flatten the Buildpacks specified after the `flatten` flag into a single layer. Can be used more than once, with each use resulting in a single layer. We also need to define how a platform implementor needs to consume a flatten buildpackpage or builder. @@ -86,119 +83,23 @@ flowchart TD Until now, when a buildpack like this is being shipped into an OCI image every individual buildpack is being saved in one layer, as a result we will have: -$$ - layer_1 = [CB_1] \\ - layer_2 = [G_1] \\ - layer_3 = [BP_1] \\ - layer_4 = [BP_2] \\ - layer_5 = [BP_4] \\ - layer_6 = [G_2] \\ - layer_7 = [BP_3] \\ - total = \text{7 layers} $$ - -Noticed that duplicated buildpacks are cleaned up. - -We can use the new `flatten` flag to reduce the number of OCI image layers used by the buildpacks in different ways. - -* `--flatten`: -Will flatten all buildpacks into one layer, the result will be: - -```mermaid -classDiagram - class Layer1 { - CB1 - G1 - BP1 - BP2 - BP4 - G2 - BP3 - } -``` - - -$$ - total = \text{1 layer} -$$ - ---- -* `--flatten --flatten-exclude=` i.e. `--flatten-exclude=` -Will flatten all buildpacks in 1 layer except for`BP2`, the result will be - -```mermaid -classDiagram - class Layer1 { - CB1 - G1 - BP1 - BP4 - G2 - BP3 - } - class Layer2 { - BP2 - } -``` - -$$ - total = \text{2 layers} -$$ - ---- - -* `--flatten --depth=0` -Will flatten all layers at the root (0) level, which is similar to flatten all, the result will be: - -```mermaid -classDiagram - class Layer1 { - CB1 - G1 - BP1 - BP2 - BP4 - G2 - BP3 - } -``` - -$$ - total = \text{1 layer} +layer_1 = [CB_1] \\ +layer_2 = [G_1] \\ +layer_3 = [BP_1] \\ +layer_4 = [BP_2] \\ +layer_5 = [BP_4] \\ +layer_6 = [G_2] \\ +layer_7 = [BP_3] \\ +total = \text{7 layers} $$ ---- -Increasing the depth number will allow to flatten the tree deeper, -for example setting `--depth=1`, the result will be: +Noticed that duplicated buildpacks are cleaned up. -```mermaid -classDiagram - class Layer1 { - CB1 - } - class Layer2 { - G1 - BP1 - BP2 - BP4 - } - class Layer3 { - G2 - BP3 - } -``` - - -$$ - total = \text{3 layers} -$$ - - ---- - -* `--flatten --flatten-include=` i.e. `--flatten --flatten-include= --flatten-include=` +We can use the new `flatten` flag to reduce the number of OCI image layers used by the buildpacks in different ways. -Will group the given buildpacks into one layer and keep the other ones as single layers buildpacks, the result will be: +* `--flatten=` i.e. `--flatten= --flatten=`: + Will group the given buildpacks into one layer and keep the other ones as single layers buildpacks, the result will be: ```mermaid classDiagram @@ -222,9 +123,11 @@ classDiagram ``` -$$ - total = \text{5 layers} $$ +total = \text{5 layers} +$$ + +--- # Migration @@ -270,20 +173,14 @@ Not sure if it is the best, but way to solve the `layer limit error` is to optim - What is the impact of not doing this? -Buildpack Authors and Platform Operators will keep seeing the layer limit error. +Buildpack Authors and Platform Operators will keep seeing the layer limit error. # Prior Art [prior-art]: #prior-art Discuss prior art, both the good and bad. -# Unresolved Questions -[unresolved-questions]: #unresolved-questions - -- What parts of the design do you expect to be resolved before this gets merged? - -We think the `--depth` command MAY not be helpful, after implementing a PoC. Should we get rid of this flag? - +--- @@ -12,7 +12,9 @@ # Summary [summary]: #summary -We propose to add new capabilities to the Pack tool that allow end users to reduce the number of Buildpack's layers in an OCI image by flattening according to their requirements. +We propose to add new capabilities to the Pack tool that allow end-users to reduce the number of Buildpack's layers in a Builder by flattening some Buildpacks according to their requirements. + +This RFC mainly focus on applying this strategy to Builders only. # Definitions [definitions]: #definitions @@ -21,7 +23,7 @@ We propose to add new capabilities to the Pack tool that allow end users to redu - Builder: A builder is an image that contains all the components necessary to execute a build. A builder image is created by taking a build image and adding a lifecycle, buildpacks, and files that configure aspects of the build including the buildpack detection order and the location(s) of the run image - Component Buildpack: A component buildpack is a buildpack containing `/bin/detect` and `/bin/build` executables. Component buildpacks implement the [Buildpack Interface](https://github.com/buildpacks/spec/blob/main/buildpack.md). - Composite Buildpack: A composite buildpack is a buildpack containing an order definition in `buildpack.toml`. Composite buildpacks do not contain `/bin/detect` or `/bin/build` executables. They MUST be [resolvable](https://github.com/buildpacks/spec/blob/main/buildpack.md#order-resolution) into a collection of component buildpacks. -- Buildpackage: A buildpackage is a [distributable](https://github.com/buildpacks/spec/blob/main/distribution.md) artifact that contains a buildpack. +- Buildpackage: A buildpackage is a [distributable](https://github.com/buildpacks/spec/blob/main/distribution.md) artifact that contains a buildpack. # Motivation [motivation]: #motivation @@ -32,16 +34,15 @@ There is a limit in the number of layer an image can have, at least on Docker, w - What use cases does it support? -Buildpacks provider like Paketo have composite buildpacks with several layers, when they pull many of those together into a builder, hitting the layer limit for a container image happens very often. A feature for the Buildpack author to group the buildpacks by any attribute will allow them to squash those groups into one layer and reduce their total number of layers, avoiding the layer limit. +Buildpacks provider like Paketo have Composite Buildpacks with several layers, when they pull many of those together into a Builder, hitting the layer limit for a container image happens very often. A feature for the Builder author to group the Buildpacks by any attribute will allow them to squash those groups into one layer and reduce their total number of layers, avoiding the layer limit. - What is the expected outcome? -When Buildpacks Authors execute commands like: +When Builder Authors execute the command: -`pack builder create ... ` or -`pack buildpack package ... ` +`pack builder create ... ` -The final OCI image artifact (A) SHOULD contain layers blobs with more than *one* buildpack according to the configuration provided by the user. If we compare an artifact (B) created *without* `` then: +The final Builder (A) SHOULD contain layers blobs with more than *one* buildpack according to the configuration provided by the user. If we compare an artifact (B) created *without* `` then: $numberOfBuildpackLayers(A) \leq numberOfBuildpackLayers(B)$ @@ -51,26 +52,25 @@ A and B MUST be otherwise interchangeable, only differing by their number of lay # What it is [what-it-is]: #what-it-is -The proposal is to include new experimental flags to the following commands on pack: +The proposal is to include a new experimental flag to the following command on Pack: - `pack builder create` -- `pack buildpack package` -The new flags will move from experimental status to supported status when maintainers deem it appropriate. +The new flag will move from experimental status to supported status when maintainers deem it appropriate. -The new flags to be included are: +The new flag to be included is: - `--flatten=` will flatten the Buildpacks specified after the `flatten` flag into a single layer. Can be used more than once, with each use resulting in a single layer. -We also need to define how a platform implementor needs to consume a flatten buildpackpage or builder. +We also need to define how a Platform implementor needs to consume a flattened Builder. -- When a platform consumes an OCI image artifact, they will need to inspect each buildpack layer blob and determine if the blob contains more than one buildpack, in such as case, they will need to process those buildpacks correctly. +- When a Platform consumes a Builder, they will need to inspect each Buildpack layer blob and determine if the blob contains more than one Buildpack, in such as case, they will need to process those Buildpacks correctly. # How it Works [how-it-works]: #how-it-works -Let's say we have a composite buildpack (CB1) with the following dependency tree: +Let's say we have a Composite Buildpack (CB1) with the following dependency tree: ```mermaid flowchart TD A[CB1] @@ -84,7 +84,7 @@ flowchart TD C --> BPE[BP4] ``` -Until now, when a buildpack like this is being shipped into an OCI image every individual buildpack is being saved in one layer, as a result we will have: +Until now, when a Buildpack like this is being shipped into a Builder every individual Buildpack is being saved in one layer, as a result we will have: $$ layer_1 = [CB_1] \\ @@ -97,12 +97,12 @@ layer_7 = [BP_3] \\ total = \text{7 layers} $$ -Noticed that duplicated buildpacks are cleaned up. +Noticed that duplicated Buildpacks are cleaned up. -We can use the new `flatten` flag to reduce the number of OCI image layers used by the buildpacks in different ways. +We can use the new `flatten` flag to reduce the number of Builder layers used by the buildpacks in different ways. * `--flatten=` i.e. `--flatten= --flatten=`: - Will group the given buildpacks into one layer and keep the other ones as single layers buildpacks, the result will be: + Will group the given Buildpacks into one layer and keep the other ones as single layers Buildpacks, the result will be: ```mermaid classDiagram @@ -136,6 +136,7 @@ $$ # Migration [migration]: #migration + The current [distribution spec](https://github.com/buildpacks/spec/blob/main/distribution.md#buildpackage) defines: ``` @@ -144,7 +145,7 @@ Each buildpack layer blob MUST contain a single buildpack at the following file /cnb/buildpacks/// ``` -A Buildpackage and a Builder flattened with this new feature would not be consumable by older platform implementations because they are not expecting to find more than one buildpack on a blob layer. +A Builder flattened with this new feature would not be consumable by older platform implementations because they are not expecting to find more than one buildpack on a blob layer.