diff --git a/.github/styles/config/vocabularies/Buildpacks/accept.txt b/.github/styles/config/vocabularies/Buildpacks/accept.txt new file mode 100644 index 000000000..b4eb66252 --- /dev/null +++ b/.github/styles/config/vocabularies/Buildpacks/accept.txt @@ -0,0 +1,12 @@ +API(?s) +[Bb]uildpack(?s) +config +Dockerfile(?s) +GitHub +mixin(?s) +prepended +rebase +Rebasing +SBOM(?s) +semver +Syft \ No newline at end of file diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index aa596a6c6..6506c2b22 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -57,7 +57,7 @@ jobs: name: public path: ./public - name: Deploy - uses: peaceiris/actions-gh-pages@v3 + uses: peaceiris/actions-gh-pages@v4 with: github_token: ${{ secrets.GITHUB_TOKEN }} publish_dir: ./public diff --git a/.github/workflows/vale-lint.yml b/.github/workflows/vale-lint.yml index 6061f9077..bb38a7da2 100644 --- a/.github/workflows/vale-lint.yml +++ b/.github/workflows/vale-lint.yml @@ -7,7 +7,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: errata-ai/vale-action@reviewdog + - uses: errata-ai/vale-action@v2.1.1 with: fail_on_error: true token: ${{secrets.GITHUB_TOKEN}} diff --git a/.vale/styles/confg/vocabularies/Buildpacks/accept.txt b/.vale/styles/confg/vocabularies/Buildpacks/accept.txt deleted file mode 100644 index ad5aa8b8a..000000000 --- a/.vale/styles/confg/vocabularies/Buildpacks/accept.txt +++ /dev/null @@ -1,2 +0,0 @@ -[Bb]uildpack(?s) -prepended \ No newline at end of file diff --git a/content/docs/for-app-developers/how-to/special-cases/build-for-arm.md b/content/docs/for-app-developers/how-to/special-cases/build-for-arm.md index 03f11a211..d8bde1a7d 100644 --- a/content/docs/for-app-developers/how-to/special-cases/build-for-arm.md +++ b/content/docs/for-app-developers/how-to/special-cases/build-for-arm.md @@ -10,7 +10,7 @@ weight=1 Building for the ARM architecture is now easier than ever! The `heroku/builder:24` builder supports both AMD64 and ARM64 architectures, and includes -multi-arch Go, Java, Node.js, PHP, Python, Ruby and Scala buildpacks. You can read more about Heroku's [Cloud Native Buildpacks here][heroku-buildpacks]. +multi-arch .NET, Go, Java, Node.js, PHP, Python, Ruby and Scala buildpacks. You can read more about Heroku's [Cloud Native Buildpacks here][heroku-buildpacks]. > **NOTE:** Our current multi-architecture support allows building an ARM64 application image on an ARM64 host, and building an AMD64 application image on an AMD64 host. We do not currently support building an application image for one architecture on a different architecture. However, if your host machine supports emulation (e.g., with QEMU) you may be able to perform cross platform builds, albeit with a performance penalty. diff --git a/content/docs/for-platform-operators/concepts/base-images.md b/content/docs/for-platform-operators/concepts/base-images.md new file mode 100644 index 000000000..08382141c --- /dev/null +++ b/content/docs/for-platform-operators/concepts/base-images.md @@ -0,0 +1,57 @@ ++++ +title="Base image types" +weight=99 ++++ + +As you already know, `Cloud Native Buildpacks (CNBs)` transform your application source code into `OCI images` that can run on any cloud. + + + +Each buildpack checks the source code and provides any relevant dependencies in the form of layers. Then, buildpack-provided layers are placed atop a runtime `base image` to form the final application image. + +## Base image types + +A `base image` is an `OCI image` containing the base, or initial set of layers, for other images. It is helpful to distinguish between two distinct types of images, `Build` and `Runtime` images. + +### Build image + +A `build image` is an `OCI image` that serves as the base image for the `build` environment in which the CNB `lifecycle` and buildpacks are executed. + +A typical `build image` might determine: + +* The OS distro in the build environment +* OS packages installed in the build environment +* Trusted CA certificates in the build environment +* The default user in the build environment + +#### Anatomy of a build image + +Typically, a `build` image may include: + +* Shell +* C-compiler +* Minimal operating system distribution, such as Linux utilities that build systems might call out to +* Build time libraries + +### Runtime image + +A `runtime image` is an `OCI image` that serves as the base image for the final application image. + +A typical runtime image might determine: + +* The OS distro or distroless OS in the launch environment +* OS packages installed in the launch environment +* Trusted CA certificates in the launch environment +* The default user in the run environment + +#### Anatomy of a runtime base image + +A `runtime` image may contain: + +* No-shell, unless it's needed by the application +* Runtime libraries, such as Libfreetype +* Runtime platforms, such as python interpreter, which are generally added by buildpacks + +For more details on `build` and `runtime` images, you can check out the [specification][spec] + +[spec]: https://github.com/buildpacks/spec/blob/main/platform.md#build-image diff --git a/content/docs/for-platform-operators/concepts/builder.md b/content/docs/for-platform-operators/concepts/builder.md index 8b85704db..6d435735b 100644 --- a/content/docs/for-platform-operators/concepts/builder.md +++ b/content/docs/for-platform-operators/concepts/builder.md @@ -20,14 +20,15 @@ A builder consists of the following components: * [Buildpacks][buildpack] * A [lifecycle][lifecycle] -* A [build image](/docs/for-app-developers/concepts/base-images/build/) -* A reference to a [run image](/docs/for-app-developers/concepts/base-images/run/) +* A [build image][build-image] +* A reference to a [run image][run-image] ### Resources To learn how to create your own builder, see our [Operator's Guide][operator-guide]. -[builder-config]: /docs/reference/builder-config/ [buildpack]: /docs/for-platform-operators/concepts/buildpack/ [lifecycle]: /docs/for-platform-operators/concepts/lifecycle/ [operator-guide]: /docs/for-platform-operators/ +[build-image]: /docs/for-platform-operators/concepts/base-images +[run-image]: /docs/for-platform-operators/concepts/base-images diff --git a/content/docs/for-platform-operators/concepts/lifecycle/analyze.md b/content/docs/for-platform-operators/concepts/lifecycle/analyze.md index 5f8505af6..48c1423c0 100644 --- a/content/docs/for-platform-operators/concepts/lifecycle/analyze.md +++ b/content/docs/for-platform-operators/concepts/lifecycle/analyze.md @@ -15,7 +15,7 @@ This information is used during the `export` phase in order to avoid re-uploadin Starting from `Platform API 0.7`, the `analyze` phase runs before the `detect` phase in order to validate registry access for all images that are used during the `build` as early as possible. In this way it provides faster failures for end users. The other responsibilities of the `analyzer` were moved to the `restorer`.\ For more information, please see [this migration guide][platform-api-06-07-migration]. -The `lifecycle` should attempt to locate a reference to the latest `OCI image` from a previous build that is readable and was created by the `lifecycle` using the same application source code. If no such reference is found, the `analysis` is skipped.\ +The `lifecycle` should attempt to locate a reference to the latest `OCI image` from a previous build that is readable and was created by the `lifecycle` using the same application source code. If no such reference is found, the `analysis` is skipped. The `lifecycle` must write [analysis metadata][analyzedtoml-toml] to ``, where: diff --git a/content/docs/for-platform-operators/how-to/build-inputs/create-builder/run-base.md b/content/docs/for-platform-operators/how-to/build-inputs/create-builder/run-base.md index e355ecaf4..4d5d3788d 100644 --- a/content/docs/for-platform-operators/how-to/build-inputs/create-builder/run-base.md +++ b/content/docs/for-platform-operators/how-to/build-inputs/create-builder/run-base.md @@ -22,13 +22,13 @@ FROM ubuntu:jammy # Install packages that we want to make available at run time RUN apt-get update && \ apt-get install -y xz-utils ca-certificates && \ - rm -rf /var/lib/apt/lists/* \ + rm -rf /var/lib/apt/lists/* # Create user and group ARG cnb_uid=1000 ARG cnb_gid=1000 RUN groupadd cnb --gid ${cnb_gid} && \ - useradd --uid ${cnb_uid} --gid ${cnb_gid} -m -s /bin/bash cnb \ + useradd --uid ${cnb_uid} --gid ${cnb_gid} -m -s /bin/bash cnb # Set user and group USER ${cnb_uid}:${cnb_gid} diff --git a/content/docs/for-platform-operators/tutorials/lifecycle/_index.md b/content/docs/for-platform-operators/tutorials/lifecycle/_index.md index 90f0f1148..0a09a2d74 100644 --- a/content/docs/for-platform-operators/tutorials/lifecycle/_index.md +++ b/content/docs/for-platform-operators/tutorials/lifecycle/_index.md @@ -5,4 +5,442 @@ expand=true include_summaries=true +++ -Coming soon! In the meantime check out this excellent [blog post](https://medium.com/buildpacks/unpacking-cloud-native-buildpacks-ff51b5a767bf) from our community. +A `platform` orchestrates builds by invoking the [lifecycle][lifecycle] binary together with buildpacks and application source code to produce a runnable `OCI image`. + + + +The majority of Buildpack users use community-maintained platforms, such as [pack][pack] and [kpack][kpack], to run Buildpacks and create `OCI images`. However this might not be desireable especially for users maintaining their own platforms and seeking more control over how the underlying Buildpack `lifecycle phases` are executed. + +> This tutorial is derived from a [blog post][blog post] contributed by one of our community members. + +In this step-by-step tutorial, you will build a `Bash` application without using any `platform` tooling like `pack` or `kpack`. You will also leverage the individual `lifecycle phases` to produce a runnable application image. + +## Prerequisites + +This tutorial has been tested on linux amd64 and darwin arm64 platforms. You'll need to clone a local copy of the following to get started: + +* The CNB `lifecycle` + + ```text + git clone https://github.com/buildpacks/lifecycle + ``` + +* The official `Buildpack.io` samples repo + + ```text + git clone https://github.com/buildpacks/samples + ``` + +As previously mentioned, the `lifecycle` orchestrates `Buildpacks` then assembles the resulting artifacts into an `OCI image`. The `lifecycle` is composed of a series of distinct `phases` that need to be executed to have the final image built and exported. + +## Overview + +Now that you’re set up, let’s build our `Bash` application and dive deeper into the `lifecycle` and its phases. + +### Build the lifecycle + +As a starting step, you need to build the `lifecycle` in order to use its phases. This could be done by navigating to the `lifecycle` directory and executing one of the following commands, depending on your system architecture. + +* `make build-linux-amd64` for `AMD64` architectures (for Linux users) +* `make build-darwin-arm64` for `ARM64` architectures (for Mac users) + +It's recommended to check the [lifecycle releases][releases] page to download binaries based on your system. +> Please note that the entire process is most easily followed on Linux systems + +### Set environment variables + +In order to execute the various `lifecycle phases` correctly, you first need to set the values of few important environment variables by running the following commands in the terminal: + +```text +export CNB_USER_ID=$(id -u) CNB_GROUP_ID=$(id -g) CNB_PLATFORM_API=0.14 +export CNB_SAMPLES_PATH="//samples" +export CNB_LIFECYCLE_PATH="//lifecycle" +``` + +Where + +* `CNB_USER_ID` and `CNB_GROUP_ID` are arbitrary values that need to be consistent. This example re-uses our user id and group id for the `CNB` user. In a production system, these are commonly set to `1000`. +* `CNB_PLATFORM_API` or the `Platform API` version, varies depending on the use case. This tutorial uses `v0.14`, which is the latest [Platform API][Platform API] version. +* `CNB_SAMPLES_PATH` represents the path of our local copy of the `samples` directory. +* `CNB_LIFECYCLE_PATH` represents the path of our local compiled `lifecycle` directory. + +> Please note that we only run the commands above on a host machine for the purpose of this tutorial, which is not a common practice for buildpacks. + +### Examine lifecycle phases + +A single app image build consists of the following phases: + +1. [Analysis](#analyze) +2. [Detection](#detect) +3. [Cache Restoration](#restore) +4. [Build](#build) +5. [Export](#export) + +> Note that a `platform` executes the phases above either by invoking phase-specific lifecycle binaries in order or by executing `/cnb/lifecycle/creator`. + +Let's expand each `lifecycle` phase to explain how the `lifecycle` orchestrates buildpacks: + +#### Analyze + +The `analyze` phase runs before the `detect` phase in order to validate registry access for all images used during the `build` as early as possible. In this way it provides faster failures for end users. + +Prior to executing `/cnb/lifecycle/analyzer`, you need to create a parent directory for this tutorial and two other directories inside it as follows: + +```text +mkdir /tmp/tutorial # or your preferred directory +cd /tmp/tutorial +mkdir -p apps/bash-script +mkdir -p layers +``` + +* `apps` directory that contains a `bash-script` directory +* `layers` directory that contains subdirectories representing each layer created by the Buildpack in the final image or build cache. + +Next, you need to copy the `bash-script` samples into our `apps/bash-script` directory, which will host our app's source code. + +```text +cp -r "${CNB_SAMPLES_PATH}/apps/bash-script" ./apps/ +``` + +Now, you can invoke the `analyzer` for `AMD64` architecture + +```text +${CNB_LIFECYCLE_PATH}/analyzer -log-level debug -daemon -layers="./layers" -run-image cnbs/sample-stack-run:jammy apps/bash-script +``` + +Or if you are on an `ARM64` platform + +```text +${CNB_LIFECYCLE_PATH}/analyzer -log-level debug -daemon -layers="./layers" -run-image arm64v8/ubuntu:latest apps/bash-script +``` + +The commands above run the `analyzer` with: + +* A `debug` logging level +* Pointing to the local `Docker daemon` as the repository where the lifecycle should look for images +* Pointing to the `layers` directory, which is the `lifecycle`'s main working directory +* Pointing to a `run` image, the base image for the application +* Specifying a name for the final application image + +Now the `analyzer`: + +* Checks the image repository (`daemon` in this case) for a previous image called `apps/bash-script` +* Reads metadata from the previous image (if it exists) for later use +* Verifies that have permission to create or update the image called `apps/bash-script` in the image repository + +In this tutorial, there is no previous `apps/bash-script` image, and the output produced should be similar to the following: + +```text +sample-stack-run:jammy apps/bash-script +Starting analyzer... +Parsing inputs... +Ensuring privileges... +Executing command... +Timer: Analyzer started at 2024-09-30T07:38:14Z +Image with name "apps/bash-script" not found +Image with name "cnbs/sample-stack-run:jammy" not found +Timer: Analyzer ran for 41.92µs and ended at 2024-09-30T07:38:14Z +Run image info in analyzed metadata is: +{"Reference":"","Image":"cnbs/sample-stack-run:jammy","Extend":false,"target":{"os":"linux","arch":"amd64"}} +``` + +Now if you `cat ./layers/analyzed.toml`, you should see a few null entries, a `run-image` section that records the provided name provided, and the found `os/arch`. + +#### Detect + +In this phase, the `detector` looks for an ordered group of buildpacks that will be used during the `build` phase. The `detector` requires an `order.toml` file to be provided. We can derive an order from `builder.toml` in the `samples` directory while removing the deprecated `stack` section as follows: + +```text +cat "${CNB_SAMPLES_PATH}/builders/jammy/builder.toml" | grep -v -i "stack" | sed 's/\.\.\/\.\./\./' > order.toml + +``` + +`order.toml` files contain a list of groups with each group containing a list of buildpacks. The `detector` reads `order.toml` and looks for the first group that passes the detection process. + +##### Set buildpacks layout directory + +Before running the `detector`, you need to: + +1. Create a `buildpacks` directory in the `root` directory + + ```text + mkdir -p buildpacks + ``` + +2. Then you must populate the `buildpacks` directory with your buildpacks of interest. + + > You have to follow the [directory layout][directory layout] defined in the buildpack spec, where each top-level directory is a `buildpack ID` and each second-level directory is a `buildpack version`. + + We will use [`dasel`](http://github.com/tomwright/dasel/) to help us parse toml files. + + ```command + $ go install github.com/tomwright/dasel/v2/cmd/dasel@master + + Let’s do that for every buildpack in the `samples/buildpacks` directory: + + ```text + for f in $(ls --color=no ${CNB_SAMPLES_PATH}/buildpacks | grep -v README) + do + bp_version=$(cat ${CNB_SAMPLES_PATH}/buildpacks/$f/buildpack.toml | dasel -r toml buildpack.version | sed s/\'//g); + mkdir -p ./buildpacks/samples_"${f}"/${bp_version} + cp -r "$CNB_SAMPLES_PATH/buildpacks/${f}/" ./buildpacks/samples_"${f}"/${bp_version}/ + done + ``` + +Now, you can run the `detector` binary: + +```text +${CNB_LIFECYCLE_PATH}/detector -log-level debug -layers="./layers" -order="./order.toml" -buildpacks="./buildpacks" -app apps/bash-script +``` + +The output of the above command should have `layers/group.toml` and `layers/plan.toml` output files (i.e., the groups that have passed the detection have been written into the `group.toml` file writing its build plan into the `plan.toml` file) + +```text +Starting detector... +Parsing inputs... +Ensuring privileges... +Executing command... +Timer: Detector started at 2024-10-01T07:00:50Z +Checking for match against descriptor: {linux []} +target distro name/version labels not found, reading /etc/os-release file +Checking for match against descriptor: {linux []} +target distro name/version labels not found, reading /etc/os-release file +Checking for match against descriptor: {linux []} +target distro name/version labels not found, reading /etc/os-release file +Checking for match against descriptor: {linux []} +target distro name/version labels not found, reading /etc/os-release file +Checking for match against descriptor: {linux []} +======== Results ======== +fail: samples/java-maven@0.0.2 +======== Results ======== +fail: samples/kotlin-gradle@0.0.2 +======== Results ======== +fail: samples/ruby-bundler@0.0.1 +======== Results ======== +pass: samples/hello-world@0.0.1 +pass: samples/hello-moon@0.0.1 +Resolving plan... (try #1) +samples/hello-world 0.0.1 +samples/hello-moon 0.0.1 +Timer: Detector ran for 26.011769ms and ended at 2024-10-01T07:00:50Z +``` + +You can view more details about the [order](https://buildpacks.io/docs/for-platform-operators/concepts/lifecycle/detect/#ordertoml), [group](https://buildpacks.io/docs/for-platform-operators/concepts/lifecycle/detect/#grouptoml) and [plan](https://buildpacks.io/docs/concepts/components/lifecycle/detect/#plantoml) toml files in the platform documentation. + +#### Restore + +The `restorer` copies cache contents, if there is a cache, into the build container. This avoids buildpacks having to re-download build-time dependencies that were downloaded during a previous build. + +This tutorial doesn't have any previous builds, i.e., the `analyze` phase didn't return any `cached` image. Therefore the `restore` phase will not be copying any `cache` contents at this stage. Feel free to inspect the `cache` when the `build` is done, and re-run the tutorial using the cache created to see how this speeds things up. + +Meanwhile you can start by creating a `cache` directory, and then run the `restorer` binary as added below: + +```text +mkdir cache +``` + +```text +${CNB_LIFECYCLE_PATH}/restorer -log-level debug -daemon -layers="./layers" -group="./layers/group.toml" -cache-dir="./cache" -analyzed="./layers/analyzed.toml" +``` + +The `cache` directory should now be populated by two sub-directories, `committed` and `staging` as shown in the output below: + +```text +Starting restorer... +Parsing inputs... +Ensuring privileges... +Executing command... +No run metadata found at path "/cnb/run.toml" +Run image info in analyzed metadata is: +{"Reference":"","Image":"cnbs/sample-stack-run:jammy","Extend":false,"target":{"os":"linux","arch":"amd64"}} +Timer: Restorer started at 2024-10-01T07:03:47Z +Restoring Layer Metadata +Reading buildpack directory: /tmp/example/layers/samples_hello-world +Reading buildpack directory: /tmp/example/layers/samples_hello-moon +Reading Buildpack Layers directory /tmp/example/layers +Reading buildpack directory: /tmp/example/layers/samples_hello-world +Reading Buildpack Layers directory /tmp/example/layers +Reading buildpack directory: /tmp/example/layers/samples_hello-moon +Timer: Restorer ran for 274.41µs and ended at 2024-10-01T07:03:47Z +``` + +#### Build + +The `builder` run buildpacks, that do the actual work of transforming application source code into runnable artifacts. + +Before running the `builder`, the following steps are required: + +1. Create two directories: + * `platform` directory to store platform configuration and environment variables + * `workspace` directory to store the application source code + + ```text + mkdir -p platform + mkdir -p workspace + ``` + +2. Copy the source code from the `app` directory to the `workspace` directory + + ```text + cp -r apps/bash-script/* ./workspace + ``` + +3. Create a `launcher` file with instructions to run your application. Note that in a real buildpacks build, the `platform` does not create this file! The `samples/hello-moon` buildpack would create it. In our case, the `samples/hello-moon` buildpack hasn't been updated with this functionality, so we are faking that behavior. + + ```text + mkdir -p layers/samples_hello-moon + cat << EOF > ./layers/samples_hello-moon/launch.toml + [[processes]] + type = "shell" + command = ["./app.sh"] + EOF + ``` + +Now you're ready to run the `builder` as follows: + +```text +${CNB_LIFECYCLE_PATH}/builder -log-level debug -layers="./layers" -group="./layers/group.toml" -analyzed="./layers/analyzed.toml" -plan="./layers/plan.toml" -buildpacks="./buildpacks" -app="./workspace" -platform="./platform" +``` + +Taking a look at the following output shows that you have invoked the two buildpacks that we need in order to run our `bash-script` application. + +```text +Starting builder... +Parsing inputs... +Ensuring privileges... +Executing command... +Timer: Builder started at 2024-10-01T07:07:46Z +target distro name/version labels not found, reading /etc/os-release file +Running build for buildpack samples/hello-world@0.0.1 +Looking up buildpack +Finding plan +Creating plan directory +Preparing paths +Running build command +---> Hello World buildpack + platform_dir files: + /tmp/example/platform: + total 0 + drwxr-xr-x 2 gitpod gitpod 40 Oct 1 07:04 . + drwxr-xr-x 8 gitpod gitpod 180 Oct 1 07:04 .. + env_dir: /tmp/example/platform/env + env vars: + declare -x CNB_BP_PLAN_PATH="/tmp/samples_hello-world-576309032/samples_hello-world/plan.toml" + declare -x CNB_BUILDPACK_DIR="/tmp/example/buildpacks/samples_hello-world/0.0.1" + declare -x CNB_LAYERS_DIR="/tmp/example/layers/samples_hello-world" + declare -x CNB_PLATFORM_DIR="/tmp/example/platform" + declare -x CNB_TARGET_ARCH="amd64" + declare -x CNB_TARGET_DISTRO_NAME="ubuntu" + declare -x CNB_TARGET_DISTRO_VERSION="22.04" + declare -x CNB_TARGET_OS="linux" + declare -x HOME="/home/gitpod" + declare -x HOSTNAME="buildpacks-docs-dusxugo5ehi" + declare -x OLDPWD + declare -x PATH="/bin:/usr/bin:/usr/local/bin" + declare -x PWD="/tmp/example/workspace" + declare -x SHLVL="1" + layers_dir: /tmp/example/layers/samples_hello-world + plan_path: /tmp/samples_hello-world-576309032/samples_hello-world/plan.toml + plan contents: + [[entries]] + name = "some-world" + + [[entries]] + name = "some-world" + [entries.metadata] + world = "Earth-616" +---> Done +Processing layers +Updating environment +Reading output files +Updating buildpack processes +Updating process list +Finished running build for buildpack samples/hello-world@0.0.1 +Running build for buildpack samples/hello-moon@0.0.1 +Looking up buildpack +Finding plan +Creating plan directory +Preparing paths +Running build command +---> Hello Moon buildpack + env_dir: /tmp/example/platform/env + env vars: + declare -x CNB_BP_PLAN_PATH="/tmp/samples_hello-moon-3356528850/samples_hello-moon/plan.toml" + declare -x CNB_BUILDPACK_DIR="/tmp/example/buildpacks/samples_hello-moon/0.0.1" + declare -x CNB_LAYERS_DIR="/tmp/example/layers/samples_hello-moon" + declare -x CNB_PLATFORM_DIR="/tmp/example/platform" + declare -x CNB_TARGET_ARCH="amd64" + declare -x CNB_TARGET_DISTRO_NAME="ubuntu" + declare -x CNB_TARGET_DISTRO_VERSION="22.04" + declare -x CNB_TARGET_OS="linux" + declare -x HOME="/home/gitpod" + declare -x HOSTNAME="buildpacks-docs-dusxugo5ehi" + declare -x OLDPWD + declare -x PATH="/bin:/usr/bin:/usr/local/bin" + declare -x PWD="/tmp/example/workspace" + declare -x SHLVL="1" + layers_dir: /tmp/example/layers/samples_hello-moon + plan_path: /tmp/samples_hello-moon-3356528850/samples_hello-moon/plan.toml + plan contents: +---> Done +Processing layers +Updating environment +Reading output files +Updating buildpack processes +Updating process list +Finished running build for buildpack samples/hello-moon@0.0.1 +Copying SBOM files +Creating SBOM files for legacy BOM +Listing processes +Timer: Builder ran for 20.200892ms and ended at 2024-10-01T07:07:46Z +``` + +#### Export + +The purpose of the `export` phase is to take the output from buildpacks and package it into an `OCI` image using a combination of remote layers, local buildpack-contributed layers (under ``), and the processed `app` directory. + +To export the artifacts built by the `builder`, you first need to specify where to find the `launcher` executable that will be bundled into your image as the entrypoint to run: + +* For AMD64 architectures + + ```text + export CNB_LINUX_LAUNCHER_PATH=//lifecycle/out/linux-amd64/lifecycle/launcher + ``` + +* For ARM64 Architectures + + ```text + export CNB_LINUX_LAUNCHER_PATH=//lifecycle/out/linux-arm64/lifecycle/launcher + ``` + +Now you can run the `exporter`: + +```text +${CNB_LIFECYCLE_PATH}/exporter --log-level debug -launch-cache "./cache" -daemon -cache-dir "./cache" -analyzed "./layers/analyzed.toml" -group "./layers/group.toml" -layers="./layers" -app "./workspace" -launcher="${CNB_LINUX_LAUNCHER_PATH}" apps/bash-script +``` + +You can verify that the image was successfully exported by running the `docker images` command. + +### Run the app image + +Finally, you can run the exported image as follows: + +```text +docker run -it apps/bash-script ./app.sh +``` + +```text +OUTPUT PLACEHOLDER +``` + +## Wrapping up + +At the end of this tutorial, we hope that you now have a better understanding of what happens during each `lifecycle phase`, and how you could use `Buildpacks` to create container images. You are now ready to explore this technology further and customize it to fit your application development and deployment needs. + +[pack]: https://buildpacks.io/docs/for-platform-operators/how-to/integrate-ci/pack/ +[kpack]: https://buildpacks.io/docs/for-platform-operators/how-to/integrate-ci/kpack/ +[lifecycle]: https://buildpacks.io/docs/for-platform-operators/concepts/lifecycle/ +[directory layout]: https://github.com/buildpacks/spec/blob/main/platform.md#buildpacks-directory-layout +[Platform API]: https://github.com/buildpacks/spec/releases?q=platform +[blog post]: https://medium.com/buildpacks/unpacking-cloud-native-buildpacks-ff51b5a767bf +[releases]: https://github.com/buildpacks/lifecycle/releases