Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

deprecate stacks, add targets #582

Closed
wants to merge 9 commits into from
42 changes: 41 additions & 1 deletion content/docs/concepts/components/stack.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,47 @@ aliases=[
]
+++

## What is a stack?
## What is a stack and Why is it deprecated?

### Deprecation
A stack restricts buildpacks to run on top of a set of related **build images** (where your app is built)
and **run images** (where your app runs). Practical experience of the buildpacks community has not found that the stack concept adds any value therefore [the community decided](https://github.com/buildpacks/rfcs/blob/main/text/0096-remove-stacks-mixins.md)
to use buildpacks with build and run images without the additional concept formerly known as _stack_.

Stacks will continue to be supported with full backwards compatibility.

### What's Next?
[Targets](https://github.com/buildpacks/rfcs/blob/main/text/0096-remove-stacks-mixins.md#example-buildpacktoml-targets-table) replace stacks.
Targets allow buildpack authors to directly specify details such as OS and architecture directly without the intermediate object known as a "stack."
joe-kimmel-vmw marked this conversation as resolved.
Show resolved Hide resolved
Targets are available starting with the 0.12 Platform API but should be safely ignored by older platforms.


#### How long can I keep using stacks?
We do not yet have a defined end-date. Historically this project allows deprecated features to remain for 6-24+ months.


#### What is the current recommended best practice?
We currently recommend that buildpack authors use both a stack and a target.
We anticipate it will take some time before all platforms catch up with this change, but by using both your buildpacks will work with all platforms past, present, and future.

In order to ease this process for those using the io.buildpacks.stacks.bionic, lifecycle will translate any section that sets this as on of the stacks:

```
[[stacks]]
id = "io.buildpacks.stacks.bionic"
```

to
```
[[targets]]
os = "linux"
arch = "amd64"
[[targets.distributions]]
name = "ubuntu"
versions = ["18.04"]
```

## (Deprecated) stack documentation

A stack is composed of two images that are intended to work together:

Expand Down
26 changes: 26 additions & 0 deletions content/docs/concepts/components/target.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
+++
title="Targets"
weight=4
aliases=[
"/docs/using-pack/targets/"
]
+++

## What is a Target?

A target is the essential information about an operating system and architecture necessary to ensure that binaries will be placed in environments where they can execute successfully.
A buildpack may specify one or several targets. A build image or run image must specific one target.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This statement is confusing to me: A build image or run image must specific one target.. Does this mean [[targets]] is supposed to be nested inside the [run] and [build] blocks? I'm more familiar with yaml/json than with toml, so I tend to convert it in order to understand what is going on and it appears to be a builder-wide setting.

given this builder.toml:

[build]
image = "ghcr.io/jericop/build-jammy:target"

[run]
[[run.images]]
image = "ghcr.io/jericop/run-jammy:target"

[[targets]]
os = "linux"
arch = "amd64"
[[targets.distributions]]
name = "ubuntu"
versions = ["18.04", "20.04"]

the yaml output is:

build:
  image: ghcr.io/jericop/build-jammy:target
run:
  images:
    - image: ghcr.io/jericop/run-jammy:target
targets:
  - os: linux
    arch: amd64
    distributions:
      - name: ubuntu
        versions:
          - "18.04"
          - "20.04"

It would be helpful to have a complete example of using [[targets]] in a builder toml.



For full documentation see the (RFC where targets are introduced)[https://github.com/buildpacks/rfcs/blob/main/text/0096-remove-stacks-mixins.md].

### Example
```
[[targets]]
os = "linux"
arch = "amd64"
[[targets.distributions]]
name = "ubuntu"
versions = ["18.04", "20.04"]
```

4 changes: 2 additions & 2 deletions content/docs/operator-guide/create-a-builder.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,10 +97,10 @@ For additional sample builders and buildpacks, check out our [samples][samples]

You can also check out our reference of the builder config [here][builder-config].

If you would like to customize the stack used by your builder, check out our [Create a stack][create-a-stack] tutorial.
If you would like to customize the image your builder builds in, check out our [Create custom build and run images][create-targets] tutorial.

[build]: /docs/concepts/operations/build/
[builder]: /docs/concepts/components/builder/
[builder-config]: /docs/reference/builder-config/
[create-a-stack]: /docs/operator-guide/create-a-stack
[create-targets]: /docs/operator-guide/create-targets
[samples]: https://github.com/buildpacks/samples
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
+++
title="Create a stack"
title="Create Target Images"
weight=2
+++

Creating a custom [stack][stack] allows you to configure the base images for the build-time environment for your [builder][builder] and the run-time for your application.
Creating a custom Build and Run images allows you to configure the base images for the build-time environment for your [builder][builder] and the run-time for your application.

<!--more-->

Expand All @@ -13,55 +13,66 @@ Before we get started, make sure you've got the following installed:

{{< download-button href="https://store.docker.com/search?type=edition&offering=community" color="blue" >}} Install Docker {{</>}}

## Creating custom images

## Creating a custom stack

In this tutorial we will create a sample stack based on `Ubuntu Bionic`. To create a custom stack, we need to create customized build and run images. Let's see how we can do so!

In this tutorial we will create sample build and run images based on `Ubuntu Jammy.`
joe-kimmel-vmw marked this conversation as resolved.
Show resolved Hide resolved

### Create a common base image

Let's start by creating a base image containing layers that will be required by both the `build` and `run` images. In order to do this, switch to a clean workspace and create a `Dockerfile` as specified below:
Let's start by creating a base image containing layers that will be required both the `build` and `run` images.
In order to do this, switch to a clean workspace and create a `Dockerfile` as specified below:

#### Defining the base
We start with `ubuntu:jammy` as our `base` image. Since we will be reusing these layers in both our build and run images we will be defining a common base image and leveraging [Docker's multi-stage builds](https://docs.docker.com/develop/develop-images/multistage-build/) to ensure this acts as the common base image for both our build-time and run-time environment.
We start with `ubuntu:jammy` as our `base` image, and we hope you like jammy too!
Since we will be reusing these layers in both our build and run images we will be defining a common base image and leveraging [Docker's multi-stage builds](https://docs.docker.com/develop/develop-images/multistage-build/) to ensure this acts as the common base image for both our build-time and run-time environment.

```Dockerfile
# 1. Set a common base
FROM ubuntu:jammy as base
```


#### Set required CNB information

Next, we will be setting up the base image as required by the [Cloud-Native Buildpack specification][stack-spec] noted below.
Next, we will be setting up the base image as required by the [Cloud-Native Buildpack specification](https://github.com/buildpacks/spec/blob/main/platform.md).

##### Specification

**Labels**
The image's config's `os` and `architecture` should be set ot valid values according to the
[OCI Image Specification](https://github.com/opencontainers/image-spec/blob/main/config.md) with the addition of wildcards:
Buildpack images may have their architecture set to `*` to indicate "any" - e.g. a shell script that is expected to succeed in any architecture could specify `*`.
Similarly

**Labels (optional)**

##### TODO / question: I think the spec says that "the platform" (as opposed to the build image author) should set the labels?
https://github.com/buildpacks/spec/pull/335/files#diff-e603760990971da3f77be4bb8d77c3405098f006814fd8c054d2d15f395b8330R199
should we mention them in this tutorial?
##### end TODO /question


Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What direction is this taking? Can I help here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm. this is wrong as -is. the "image config" doesn't get the * but the labels do, i think. maybe I can ask @natalieparellano to confirm

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah, so, we said, heck with it let's just not mention it in the tutorial since it's optional anyways, and only getting more optional as the spec gets closer and closer to being released.


| Name | Description | Format |
| ------------------------ | ------------------------ | ------ |
| `io.buildpacks.stack.id` | Identifier for the stack | String |
| `io.buildpacks.distribution.name` | OS Distribution Name | String |
| `io.buildpacks.distribution.version` | OS Distribution Version | String |

**Environment Variables**

| Name | Description |
| -------------- | -------------------------------------- |
| `CNB_STACK_ID` | Identifier for the stack |
| `CNB_USER_ID` | UID of the user specified in the image |
| `CNB_GROUP_ID` | GID of the user specified in the image |
<p class="spacer"></p>

> **NOTE:** The **stack identifier** implies compatibility with other stacks of that same identifier. For instance, a custom stack may use
> `io.buildpacks.stacks.jammy` as its identifier so long as it will work with buildpacks that declare compatibility with the
> `io.buildpacks.stacks.jammy` stack.


The `CNB_USER_ID` is the `UID` of the user as which the `detect` and `build` steps are run. The given user **MUST NOT** be a root user
and have it's home directly writable. `CNB_GROUP_ID` is the primary `GID` of the above user.

Let's update the `Dockerfile` to reflect the above specification.


```Dockerfile
# 1. Set a common base
FROM ubuntu:jammy as base
Expand All @@ -70,8 +81,6 @@ FROM ubuntu:jammy as base
# 2. Set required CNB information
ENV CNB_USER_ID=1000
ENV CNB_GROUP_ID=1000
ENV CNB_STACK_ID="io.buildpacks.samples.stacks.jammy"
LABEL io.buildpacks.stack.id="io.buildpacks.samples.stacks.jammy"

# 3. Create the user
RUN groupadd cnb --gid ${CNB_GROUP_ID} && \
Expand All @@ -84,13 +93,13 @@ Next up, we will be installing any system packages that we want to make availabl

```Dockerfile
# 1. Set a common base
FROM ubuntu:jammy as base
FROM ubuntu:bionic as base

# 2. Set required CNB information
ENV CNB_USER_ID=1000
ENV CNB_GROUP_ID=1000
ENV CNB_STACK_ID="io.buildpacks.samples.stacks.jammy"
LABEL io.buildpacks.stack.id="io.buildpacks.samples.stacks.jammy"
ENV CNB_STACK_ID="io.buildpacks.samples.stacks.bionic"
LABEL io.buildpacks.stack.id="io.buildpacks.samples.stacks.bionic"

# 3. Create the user
RUN groupadd cnb --gid ${CNB_GROUP_ID} && \
Expand Down Expand Up @@ -123,8 +132,6 @@ FROM ubuntu:jammy as base
# 2. Set required CNB information
ENV CNB_USER_ID=1000
ENV CNB_GROUP_ID=1000
ENV CNB_STACK_ID="io.buildpacks.samples.stacks.jammy"
LABEL io.buildpacks.stack.id="io.buildpacks.samples.stacks.jammy"

# 3. Create the user
RUN groupadd cnb --gid ${CNB_GROUP_ID} && \
Expand All @@ -146,7 +153,7 @@ USER ${CNB_USER_ID}:${CNB_GROUP_ID}
That should be it for our run image! Let's verify that we can successfully build this image by running:

```bash
docker build . -t cnbs/sample-stack-run:jammy --target run
docker build . -t cnbs/sample-run:jammy --target run
```

### Creating the build image
Expand All @@ -166,8 +173,6 @@ FROM ubuntu:jammy as base
# 2. Set required CNB information
ENV CNB_USER_ID=1000
ENV CNB_GROUP_ID=1000
ENV CNB_STACK_ID="io.buildpacks.samples.stacks.jammy"
LABEL io.buildpacks.stack.id="io.buildpacks.samples.stacks.jammy"

# 3. Create the user
RUN groupadd cnb --gid ${CNB_GROUP_ID} && \
Expand Down Expand Up @@ -207,8 +212,6 @@ FROM ubuntu:jammy as base
# 2. Set required CNB information
ENV CNB_USER_ID=1000
ENV CNB_GROUP_ID=1000
ENV CNB_STACK_ID="io.buildpacks.samples.stacks.jammy"
LABEL io.buildpacks.stack.id="io.buildpacks.samples.stacks.jammy"

# 3. Create the user
RUN groupadd cnb --gid ${CNB_GROUP_ID} && \
Expand Down Expand Up @@ -243,70 +246,21 @@ USER ${CNB_USER_ID}:${CNB_GROUP_ID}
That should be it for our build image! Let's verify that we can successfully build this image by running:

```bash
docker build . -t cnbs/sample-stack-build:jammy --target build
```

**Congratulations!** You've got a custom stack!


## Additional information

### Mixins

Mixins provide a way to document OS-level dependencies that a stack provides to buildpacks. Mixins can be provided at build-time
(name prefixed with `build:`), run-time (name prefixed with `run:`), or both (name unprefixed).

#### Declaring provided mixins

When declaring provided mixins, both the build and run image of a stack must contain the following label:

| Name | Description | Format |
| ---------------------------- | ----------------------- | ----------------- |
| `io.buildpacks.stack.mixins` | List of provided mixins | JSON string array |

\
The following rules apply for mixin declarations:

- `build:`-prefixed mixins may not be declared on a run image
- `run:`-prefixed mixins may not be declared on a build image
- Unprefixed mixins must be declared on both stack images

##### Example

_Build image:_
```json
io.buildpacks.stack.mixins: ["build:git", "wget"]
docker build . -t cnbs/sample-build:jammy --target build
```

_Run image:_
```json
io.buildpacks.stack.mixins: ["run:imagemagick", "wget"]
```

#### Declaring required mixins

A buildpack must list any required mixins in the `stacks` section of its `buildpack.toml` file.
**Congratulations!** You've got custom build and run images!

When validating whether the buildpack's mixins are satisfied by a stack, the following rules apply:

- `build:`-prefixed mixins must be provided by stack's build image
- `run:`-prefixed mixins must be provided by stack's run image
- Unprefixed mixins must be provided by both stack images

##### Example
## Resources and Additional Information

```toml
[[stacks]]
id = "io.buildpacks.stacks.jammy"
mixins = ["build:git", "run:imagemagick", "wget"]
```
**Image Extensions** provide a way to add functionality that could be shared by multiple base images. see:

## Resources
[Image Extension Spec](https://github.com/buildpacks/spec/blob/main/image_extension.md) and [Extension Author Guide](https://buildpacks.io/docs/extension-author-guide/)

For sample stacks, see our [samples][samples] repo.
For technical details on stacks, see the [platform specification for stacks][stack-spec].

[stack]: /docs/concepts/components/stack/
[builder]: /docs/concepts/components/builder/
[samples]: https://github.com/buildpacks/samples
[stack-spec]: https://github.com/buildpacks/spec/blob/main/platform.md#stacks