Skip to content

Commit 7c339b5

Browse files
authored
Merge branch 'main' into dependabot/github_actions/actions/checkout-4
2 parents f3c0501 + 6951d98 commit 7c339b5

File tree

2 files changed

+163
-0
lines changed

2 files changed

+163
-0
lines changed
Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
+++
2+
title="The finer points of image extensions"
3+
weight=406
4+
+++
5+
6+
# Guidance for extension authors
7+
8+
## During detect
9+
10+
### Expressing provided dependencies through the build plan
11+
12+
The [build plan](/docs/reference/spec/buildpack-api#build-plan) is a mechanism for inter-buildpack communication.
13+
Through the build plan, buildpacks may express the dependencies they require, as well as those they provide.
14+
The lifecycle uses information from the build plan to determine whether a group of buildpacks is compatible - that is, whether for every buildpack in the group, its required dependencies are provided by a buildpack that comes before it.
15+
16+
Extensions can use the build plan too - but they are only allowed to provide dependencies, they cannot require any.
17+
Note that because there is a separate order for extensions that is prepended to each buildpack group during the `detect` phase,
18+
all extension "provides" come before all buildpack "requires" in the build plan.
19+
20+
During the `detect` phase, the lifecycle sets a `CNB_OUTPUT_DIR` environment variable when executing each `./bin/detect`.
21+
If using a build plan, extensions should write the plan to `$CNB_OUTPUT_DIR/plan.toml`.
22+
23+
## During generate
24+
25+
### Configuring build args
26+
27+
During the `generate` phase, extensions may output (in addition to Dockerfiles) an `extend-config.toml`
28+
containing build-time arguments for Dockerfiles.
29+
(Not to be confused with the `build` phase, "build" here refers to the application of Dockerfiles to a base image,
30+
similar to a `docker build`).
31+
32+
Arguments may be configured for builder image extension or runtime base image extension or both,
33+
according to the schema defined in the [spec](https://github.com/buildpacks/spec/blob/main/image_extension.md#extend-configtoml-toml).
34+
35+
During the `generate` phase, the lifecycle sets a `CNB_OUTPUT_DIR` environment variable when executing each `./bin/generate`.
36+
If using an `extend-config.toml`, extensions should write the config to `$CNB_OUTPUT_DIR/extend-config.toml`.
37+
38+
### Invalidating the build cache with the UUID build arg
39+
40+
Whenever possible, the application of Dockerfiles to a base image will use a caching mechanism
41+
similar to that of a `docker build`.
42+
The lifecycle, for example, uses [`kaniko`](https://github.com/GoogleContainerTools/kaniko) to implement the `extender`.
43+
44+
However, there may be times when caching is not desired - for example, when fetching the "latest" available version of a package.
45+
In such cases, Dockerfiles can use the `build_id` build argument to invalidate the cache for all instructions that follow.
46+
47+
As an example:
48+
49+
```bash
50+
RUN echo "this instruction may be found in the cache"
51+
52+
ARG build_id=0
53+
RUN echo ${build_id}
54+
55+
RUN echo "this instruction should never be found in the cache, as the value above will change"
56+
```
57+
58+
Note that `build_id` is defaulted to `0` as a best practice.
59+
60+
### Re-setting the user/group with build args
61+
62+
Dockerfiles from image extensions may contain `USER root` instructions in order to perform actions that would not be possible
63+
when running as a non-root user.
64+
65+
However, for security reasons, the final user after all Dockerfiles have been applied should _not_ be root.
66+
To reset the user to its original value (before the application of the current Dockerfile),
67+
Dockerfiles should make use of `user_id` and `group_id` build arguments, as seen below:
68+
69+
```bash
70+
ARG user_id=1000
71+
ARG group_id=1000
72+
USER ${user_id}:${group_id}
73+
```
74+
75+
### Making 'rebasable' changes
76+
77+
Image layers generated from extensions are "above the rebasable seam" - that is,
78+
after swapping the runtime image to an updated version through a `rebase` operation,
79+
the extension layers will be persisted in the rebased application image.
80+
81+
Unlike buildpack layers, extension layers are _not_ always safe to rebase.
82+
Extension layers _may_ be safe to rebase if:
83+
* the changes they introduce are purely additive (no modification of pre-existing files from the base image), or
84+
* any modified pre-existing files are safe to exclude from rebase (the file from the extension layer will override any updated version of the file from the new runtime base image)
85+
86+
By default, the lifecycle will assume that any extension layers are _not_ rebasable.
87+
To indicate otherwise, `run.Dockerfile`s should include:
88+
89+
```bash
90+
LABEL io.buildpacks.rebasable=true
91+
```
92+
93+
If all `run.Dockerfile`s set this label to `true`, the application image will contain the label `io.buildpacks.rebasable=true`.
94+
Otherwise, the application image will contain the label `io.buildpacks.rebasable=false`.
95+
`pack rebase` requires a `--force` flag if the application image contains `io.buildpacks.rebasable=false`.
96+
97+
Extension authors should take great care (and perform testing) to ensure that any layers marked as rebasable are in fact rebasable.
98+
99+
## In general
100+
101+
### Choosing an extension ID
102+
103+
Extension IDs must be globally unique to extensions, but extensions and buildpacks can share the same ID.
104+
105+
### Expressing information in extension.toml
106+
107+
Just like `buildpack.toml`, an `extension.toml` can contain additional metadata to describe its behavior.
108+
See the [spec](https://github.com/buildpacks/spec/blob/main/image_extension.md#extensiontoml-toml) for more information.
109+
110+
### Pre-populating output
111+
112+
The root directory for a typical extension might look like the following:
113+
114+
```
115+
.
116+
├── bin
117+
│ ├── detect
118+
│ ├── generate
119+
├── extension.toml
120+
```
121+
122+
But it could also look like any of the following:
123+
124+
#### ./bin/detect is optional!
125+
126+
If `./bin/detect` is missing,
127+
the extension is assumed to pass detection and
128+
the lifecycle will interpret the contents of `./detect` as the contents of `$CNB_OUTPUT_DIR`.
129+
130+
```
131+
.
132+
├── bin
133+
│ ├── generate
134+
├── detect
135+
│ ├── plan.toml
136+
├── extension.toml
137+
```
138+
139+
#### ./bin/generate is optional!
140+
141+
If `./bin/generate` is missing,
142+
the lifecycle will interpret the contents of `./generate` as the contents of `$CNB_OUTPUT_DIR`.
143+
144+
```
145+
├── bin
146+
│ ├── detect
147+
├── generate
148+
│ ├── build.Dockerfile
149+
│ ├── run.Dockerfile
150+
├── extension.toml
151+
```
152+
153+
#### It's all optional!
154+
155+
```
156+
├── detect
157+
│ ├── plan.toml
158+
├── generate
159+
│ ├── build.Dockerfile
160+
│ ├── run.Dockerfile
161+
├── extension.toml
162+
```

content/docs/extension-guide/create-extension/building-blocks-extension.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ You should see something akin to the following:
4040
for further details.
4141

4242
We'll take a closer look at the executables for the `vim` extension in the next step.
43+
For guidance around writing extensions and more advanced use cases, see [here](/docs/extension-guide/create-extension/advanced-extensions).
4344

4445
<!--+ if false+-->
4546
---

0 commit comments

Comments
 (0)