Skip to content

Commit

Permalink
Merge pull request #581 from buildpacks/runext/demo
Browse files Browse the repository at this point in the history
Demo run image extension
  • Loading branch information
AidanDelaney authored Aug 14, 2023
2 parents 50c1d29 + 082ee11 commit 77adc63
Show file tree
Hide file tree
Showing 9 changed files with 193 additions and 79 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ jobs:
- name: Install pack
uses: buildpacks/github-actions/setup-pack@v5.2.0
with:
pack-version: '0.30.0-rc1'
pack-version: '0.30.0-rc1' # FIXME: update to 0.30.0 when available
- name: Test
run: make test
env:
Expand Down
2 changes: 1 addition & 1 deletion content/docs/extension-guide/create-extension/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ This is a step-by-step tutorial for creating and using CNB image extensions.
- [See a build that requires base image extension in order to succeed](/docs/extension-guide/create-extension/why-dockerfiles)
- [Building blocks of an extension](/docs/extension-guide/create-extension/building-blocks-extension)
- [Generating a build.Dockerfile for your application](/docs/extension-guide/create-extension/build-dockerfile)
- [Generating a run.Dockerfile for your application](/docs/extension-guide/create-extension/run-dockerfile)
- [Generating a run.Dockerfile for your application](/docs/extension-guide/create-extension/run-dockerfile-switch)

