31 个版本 (破坏性更新)

0.22.0 2024年6月18日
0.20.0 2024年4月12日
0.19.0 2024年2月23日
0.17.0 2023年12月6日
0.1.0 2021年3月18日

#3 in #opinionated

Download history 228/week @ 2024-04-25 145/week @ 2024-05-02 31/week @ 2024-05-09 29/week @ 2024-05-16 31/week @ 2024-05-23 97/week @ 2024-05-30 57/week @ 2024-06-06 396/week @ 2024-06-13 126/week @ 2024-06-20 144/week @ 2024-06-27 344/week @ 2024-07-04 70/week @ 2024-07-11 40/week @ 2024-07-18 245/week @ 2024-07-25 54/week @ 2024-08-01 84/week @ 2024-08-08

每月430 次下载
用于 2 crates

BSD-3-Clause

330KB
6.5K SLoC

libcnb.rs − 构建状态 文档 最新版本 MSRV

libcnb.rs 是一个用于在 Rust 中编写 Cloud Native Buildpacks 的框架。它是一个具有语言构造和方便方法的意见性实现,用于处理规范。它重视对规范和数据格式的严格遵守。

它目前针对 CNB Buildpack API 规范0.10 版本。

快速入门指南

本快速入门指南将指导您使用 libcnb.rs 在 Rust 中编写简单的 Cloud Native Buildpack,还将演示如何打包您的 buildpack 以及如何使用它构建应用程序镜像。

开发环境设置

除了 libcnb 包之外,我们还需要一些工具来编译、打包和运行 buildpack。以下步骤只需执行一次,不需要为每个将要编写的 buildpack 重复执行。

libcnb Cargo 命令

首先安装 libcnb-cargo,它提供了我们将使用的 libcnb Cargo 命令,用于稍后打包我们的 buildpack

cargo install --locked libcnb-cargo

交叉编译先决条件

通常,我们在一个与最终运行构建包的平台不同的平台上编写和构建构建包。这意味着我们必须进行交叉编译构建包。libcnb package Cargo 命令尝试根据您的宿主平台帮助您设置环境,但我们需要安装适当的 Rust 目标平台,我们可以使用 rustup 来安装。

rustup target add x86_64-unknown-linux-musl

Docker

如果您还没有安装 Docker,我们需要安装它。有关如何在您的操作系统上安装 Docker 的说明,请参阅 Docker 文档:https://docs.docker.net.cn/engine/install/

pack

为了在本地运行我们的构建包,我们将使用由 Cloud Native Buildpacks 项目维护的 pack 工具来支持构建包的使用。这是我们最终将用来运行构建包并创建应用程序镜像的工具。您可以在以下位置找到有关安装它的文档:https://buildpacks.io/docs/install-pack/

项目设置

在我们成功设置开发环境之后,我们可以继续创建一个新的 Rust 项目用于我们的构建包。首先,我们使用 Cargo 创建一个新的二进制包

cargo new my-buildpack

然后,将 libcnb 依赖项添加到您项目的 Cargo.toml

cargo add libcnb

注意:如果您在执行 cargo add 时遇到错误,请确保您正在使用 Rust 1.62+,否则请安装 cargo-edit

由于我们正在编写 Cloud Native Buildpack,我们还需要一个 buildpack.toml。使用以下模板,并将其写入到名为 buildpack.toml 的文件中,该文件位于项目的根目录,紧挨着 Cargo.toml

api = "0.10"

[buildpack]
id = "libcnb-examples/my-buildpack"
version = "0.1.0"
name = "My Buildpack"

这就足够了!现在我们可以继续编写一些构建包代码了!

编写构建包

我们正在编写的构建包将非常简单。我们将在构建过程中输出一个 "Hello World" 消息,并将默认进程类型设置为在运行应用程序镜像时也会输出 "Hello World" 的命令。更复杂的构建包示例可以在 示例目录 中找到。

修改项目的 src/main.rs 文件,包含以下内容

use libcnb::build::{BuildContext, BuildResult, BuildResultBuilder};
use libcnb::data::launch::{LaunchBuilder, ProcessBuilder};
use libcnb::data::process_type;
use libcnb::detect::{DetectContext, DetectResult, DetectResultBuilder};
use libcnb::generic::{GenericError, GenericMetadata, GenericPlatform};
use libcnb::{buildpack_main, Buildpack};

pub(crate) struct HelloWorldBuildpack;

impl Buildpack for HelloWorldBuildpack {
    // The CNB platform this buildpack targets, usually `GenericPlatform`. See the CNB spec for
    // more information about platforms:
    // https://github.com/buildpacks/spec/blob/main/buildpack.md
    type Platform = GenericPlatform;

    // The type for the metadata of the buildpack itself. This is the data found in the
    // `[metadata]` section of your buildpack's `buildpack.toml`. The framework will automatically
    // try to parse it into the specified type. This example buildpack uses GenericMetadata which
    // provides low-level access to the TOML table.
    type Metadata = GenericMetadata;

