-
Notifications
You must be signed in to change notification settings - Fork 71
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
RFC: Execution Environments #274
base: main
Are you sure you want to change the base?
Changes from 5 commits
2e9e00d
6d2a4ff
b702b6b
ea59782
baa83c4
992d873
d789f61
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,225 @@ | ||
# Meta | ||
[meta]: #meta | ||
- Name: Execution Environments | ||
- Start Date: 2023-01-11 | ||
- Author(s): @hone | ||
- Status: Draft <!-- Acceptable values: Draft, Approved, On Hold, Superseded --> | ||
- 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 | ||
|
||
Add support for different execution environments for buildpacks, with testing as the first use case. | ||
|
||
# Definitions | ||
[definitions]: #definitions | ||
|
||
- Execution Environment - The target environment the OCI image is expected to be run in, i.e. production, test, development. | ||
|
||
# Motivation | ||
[motivation]: #motivation | ||
|
||
The main way Buildpacks are being used is building production images, but this is only one piece of the software development process. Without a solid buildpack test environment story, users will be required alternatives for building their environment. A testing environment, while different, shares many of the same broad strokes ultimately producing an execution environment. This is something Buildpacks are well suited to solve. | ||
|
||
# What it is | ||
[what-it-is]: #what-it-is | ||
|
||
## Test Environments | ||
|
||
One of the goals in this design is to minimize the changes needed. The Buildpack lifecycle is already well suited to produce environments: | ||
|
||
``` | ||
App Source -> OCI Image (Production Environment) -> Execute (Launch Process) | ||
``` | ||
|
||
To create a test environment, it can follow the same flow: | ||
|
||
``` | ||
App Source -> OCI Image (Test Environment) -> Execute (Test Process) | ||
``` | ||
|
||
### Division of Responsibility | ||
With the test OCI Image, a platform can execute the tests in the pipeline as they see fit. This means a bulk of the responsibilities are platform concerns: | ||
|
||
- Set which environment to build for | ||
- Decide which buildpacks to execute | ||
- How to execute the tests | ||
- What is the test result format like [TAP](https://en.wikipedia.org/wiki/Test_Anything_Protocol)? | ||
- How to process the test results | ||
- What to do with the results | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this ever something we would want to spec? Having a consistent way for buildpacks to e.g., dump test output could help ensure portability across platforms. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I could see us wanting to do that, but I wasn't sure how much we wanted to impose standards there. |
||
|
||
This narrows the scope of the Buildpack responsibilities to what it's already good at: | ||
|
||
- Produce Test Environment | ||
- How to launch the process | ||
- launch.toml with test process marked as default (recommendation) | ||
|
||
## Setting the Execution Enviroment for Build + Buildpack | ||
A platform will set the `CNB_EXEC_ENV` env var to the execution environment desired. Buildpacks can than read this env var to branch or switch on logic needed based on the execution environment. | ||
|
||
In addition, Builder Authors, Buildpack Authors, and App Developers will be able to specify various options to a specific execution enviroment using the `exec-env` key. | ||
|
||
## Development Environments | ||
The specifics of creating development enviroments are out of scope of this RFC, but it's not hard to extrapolate how these kind of changes can assist in creating Buildpacks for development environments. | ||
|
||
# How it Works | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It would be nice to see the pack flow as well There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we add anything to the app image to designate it as being built for a particular environment? To avoid users accidentally deploying a test image in production... I could see folks wanting to use the same tag when re-building a test image for production, in order to use previously cached dependencies. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @natalieparellano that's a good question. Do you think cached dependencies should be shared b/t different execution environments? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is a label the best place to designate the execution environment? |
||
[how-it-works]: #how-it-works | ||
|
||
## `exec-env` key in TOML | ||
|
||
In order to support additional execution environments an `exec-env` key will be added to various TOML tables in the project. The value can be any string with `all` having special meaning. `all` will apply to all execution environments and will be the default if not specified. This should make it backwards compatible and optional. When `exec-env` is not set to `all`, the table settings will only be applied to that execution environment. | ||
hone marked this conversation as resolved.
Show resolved
Hide resolved
hone marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
### Project Descriptor - `project.toml` (App Developers) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you add an example of a full project.toml that is used for producing a test image and a production image? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just for Project Descriptor? |
||
|
||
This file be extended by adding `exec-env` to the following tables: | ||
|
||
`[[io.buildpacks.group]]` | ||
`[[io.buildpacks.pre.group]]` | ||
`[[io.buildpacks.post.group.env]]` | ||
`[[io.buildpacks.build.env]]` | ||
|
||
An example would look like this: | ||
|
||
```TOML | ||
[_] | ||
schema-version = "0.3" | ||
|
||
[[io.buildpacks.group]] | ||
id = "buildpacks/ruby" | ||
version = "latest" | ||
|
||
[[io.buildpacks.group]] | ||
id = "buildpacks/metrics-agent" | ||
version = "latest" | ||
exec-env = "production" | ||
|
||
[[io.buildpacks.group]] | ||
id = "buildpacks/headless-chrome" | ||
version = "latest" | ||
exec-env = "test" | ||
|
||
[[io.buildpacks.post.group]] | ||
id = "buildpacks/procfile" | ||
version = "latest" | ||
|
||
[[io.buildpacks.build.env]] | ||
name = "RAILS_ENV" | ||
value = "production" | ||
exec-env = "production" | ||
|
||
[[io.buildpacks.build.env]] | ||
name = "RAILS_ENV" | ||
value = "test" | ||
exec-env = "test" | ||
|
||
[[io.buildpacks.build.env]] | ||
name = "PARALLEL_WORKERS" | ||
value = "4" | ||
exec-env = "test" | ||
``` | ||
|
||
### `builder.toml` (Builder Authors) | ||
|
||
The only table that `exec-env` will be added to is `[[order.group.env]]`. | ||
hone marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
### `buildpack.toml` (Buildpack Authors) | ||
|
||
The only table that `exec-env` will be added to is `[[buildpack.order.group]]`. This only is applicable for composite buildpacks. | ||
|
||
## `CNB_EXEC_ENV` Environment Variable | ||
|
||
This env var will reserve the following values: | ||
|
||
* production | ||
* test | ||
* development | ||
|
||
### Buildpack API | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we perhaps get a conceptual example of what a buildpack author might do with this new execution environment information? I have in my head a language buildpack author may...
|
||
|
||
A buildpack author will be able to determine the execution environment their buildpack is expected to build for by reading the `CNB_EXEC_ENV` environment variable. If this value is not set, a Buildpack Author can assume it's set to `production`. | ||
|
||
### Platform API | ||
|
||
It will be up to the platform to set the environment variable `CNB_EXEC_ENV`. If this value is set, `lifecycle` MUST NOT override this value. If the value is not set, `lifecycle` will set it to `production`. | ||
|
||
# Migration | ||
[migration]: #migration | ||
|
||
In order to allow the Buildpack API and Platform API to be updated independently, both APIs will have a fallback to the `production` value. For `1.0`, it would be nice to drop this behavior and assume it will always be set. | ||
|
||
This also touches Project Descriptor, but since the platform controls the Platform API and the Project Descriptor Extension API it shouldn't cause any issues. | ||
|
||
# Drawbacks | ||
[drawbacks]: #drawbacks | ||
|
||
While the design tries to stay simple, it still adds new additions to the spec. | ||
|
||
* env var to Buildpack API | ||
* env var to Platform API | ||
* field to Project Descriptor, `builder.toml`, and `buildpack.toml`. | ||
|
||
# Alternatives | ||
[alternatives]: #alternatives | ||
|
||
## Separate Execution Environment Project Descriptor files | ||
|
||
When using `Dockerfile`, it's common to create a separate one for other execution environments like `Dockerfile.test`. This makes the file clean and easy to read, but comes at the cost of duplicating setup/code. | ||
|
||
With Project Descriptor, this would remove the need for the `exec-env` key at the cost of replicating buildpack groups. It does bring a big benefit by easily unlocking the `builder` key in Project Descriptor to be specific to an execution environment. This would apply to any fields (not tables) that exist at the `[io.buildpacks]` level like `include`/`exclude`. There are some other options if this is desired, where a new table could be created for hoisting fields into that would allow us to add the `exec-env` field. | ||
|
||
# Prior Art | ||
[prior-art]: #prior-art | ||
|
||
## [Heroku Testpack API](https://devcenter.heroku.com/articles/testpack-api) | ||
|
||
As part of the classic buildpack design, Heroku extended the API to include support for tests. It added a `bin/test-compile` phase, which is like the normal `bin/compile` phase but specific for setting things up for test. `bin/test` was called for executing tests. This design let a buildpack have a specific codepath for tests and also do intelligent logic for executing tests based on the source code. For example [in Ruby](https://github.com/heroku/heroku-buildpack-ruby/blob/main/bin/support/ruby_test#L62-L76), the buildpack author can run `bin/rspec` if it detects `rspec`, `bin/rails test` when using rails, or default to `rake test`. | ||
|
||
There were some flaws in this design. Though it's clean to separate production and test code paths, they end up sharing a lot of code. Many of the bash based Heroku buildpacks would just [call `bin/compile`](https://github.com/heroku/heroku-buildpack-nodejs/blob/main/bin/test-compile#L24) with different parameters/env vars. | ||
|
||
## [GOOGLE_DEVMODE](https://cloud.google.com/docs/buildpacks/service-specific-configs#google_devmode) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Similar to devmode, I just ran across live reloading in the Paketo python buildpacks https://paketo.io/docs/howto/python/#using-bp_live_reload_enabled |
||
|
||
These are specific to the Google Cloud Buildpacks for setting a development code path to work with skaffold. | ||
|
||
## [Develop API](https://github.com/buildpacks/spec/pull/71) | ||
|
||
The original Cloud Native Buildpacks spec included a Develop API, but it was never implemented. | ||
|
||
# Unresolved Questions | ||
[unresolved-questions]: #unresolved-questions | ||
|
||
- "env" is overloaded as a word since we also use it for environment variables. Is there a better word here? | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How about "mode"? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I like "context", but that's just as overloaded. How about "purpose = test" or "intent = test"? |
||
- Should there be builders that are specific to an execution environment? What about `include` or `exclude`? | ||
- Should the execution environments be an enum or flexible as a string? | ||
- enums will help encourage standardization across buildpacks and platforms. | ||
- strings can help account for use cases we haven't thought of yet. | ||
- Should buildpacks be allowed specify allowlist execution environments? | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are there any downsides to doing this? It would be more flexible and possibly avoid some duplication within orders (we could keep There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think the only downside is what if a user wants to override in a way it wasn't intended? Is there a reason to lock stuff out? |
||
- What changes are needed in the buildpack registry? | ||
|
||
# Spec. Changes (OPTIONAL) | ||
[spec-changes]: #spec-changes | ||
|
||
See ["How it Works"](#how-it-works). | ||
|
||
# History | ||
[history]: #history | ||
|
||
<!-- | ||
## Amended | ||
### Meta | ||
[meta-1]: #meta-1 | ||
- Name: (fill in the amendment name: Variable Rename) | ||
- Start Date: (fill in today's date: YYYY-MM-DD) | ||
- Author(s): (Github usernames) | ||
- Amendment Pull Request: (leave blank) | ||
|
||
### Summary | ||
|
||
A brief description of the changes. | ||
|
||
### Motivation | ||
|
||
Why was this amendment necessary? | ||
---> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't this a lifecycle concern? i.e., when processing a group within an order, should it skip buildpacks that do not declare
exec-env
matching the desired env?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When talking to @jabrown85, I thought the Platform/Builder provide the
order.toml
tolifecycle
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From WG,
lifecycle
will decide which buildpacks to run based on the execution environment being passed along by the platform.