<!--+if false+-->
---
Expand Down
21 changes: 13 additions & 8 deletions content/docs/extension-guide/create-extension/build-dockerfile.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ aliases = [

<!-- test:suite=dockerfiles;weight=4 -->

Builder images can be kept lean if image extensions are used to dynamically install the needed dependencies
for the current application.

### Examine `vim` extension

#### detect
Expand All @@ -28,7 +31,9 @@ cat $PWD/samples/extensions/vim/bin/generate

The extension generates a `build.Dockerfile` that installs `vim` on the builder image.

### Re-build the application image
### Configure the `hello-extensions` buildpack to require `vim`

Set the `BP_REQUIRES` build-time environment variable to configure the `hello-extensions` buildpack to require `vim` (review the `./bin/detect` script to see why this works).

<!-- test:exec -->
```
Expand All @@ -47,6 +52,7 @@ Note that `--network host` is necessary when publishing to a local registry.
You should see:

```
...
[detector] ======== Results ========
[detector] pass: samples/vim@0.0.1
[detector] pass: samples/hello-extensions@0.0.1
Expand All @@ -55,12 +61,12 @@ You should see:
[detector] samples/hello-extensions 0.0.1
[detector] Running generate for extension samples/vim@0.0.1
...
[extender] Found build Dockerfile for extension 'samples/vim'
[extender] Applying the Dockerfile at /layers/generated/build/samples_vim/Dockerfile...
[extender (build)] Found build Dockerfile for extension 'samples/vim'
[extender (build)] Applying the Dockerfile at /layers/generated/build/samples_vim/Dockerfile...
...
[extender] Running build command
[extender] ---> Hello Extensions Buildpack
[extender] vim v1.8.0 (c) 1996 - 2018 by Steve Baker, Thomas Moore, Francesc Rocher, Florian Sesser, Kyosuke Tokoro
[extender (build)] Running build command
[extender (build)] ---> Hello Extensions Buildpack
[extender (build)] VIM - Vi IMproved 9.0 (2022 Jun 28, compiled May 19 2023 16:28:36)
...
Successfully built image hello-extensions
```
Expand All @@ -85,5 +91,4 @@ Let's take a look at how the `samples/curl` extension fixes the error by switchi
<!--+ if false+-->
---

<a href="/docs/extension-guide/create-extension/run-dockerfile" class="button bg-pink">Next Step</a>
<!--+ end +-->
<a href="/docs/extension-guide/create-extension/run-dockerfile-switch" class="button bg-pink">Next Step</a>
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ aliases = [

<!-- test:exec -->
```bash
vim --help
tree $PWD/samples/extensions/vim
```

(That's right, we're using the very tool we will later be installing!) You should see something akin to the following:
You should see something akin to the following:

```
.
Expand All @@ -38,11 +38,6 @@ vim --help
* Only a limited set of Dockerfile instructions is supported - consult
the [spec](https://github.com/buildpacks/spec/blob/main/image_extension.md)
for further details.
* In the [initial implementation](/docs/features/dockerfiles#phased-approach), `run.Dockerfile` instructions are
limited to a single `FROM` instruction (effectively, it is only possible to switch the run-time base image to a
pre-created image i.e., no dynamic image modification is allowed). Consult
the [spec](https://github.com/buildpacks/spec/blob/main/image_extension.md)
for further details.

We'll take a closer look at the executables for the `vim` extension in the next step.

Expand Down
107 changes: 107 additions & 0 deletions content/docs/extension-guide/create-extension/run-dockerfile-extend.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
+++
title="Generating a run.Dockerfile that extends the runtime base image"
weight=406
+++

<!-- test:suite=dockerfiles;weight=6 -->

Run images can be kept lean if image extensions are used to dynamically install the needed dependencies
for the current application.

### Examine `cowsay` extension

#### detect

<!-- test:exec -->
```bash
cat $PWD/samples/extensions/cowsay/bin/detect
```

The extension always detects (because its exit code is `0`) and provides a dependency called `cowsay`.

#### generate

<!-- test:exec -->
```bash
cat $PWD/samples/extensions/cowsay/bin/generate
```

The extension generates a `run.Dockerfile` that installs `cowsay` on the current run image.

### Configure the `hello-extensions` buildpack to require `cowsay`

Set the `BP_REQUIRES` build-time environment variable to configure the `hello-extensions` buildpack to require both `vim` and `curl` (review the `./bin/detect` script to see why this works).

<!-- test:exec -->
```bash
pack build hello-extensions \
--builder localhost:5000/extensions-builder \
--env BP_EXT_DEMO=1 \
--env BP_REQUIRES=vim,curl,cowsay \
--path $PWD/samples/apps/java-maven \
--pull-policy always \
--network host \
--verbose
```

Note that `--network host` is necessary when publishing to a local registry.

You should see:

```
...
[detector] ======== Results ========
[detector] pass: samples/vim@0.0.1
[detector] pass: samples/curl@0.0.1
[detector] pass: samples/cowsay@0.0.1
[detector] pass: samples/hello-extensions@0.0.1
[detector] Resolving plan... (try #1)
[detector] samples/vim 0.0.1
[detector] samples/curl 0.0.1
[detector] samples/cowsay 0.0.1
[detector] samples/hello-extensions 0.0.1
[detector] Running generate for extension samples/vim@0.0.1
...
[detector] Running generate for extension samples/curl@0.0.1
...
[detector] Running generate for extension samples/cowsay@0.0.1
...
[detector] Found a run.Dockerfile from extension 'samples/curl' setting run image to 'localhost:5000/run-image-curl'
...
[extender (build)] Found build Dockerfile for extension 'samples/vim'
[extender (build)] Applying Dockerfile at /layers/generated/build/samples_vim/Dockerfile...
[extender (run)] Found run Dockerfile for extension 'samples/curl'
[extender (run)] Found run Dockerfile for extension 'samples/cowsay'
[extender (run)] Applying Dockerfile at /layers/generated/run/samples_curl/Dockerfile...
...
[extender (run)] Applying Dockerfile at /layers/generated/run/samples_cowsay/Dockerfile
...
[extender (build)] Running build command
[extender (build)] ---> Hello Extensions Buildpack
[extender (build)] VIM - Vi IMproved 9.0 (2022 Jun 28, compiled May 19 2023 16:28:36)
...
Successfully built image hello-extensions
```

Note: build image extension and run image extension are done in parallel,
so the log lines for those phases may print in a different order from that shown above.

### See the image run successfully

<!-- test:exec -->
```bash
docker run --rm --entrypoint cowsay hello-extensions
```

You should see something akin to:

```
________
< MOOOO! >
--------
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
```
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
+++
title="Generating a run.Dockerfile"
title="Generating a run.Dockerfile that switches the runtime base image"
weight=405
aliases = [
"/docs/extension-author-guide/run-dockerfile/"
Expand All @@ -8,6 +8,10 @@ aliases = [

<!-- test:suite=dockerfiles;weight=5 -->

Platforms can have several run images available, each tailored to a specific language family - thus limiting the number
of installed dependencies for each image to the minimum necessary to support the targeted language. Image extensions
can be used to switch the run image to that most appropriate for the current application.

### Examine `curl` extension

#### detect
Expand All @@ -26,7 +30,7 @@ The extension always detects (because its exit code is `0`) and provides a depen
cat $PWD/samples/extensions/curl/bin/generate
```

The extension generates a `run.Dockerfile` that switches the run image to reference `run-image-curl`.
The extension generates a `run.Dockerfile` that switches the run image to reference `localhost:5000/run-image-curl`.

### Build a run image for `curl` extension to use

Expand All @@ -46,9 +50,13 @@ Build the run image:
docker build \
--file $PWD/samples/stacks/alpine/run/curl.Dockerfile \
--tag localhost:5000/run-image-curl .

docker push localhost:5000/run-image-curl
```

### Re-build the application image
### Configure the `hello-extensions` buildpack to require `curl`

Set the `BP_REQUIRES` build-time environment variable to configure the `hello-extensions` buildpack to require both `vim` and `curl` (review the `./bin/detect` script to see why this works).

<!-- test:exec -->
```bash
Expand All @@ -70,8 +78,11 @@ You should see:
[detector] ======== Results ========
[detector] pass: samples/vim@0.0.1
[detector] pass: samples/curl@0.0.1
[detector] pass: samples/cowsay@0.0.1
[detector] pass: samples/hello-extensions@0.0.1
[detector] Resolving plan... (try #1)
[detector] skip: samples/cowsay@0.0.1 provides unused cowsay
[detector] 3 of 4 buildpacks participating
[detector] samples/vim 0.0.1
[detector] samples/curl 0.0.1
[detector] samples/hello-extensions 0.0.1
Expand All @@ -80,14 +91,14 @@ You should see:
[detector] Running generate for extension samples/curl@0.0.1
...
[detector] Checking for new run image
[detector] Found a run.Dockerfile configuring image 'run-image-curl' from extension with id 'samples/curl'
[detector] Found a run.Dockerfile from extension 'samples/curl' setting run image to 'localhost:5000/run-image-curl'
...
[extender] Found build Dockerfile for extension 'samples/vim'
[extender] Applying the Dockerfile at /layers/generated/build/samples_vim/Dockerfile...
[extender (build)] Found build Dockerfile for extension 'samples/vim'
[extender (build)] Applying the Dockerfile at /layers/generated/build/samples_vim/Dockerfile...
...
[extender] Running build command
[extender] ---> Hello Extensions Buildpack
[extender] vim v1.8.0 (c) 1996 - 2018 by Steve Baker, Thomas Moore, Francesc Rocher, Florian Sesser, Kyosuke Tokoro
[extender (build)] Running build command
[extender (build)] ---> Hello Extensions Buildpack
[extender (build)] VIM - Vi IMproved 9.0 (2022 Jun 28, compiled May 19 2023 16:28:36)
...
Successfully built image hello-extensions
```
Expand All @@ -108,20 +119,31 @@ curl 7.85.0-DEV (x86_64-pc-linux-musl) ... more stuff here ...
What happened: now that `hello-extensions` requires both `vim` and `curl` in its build plan, both extensions are
included in the build and provide the needed dependencies for build and launch, respectively
* The `vim` extension installs `vim` at build time, as before
* The `curl` extension switches the run image to `run-image-curl`, which has `curl` installed
* The `curl` extension switches the run image to `localhost:5000/run-image-curl`, which has `curl` installed

Now our `curl` process can succeed!

## What's next?
### Next steps

The `vim` and `curl` examples are very simple, but we can unlock powerful new features with this functionality.
Our `curl` process succeeded, but there is another process type defined on our image:

Platforms could have several run images available, each tailored to a specific language family, thus limiting the number
of installed dependencies for each image to the minimum necessary to support the targeted language. Image extensions
could be used to switch the run image to that most appropriate for the current application.
```
docker run --rm --entrypoint cowsay hello-extensions
```

You should see:

```
ERROR: failed to launch: path lookup: exec: "cowsay": executable file not found in $PATH
```

Our run image, `localhost:5000/run-image-curl`, has `curl` installed, but it doesn't have `cowsay`.

In general, we may not always have a preconfigured run image available with all the needed dependencies for the current application.
Luckily, we can also use image extensions to dynamically install runtime dependencies at build time. Let's look at that next.

Similarly, builder images could be kept lean if image extensions are used to dynamically install the needed dependencies
for each application.
<!--+ if false+-->
---

In the future, both run image switching and run image modification will be supported, opening the door to other use
cases. Consult the [RFC](https://github.com/buildpacks/rfcs/pull/173) for further information.
<a href="/docs/extension-guide/create-extension/run-dockerfile-extend" class="button bg-pink">Next Step</a>
<!--+ end +-->
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ cd <your preferred workspace directory>
pack version
```

The version should be at least `0.28.0`
The version should be at least `0.30.0`

### Update pack configuration

Expand Down
37 changes: 22 additions & 15 deletions content/docs/extension-guide/create-extension/why-dockerfiles.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ Let's see a build that requires base image extension in order to succeed.
cat $PWD/samples/buildpacks/hello-extensions/bin/detect
```

The buildpack always detects (because its exit code is `0`) but doesn't require any dependencies (as the output build plan is empty).
The buildpack opts-out of the build (exits with non-zero code) unless the `BP_EXT_DEMO` environment variable is set.

If the `BP_EXT_DEMO` environment variable is set, the buildpack detects (exits with code `0`), but doesn't require any dependencies through a build plan unless the `BP_REQUIRES` environment variable is set.

#### build

Expand All @@ -28,7 +30,7 @@ The buildpack always detects (because its exit code is `0`) but doesn't require
cat $PWD/samples/buildpacks/hello-extensions/bin/build
```

The buildpack tries to use `tree` at build-time, and defines a launch process called `curl` that runs `curl --version` at runtime.
The buildpack tries to use `vim` at build-time, and defines a launch process called `curl` that runs `curl --version` at runtime.

### Create a builder with extensions and publish it

Expand Down Expand Up @@ -72,28 +74,33 @@ Note that `--network host` is necessary when publishing to a local registry.
You should see:

```
...
[detector] ======== Results ========
[detector] pass: samples/tree@0.0.1
[detector] pass: samples/vim@0.0.1
[detector] pass: samples/curl@0.0.1
[detector] pass: samples/cowsay@0.0.1
[detector] pass: samples/hello-extensions@0.0.1
[detector] Resolving plan... (try #1)
[detector] skip: samples/tree@0.0.1 provides unused tree
[detector] 1 of 2 buildpacks participating
[detector] skip: samples/vim@0.0.1 provides unused vim
[detector] skip: samples/curl@0.0.1 provides unused curl
[detector] skip: samples/cowsay@0.0.1 provides unused cowsay
[detector] 1 of 4 buildpacks participating
[detector] samples/hello-extensions 0.0.1
...
[extender] Running build command
[extender] ---> Hello Extensions Buildpack
[extender] /cnb/buildpacks/samples_hello-extensions/0.0.1/bin/build: line 6: tree: command not found
[extender] ERROR: failed to build: exit status 127
[extender (build)] Running build command
[extender (build)] ---> Hello Extensions Buildpack
[extender (build)] /cnb/buildpacks/samples_hello-extensions/0.0.1/bin/build: line 6: vim: command not found
[extender (build)] ERROR: failed to build: exit status 127
```

What happened: our builder doesn't have `tree` installed, so the `hello-extensions` buildpack failed to build (as it
tries to run `tree --version` in its `./bin/build` script).
What happened: our builder doesn't have `vim` installed, so the `hello-extensions` buildpack failed to build (as it
tries to run `vim --version` in its `./bin/build` script).

Even though there is a `samples/tree` extension that passed detection (`pass: samples/tree@0.0.1`), because
the `hello-extensions` buildpack didn't require `tree` in the build plan, the extension was omitted from the detected
group (`skip: samples/tree@0.0.1 provides unused tree`).
Even though there is a `samples/vim` extension that passed detection (`pass: samples/vim@0.0.1`), because
the `hello-extensions` buildpack didn't require `vim` in the build plan, the extension was omitted from the detected
group (`skip: samples/vim@0.0.1 provides unused vim`).

Let's take a look at how the `samples/tree` extension installs `tree` on the builder image...
Let's take a look at how the `samples/vim` extension installs `vim` on the builder image...

<!--+ if false+-->
---
Expand Down
Loading

0 comments on commit 77adc63

Please sign in to comment.