    // The error type for this buildpack. Buildpack authors usually implement an enum with
    // specific errors that can happen during buildpack execution. This error type should
    // only contain error specific to this buildpack, such as `CouldNotExecuteMaven` or
    // `InvalidGemfileLock`. This example buildpack uses `GenericError` which means this buildpack
    // does not specify any errors.
    //
    // Common errors that happen during buildpack execution such as I/O errors while
    // writing CNB TOML files are handled by libcnb.rs itself.
    type Error = GenericError;

    // This method will be called when the CNB lifecycle executes the detect phase (`bin/detect`).
    // Use the `DetectContext` to access CNB data such as the operating system this buildpack is currently
    // executed on, the app directory and similar things. When using libcnb.rs, you never have
    // to read environment variables or read/write files to disk to interact with the CNB lifecycle.
    //
    // One example of this is the return type of this method. `DetectResult` encapsulates the
    // required exit code as well as the data written to the build plan. libcnb.rs will,
    // according to the returned value, handle both writing the build plan and exiting with
    // the correct status code for you.
    fn detect(&self, _context: DetectContext<Self>) -> libcnb::Result<DetectResult, Self::Error> {
        DetectResultBuilder::pass().build()
    }

    // Similar to detect, this method will be called when the CNB lifecycle executes the
    // build phase (`bin/build`).
    fn build(&self, context: BuildContext<Self>) -> libcnb::Result<BuildResult, Self::Error> {
        println!("Hello World!");
        println!("The build is running on: {} ({})!", context.target.os, context.target.arch);

        BuildResultBuilder::new()
            .launch(
                LaunchBuilder::new()
                    .process(
                        ProcessBuilder::new(process_type!("web"), ["echo"])
                            .arg("Hello World!")
                            .default(true)
                            .build(),
                    )
                    .build(),
            )
            .build()
    }
}

// Implements the main function and wires up the framework for the given buildpack.
buildpack_main!(HelloWorldBuildpack);

打包构建包

现在我们的构建包已经编写完成,我们需要将其打包以便运行。如果您按照设置开发环境的步骤操作,您就有权访问处理打包的 libcnb Cargo 命令。

在您的项目目录中,运行 cargo libcnb package 开始打包

$ cargo libcnb package
🚚 Preparing package directory...
🖥️ Gathering Cargo configuration (for x86_64-unknown-linux-musl)
🏗️ Building buildpack dependency graph...
🔀 Determining build order...
🚚 Building 1 buildpacks...
📦 [1/1] Building libcnb-examples/my-buildpack (./)
# Omitting compilation output...
    Finished dev [unoptimized] target(s) in 8.24s
Successfully wrote buildpack directory: packaged/x86_64-unknown-linux-musl/debug/libcnb-examples_my-buildpack (4.09 MiB)
✨ Packaging successfully finished!

💡 To test your buildpack locally with pack, run:
pack build my-image-name \
  --buildpack packaged/x86_64-unknown-linux-musl/debug/libcnb-examples_my-buildpack \
  --path /path/to/application

/Users/example/src/my-buildpack/packaged/x86_64-unknown-linux-musl/debug/libcnb-examples_my-buildpack

如果您遇到有关如何安装所需工具以从宿主平台交叉编译到目标平台的错误提示,请按照提示操作,然后重试。这些根据平台而异,这就是为什么它们不包含在本快速入门指南中的原因。

运行构建包

您可能会在输出中看到我们现在可以使用 pack 在本地运行我们的构建包。在我们能够这样做之前,我们需要一个要构建的应用程序。由于我们的构建包根本不与应用程序代码交互,我们只需创建一个空目录并将其用作我们的应用程序

$ mkdir bogus-app
$ pack build my-image --buildpack packaged/x86_64-unknown-linux-musl/debug/libcnb-examples_my-buildpack --path bogus-app --builder heroku/builder:22
...
===> ANALYZING
Image with name "my-image" not found
===> DETECTING
libcnb-examples/my-buildpack 0.1.0
===> RESTORING
===> BUILDING
Hello World!
The build is running on: linux (amd64)!
===> EXPORTING
Adding layer 'buildpacksio/lifecycle:launch.sbom'
Adding 1/1 app layer(s)
Adding layer 'buildpacksio/lifecycle:launcher'
Adding layer 'buildpacksio/lifecycle:config'
Adding layer 'buildpacksio/lifecycle:process-types'
Adding label 'io.buildpacks.lifecycle.metadata'
Adding label 'io.buildpacks.build.metadata'
Adding label 'io.buildpacks.project.metadata'
Setting default process type 'web'
Saving my-image...
*** Images (85b067fc926a):
      my-image
Successfully built image my-image

运行镜像

新创建的 Docker 镜像可以像使用通过 docker build 创建的 Docker 镜像一样运行。如果一切顺利,您应该在您的终端中看到我们的 "Hello World!" 消息

$ docker run my-image
Hello World!

下一步

虽然本快速入门指南中编写的构建包不太有用,但它可以作为更有用构建包的起点。要了解更多关于libcnb API的信息,请浏览示例目录docs.rs上的文档

稍后,当您准备好编写构建包的集成测试时,请参阅libcnb-test文档

依赖项

~4–14MB
~171K SLoC