Skip to content

Commit b362c49

Browse files
authored
Merge pull request cds-hooks#527 from buildpacks/extensions-phase-2-rc2
Docs for Dockerfiles
2 parents cce79a5 + 6c9e542 commit b362c49

File tree

10 files changed

+760
-0
lines changed

10 files changed

+760
-0
lines changed
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
+++
2+
title="Extension Author Guide"
3+
weight=4
4+
include_summaries=true
5+
expand=true
6+
aliases=[
7+
"/docs/create-extension/"
8+
]
9+
+++
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
+++
2+
title="Create an extension"
3+
weight=4
4+
summary="This is a step-by-step tutorial for creating and using CNB image extensions"
5+
+++
6+
7+
<!--+if false+-->
8+
## Prerequisites
9+
10+
Before we get started, make sure you've got the following installed:
11+
12+
{{< download-button href="https://store.docker.com/search?type=edition&offering=community" color="blue" >}} Install Docker {{</>}}
13+
{{< download-button href="/docs/install-pack" color="pink" >}} Install pack {{</>}}
14+
15+
## Overview
16+
<!--+end+-->
17+
18+
This is a step-by-step tutorial for creating and using CNB image extensions.
19+
20+
- [Set up your local environment](/docs/extension-author-guide/create-extension/setup-local-environment)
21+
- [See a build that requires base image extension in order to succeed](/docs/extension-author-guide/create-extension/why-dockerfiles)
22+
- [Building blocks of an extension](/docs/extension-author-guide/create-extension/building-blocks-extension)
23+
- [Generating a build.Dockerfile for your application](/docs/extension-author-guide/create-extension/build-dockerfile)
24+
- [Generating a run.Dockerfile for your application](/docs/extension-author-guide/create-extension/run-dockerfile)
25+
26+
<!--+if false+-->
27+
---
28+
29+
<a href="/docs/extension-author-guide/create-extension/setup-local-environment" class="button bg-pink">Start Tutorial</a>
30+
<!--+end+-->
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
+++
2+
title="Generating a build.Dockerfile"
3+
weight=404
4+
+++
5+
6+
<!-- test:suite=dockerfiles;weight=4 -->
7+
8+
### Examine `tree` extension
9+
10+
#### detect
11+
12+
<!-- test:exec -->
13+
```bash
14+
cat $PWD/samples/extensions/tree/bin/detect
15+
```
16+
17+
The extension always detects (because its exit code is `0`) and provides a dependency called `tree` by writing to the build plan.
18+
19+
#### generate
20+
21+
<!-- test:exec -->
22+
```bash
23+
cat $PWD/samples/extensions/tree/bin/generate
24+
```
25+
26+
The extension generates a `build.Dockerfile` that installs `tree` on the builder image.
27+
28+
### Re-create our builder with `hello-extensions` updated to require `tree`
29+
30+
Edit `$PWD/samples/buildpacks/hello-extensions/bin/detect` to uncomment the first set of lines that output `[[requires]]` to the build plan:
31+
32+
<!-- test:exec -->
33+
```bash
34+
sed -i "10,11s/#//" $PWD/samples/buildpacks/hello-extensions/bin/detect
35+
```
36+
37+
(On Mac, use `sed -i '' "10,11s/#//" $PWD/samples/buildpacks/hello-extensions/bin/detect`)
38+
39+
Re-create the builder:
40+
41+
<!-- test:exec -->
42+
```
43+
pack builder create localhost:5000/extensions-builder \
44+
--config $PWD/samples/builders/alpine/builder.toml \
45+
--publish
46+
```
47+
48+
### Re-build the application image
49+
50+
<!-- test:exec -->
51+
```
52+
pack build hello-extensions \
53+
--builder localhost:5000/extensions-builder \
54+
--network host \
55+
--path $PWD/samples/apps/java-maven \
56+
--pull-policy always \
57+
--verbose
58+
```
59+
60+
Note that `--network host` is necessary when publishing to a local registry.
61+
62+
You should see:
63+
64+
```
65+
[detector] ======== Results ========
66+
[detector] pass: samples/[email protected]
67+
[detector] pass: samples/[email protected]
68+
[detector] Resolving plan... (try #1)
69+
[detector] samples/tree 0.0.1
70+
[detector] samples/hello-extensions 0.0.1
71+
[detector] Running generate for extension samples/[email protected]
72+
...
73+
[extender] Found build Dockerfile for extension 'samples/tree'
74+
[extender] Applying the Dockerfile at /layers/generated/build/samples_tree/Dockerfile...
75+
...
76+
[extender] Running build command
77+
[extender] ---> Hello Extensions Buildpack
78+
[extender] tree v1.8.0 (c) 1996 - 2018 by Steve Baker, Thomas Moore, Francesc Rocher, Florian Sesser, Kyosuke Tokoro
79+
...
80+
Successfully built image hello-extensions
81+
```
82+
83+
### See the image fail to run
84+
85+
```
86+
docker run --rm hello-extensions
87+
```
88+
89+
You should see:
90+
91+
```
92+
ERROR: failed to launch: path lookup: exec: "curl": executable file not found in $PATH
93+
```
94+
95+
What happened: our builder uses run image `cnbs/sample-stack-run:alpine`, which does not have `curl` installed, so our
96+
process failed to launch.
97+
98+
Let's take a look at how the `samples/curl` extension fixes the error by switching the run image to another image...
99+
100+
<!--+ if false+-->
101+
---
102+
103+
<a href="/docs/extension-author-guide/create-extension/run-dockerfile" class="button bg-pink">Next Step</a>
104+
<!--+ end +-->
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
+++
2+
title="Building blocks of a CNB Image Extension"
3+
weight=403
4+
+++
5+
6+
<!-- test:suite=dockerfiles;weight=3 -->
7+
8+
### Examine `tree` extension
9+
10+
<!-- test:exec -->
11+
```bash
12+
tree $PWD/samples/extensions/tree
13+
```
14+
15+
(That's right, we're using the very tool we will later be installing!) You should see something akin to the following:
16+
17+
```
18+
.
19+
├── bin
20+
│ ├── detect <- similar to a buildpack ./bin/detect
21+
│ ├── generate <- similar to a buildpack ./bin/build
22+
├── extension.toml <- similar to a buildpack buildpack.toml
23+
```
24+
25+
* The `extension.toml` describes the extension, containing information such as its name, ID, and version, as well as the
26+
buildpack API that it implements. Though extensions are not buildpacks, they are expected to conform to the buildpack
27+
API except where noted. Consult the [spec](https://github.com/buildpacks/spec/blob/buildpack/main/image_extension.md)
28+
for further details.
29+
* `./bin/detect` is invoked during the `detect` phase. It analyzes application source code to determine if the extension
30+
is needed and contributes [build plan](/docs/reference/spec/buildpack-api/#build-plan) entries (much like a
31+
buildpack `./bin/detect`). Just like for buildpacks, a `./bin/detect` that exits with code `0` is considered to have
32+
passed detection, and fails otherwise.
33+
* `./bin/generate` is invoked during the `generate` phase (a new lifecycle phase that happens after `detect`). It
34+
outputs either or both of `build.Dockerfile` or `run.Dockerfile` for extending the builder or run image, respectively.
35+
* Only a limited set of Dockerfile instructions is supported - consult
36+
the [spec](https://github.com/buildpacks/spec/blob/buildpack/main/image_extension.md)
37+
for further details.
38+
* In the [initial implementation](/docs/features/dockerfiles#phased-approach), `run.Dockerfile` instructions are
39+
limited to a single `FROM` instruction (effectively, it is only possible to switch the run-time base image to a
40+
pre-created image i.e., no dynamic image modification is allowed). Consult
41+
the [spec](https://github.com/buildpacks/spec/blob/buildpack/main/image_extension.md)
42+
for further details.
43+
44+
We'll take a closer look at the executables for the `tree` extension in the next step.
45+
46+
<!--+ if false+-->
47+
---
48+
49+
<a href="/docs/extension-author-guide/create-extension/build-dockerfile" class="button bg-pink">Next Step</a>
50+
<!--+ end +-->
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
+++
2+
title="Generating a run.Dockerfile"
3+
weight=405
4+
+++
5+
6+
<!-- test:suite=dockerfiles;weight=5 -->
7+
8+
### Examine `curl` extension
9+
10+
#### detect
11+
12+
<!-- test:exec -->
13+
```bash
14+
cat $PWD/samples/extensions/curl/bin/detect
15+
```
16+
17+
The extension always detects (because its exit code is `0`) and provides a dependency called `curl`.
18+
19+
#### generate
20+
21+
<!-- test:exec -->
22+
```bash
23+
cat $PWD/samples/extensions/curl/bin/generate
24+
```
25+
26+
The extension generates a `run.Dockerfile` that switches the run image to reference `run-image-curl`.
27+
28+
### Build a run image for `curl` extension to use
29+
30+
<!-- test:exec -->
31+
```bash
32+
cat $PWD/samples/stacks/alpine/run/curl.Dockerfile
33+
```
34+
35+
This is a simple Dockerfile that creates a CNB run image from the `curl` base image by adding the required CNB user configuration and `io.buildpacks.stack.id` label.
36+
37+
The Dockerfile could come from anywhere, but we include it in the `stacks` directory for convenience.
38+
39+
Build the run image:
40+
41+
<!-- test:exec -->
42+
```bash
43+
docker build \
44+
--file $PWD/samples/stacks/alpine/run/curl.Dockerfile \
45+
--tag run-image-curl .
46+
```
47+
48+
### Re-create our builder with `hello-extensions` updated to require `curl`
49+
50+
Edit `$PWD/samples/buildpacks/hello-extensions/bin/detect` to uncomment the second set of lines that output `[[requires]]` to the build plan:
51+
52+
<!-- test:exec -->
53+
```bash
54+
sed -i "14,15s/#//" $PWD/samples/buildpacks/hello-extensions/bin/detect
55+
```
56+
57+
(On Mac, use `sed -i '' "14,15s/#//" $PWD/samples/buildpacks/hello-extensions/bin/detect`)
58+
59+
Re-create the builder:
60+
61+
<!-- test:exec -->
62+
```bash
63+
pack builder create localhost:5000/extensions-builder \
64+
--config $PWD/samples/builders/alpine/builder.toml \
65+
--publish
66+
```
67+
68+
### Re-build the application image
69+
70+
<!-- test:exec -->
71+
```bash
72+
pack build hello-extensions \
73+
--builder localhost:5000/extensions-builder \
74+
--path $PWD/samples/apps/java-maven \
75+
--pull-policy always \
76+
--network host \
77+
--verbose
78+
```
79+
80+
Note that `--network host` is necessary when publishing to a local registry.
81+
82+
You should see:
83+
84+
```
85+
[detector] ======== Results ========
86+
[detector] pass: samples/[email protected]
87+
[detector] pass: samples/[email protected]
88+
[detector] pass: samples/[email protected]
89+
[detector] Resolving plan... (try #1)
90+
[detector] samples/tree 0.0.1
91+
[detector] samples/curl 0.0.1
92+
[detector] samples/hello-extensions 0.0.1
93+
[detector] Running generate for extension samples/[email protected]
94+
...
95+
[detector] Running generate for extension samples/[email protected]
96+
...
97+
[detector] Checking for new run image
98+
[detector] Found a run.Dockerfile configuring image 'run-image-curl' from extension with id 'samples/curl'
99+
...
100+
[extender] Found build Dockerfile for extension 'samples/tree'
101+
[extender] Applying the Dockerfile at /layers/generated/build/samples_tree/Dockerfile...
102+
...
103+
[extender] Running build command
104+
[extender] ---> Hello Extensions Buildpack
105+
[extender] tree v1.8.0 (c) 1996 - 2018 by Steve Baker, Thomas Moore, Francesc Rocher, Florian Sesser, Kyosuke Tokoro
106+
...
107+
Successfully built image hello-extensions
108+
```
109+
110+
### See the image run successfully
111+
112+
<!-- test:exec -->
113+
```bash
114+
docker run --rm hello-extensions
115+
```
116+
117+
You should see something akin to:
118+
119+
```
120+
curl 7.85.0-DEV (x86_64-pc-linux-musl) ... more stuff here ...
121+
```
122+
123+
What happened: now that `hello-extensions` requires both `tree` and `curl` in its build plan, both extensions are
124+
included in the build and provide the needed dependencies for build and launch, respectively
125+
* The `tree` extension installs `tree` at build time, as before
126+
* The `curl` extension switches the run image to `run-image-curl`, which has `curl` installed
127+
128+
Now our `curl` process can succeed!
129+
130+
## What's next?
131+
132+
The `tree` and `curl` examples are very simple, but we can unlock powerful new features with this functionality.
133+
134+
Platforms could have several run images available, each tailored to a specific language family, thus limiting the number
135+
of installed dependencies for each image to the minimum necessary to support the targeted language. Image extensions
136+
could be used to switch the run image to that most appropriate for the current application.
137+
138+
Similarly, builder images could be kept lean if image extensions are used to dynamically install the needed dependencies
139+
for each application.
140+
141+
In the future, both run image switching and run image modification will be supported, opening the door to other use
142+
cases. Consult the [RFC](https://github.com/buildpacks/rfcs/pull/173) for further information.

0 commit comments

Comments
 (0)