时间:2025-04-17 19:48
人气:
作者:admin
Cloud Native Buildpacks(简称CNB)是一种标准化、云原生的容器镜像构建系统,其核心目标是:

Cloud Native Buildpacks由Heroku构思,在2018年成为CNCF项目,形成现代云原生标准,被Heroku、Cloud Foundry 和其他 PaaS(例如 Google App Engine、Gitlab、Knative、Deis、Dokku 和 Drie)采用。

|
组件 |
功能说明 |
|
Lifecycle |
Lifecycle管理整个构建过程,由多阶段构成 |
|
Builder |
包含Buildpacks、生命周期组件的构建环境(容器) |
|
Buildpack |
模块化构建逻辑单元(可组合),负责处理应用程序源代码,安装依赖项,配置环境并生成最终的可运行单位 |
CNB通过独特的分层策略构建符合OCI标准的镜像。

每个Buildpack都会检查源代码并提供相关的依赖项。然后,会根据应用程序的源代码和这些依赖项生成一个镜像。
在构建过程中,构建时基础镜像成为执行Buildpack的环境,而运行时基础镜像成为最终应用程序镜像的基础。
Buildpacks可以与特定的构建时基础镜像捆绑在一起,从而生成Builder镜像。Builder提供了一种便捷的Buildpacks分发方式。
下面我们使用Spring官方的宠物诊所(spring-petclinic)应用为例演示CNB构建部署应用的过程。
CNB相关的镜像托管在DockerHub上。因此要求您从本地可以访问DockerHub。
以下以在阿里云的香港/新加坡等非大陆地域的ECS实例作为试验环境。
# 在阿里云香港地域购买一台ECS实例。临时使用可以购买抢占式实例,用完即释放
# 使用Alibaba Cloud Linux3公共镜像创建ECS实例,开公网
# 安装docker和常用工具,启动docker
yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
yum makecache
yum install -y curl git docker-ce
systemctl enable docker && systemctl start docker
# 安装pack CLI。从yum中安装的pack版本太旧无法使用。需要从github下载最新版本
PACK_VERSION="0.36.4"
DOWNLOAD_URL="https://github.com/buildpacks/pack/releases/download/v${PACK_VERSION}/pack-v${PACK_VERSION}-linux.tgz"
curl -fsSL "$DOWNLOAD_URL" -o pack-v${PACK_VERSION}-linux.tgz
tar xzf pack-v0.36.4-linux.tgz
mv pack /usr/local/bin/
# 克隆代码到本地
git clone https://github.com/spring-projects/spring-petclinic.git
cd spring-petclinic
# 使用pack将应用代码构建成容器镜像;这里使用了heroku提供的CNB builder
pack build petclinic --path . --builder heroku/builder:24
[root@cnb-demo spring-petclinic]# pack build petclinic --path . --builder heroku/builder:24
24: Pulling from heroku/builder
Digest: sha256:1f8c4f74030b31af122cbcccd9da975bd136a1076af2e3567bbf1a27c50ac0a3
Status: Image is up to date for heroku/builder:24
24: Pulling from heroku/heroku
Digest: sha256:c697e8808410892d54125b850854b908105dbae1c8e335255b9523c7f4e75516
Status: Image is up to date for heroku/heroku:24
===> ANALYZING
Image with name "petclinic" not found
===> DETECTING
2 of 4 buildpacks participating
heroku/jvm 6.1.2
heroku/maven 6.1.2
===> RESTORING
===> BUILDING
[Warning: No OpenJDK version specified]
Your application does not explicitly specify an OpenJDK version. The latest
long-term support (LTS) version will be installed. This currently is OpenJDK 21.
This default version will change when a new LTS version is released. Your
application might fail to build with the new version. We recommend explicitly
setting the required OpenJDK version for your application.
To set the OpenJDK version, add or edit the system.properties file in the root
directory of your application to contain:
java.runtime.version = 21
[Installing OpenJDK 21.0.5]
[Installing Maven]
Maven wrapper detected, skipping installation.
[Executing Maven]
$ ./mvnw -DskipTests clean install
Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF-8
[INFO] Scanning for projects...
[INFO] Downloading from spring-snapshots: https://repo.spring.io/snapshot/org/springframework/boot/spring-boot-starter-parent/3.4.2/spring-boot-starter-parent-3.4.2.pom
[INFO] Downloading from spring-milestones: https://repo.spring.io/milestone/org/springframework/boot/spring-boot-starter-parent/3.4.2/spring-boot-starter-parent-3.4.2.pom
[INFO] Downloading from central: https://repo.maven.apache.org/maven2/org/springframework/boot/spring-boot-starter-parent/3.4.2/spring-boot-starter-parent-3.4.2.pom
.......... 此处省略非常多的maven build日志..........
.......... spring-petclinic的依赖很多,需要耐心等待下载和编译..........
[INFO] Downloaded from central: https://repo.maven.apache.org/maven2/com/github/luben/zstd-jni/1.5.6-3/zstd-jni-1.5.6-3.jar (6.7 MB at 48 MB/s)
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 35.909 s
[INFO] Finished at: 2025-04-15T12:03:56Z
[INFO] ------------------------------------------------------------------------
===> EXPORTING
Adding layer 'heroku/jvm:openjdk'
Adding layer 'heroku/jvm:runtime'
Adding layer 'buildpacksio/lifecycle:launch.sbom'
Added 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 petclinic...
*** Images (37a5a5d4a590):
petclinic
Adding cache layer 'heroku/jvm:openjdk'
Adding cache layer 'heroku/maven:repository'
Successfully built image petclinic
从上面的日志可以看出,从代码到容器镜像,构建过程包含了以下步骤:
我们查看一下本地的docker镜像,可以发现petclinic就是我们刚刚构建出来的目标容器镜像。
而其他3个镜像都是CNB构建使用的镜像。
[root@cnb-demo spring-petclinic]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
heroku/heroku 24 7c60575a1268 7 days ago 493MB
buildpacksio/lifecycle 0.20.7 c083cc1d50e2 45 years ago 35.6MB
petclinic latest 37a5a5d4a590 45 years ago 821MB
heroku/builder 24 2a52b7dc6e23 45 years ago 1.2GB
在本地运行镜像(注意需要指定应用监听的端口):
[root@cnb-demo spring-petclinic]# docker run -p 8080:8080 petclinic
Picked up JAVA_TOOL_OPTIONS: -XX:MaxRAMPercentage=80.0 -Dfile.encoding=UTF-8
|\ _,,,--,,_
/,`.-'`' ._ \-;;,_
_______ __|,4- ) )_ .;.(__`'-'__ ___ __ _ ___ _______
| | '---''(_/._)-'(_\_) | | | | | | | | |
| _ | ___|_ _| | | | | |_| | | | __ _ _
| |_| | |___ | | | | | | | | | | \ \ \ \
| ___| ___| | | | _| |___| | _ | | _| \ \ \ \
| | | |___ | | | |_| | | | | | | |_ ) ) ) )
|___| |_______| |___| |_______|_______|___|_| |__|___|_______| / / / /
==================================================================/_/_/_/
:: Built with Spring Boot :: 3.4.2
2025-04-15T12:10:51.412Z INFO 1 --- [ main] o.s.s.petclinic.PetClinicApplication : Starting PetClinicApplication v3.4.0-SNAPSHOT using Java 21.0.5 with PID 1 (/workspace/target/spring-petclinic-3.4.0-SNAPSHOT.jar started by heroku in /workspace)
2025-04-15T12:10:51.421Z INFO 1 --- [ main] o.s.s.petclinic.PetClinicApplication : No active profile set, falling back to 1 default profile: "default"
2025-04-15T12:10:53.002Z INFO 1 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data JPA repositories in DEFAULT mode.
2025-04-15T12:10:53.176Z INFO 1 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 160 ms. Found 2 JPA repository interfaces.
2025-04-15T12:10:54.196Z INFO 1 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port 8080 (http)
2025-04-15T12:10:54.216Z INFO 1 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2025-04-15T12:10:54.216Z INFO 1 --- [ main] o.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/10.1.34]
2025-04-15T12:10:54.263Z INFO 1 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2025-04-15T12:10:54.265Z INFO 1 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 2774 ms
2025-04-15T12:10:54.664Z INFO 1 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting...
2025-04-15T12:10:54.934Z INFO 1 --- [ main] com.zaxxer.hikari.pool.HikariPool : HikariPool-1 - Added connection conn0: url=jdbc:h2:mem:3480bd0f-aaa2-489a-9469-99dc4aa2fc52 user=SA
2025-04-15T12:10:54.936Z INFO 1 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Start completed.
2025-04-15T12:10:55.120Z INFO 1 --- [ main] o.hibernate.jpa.internal.util.LogHelper : HHH000204: Processing PersistenceUnitInfo [name: default]
2025-04-15T12:10:55.174Z INFO 1 --- [ main] org.hibernate.Version : HHH000412: Hibernate ORM core version 6.6.5.Final
2025-04-15T12:10:55.219Z INFO 1 --- [ main] o.h.c.internal.RegionFactoryInitiator : HHH000026: Second-level cache disabled
2025-04-15T12:10:55.463Z INFO 1 --- [ main] o.s.o.j.p.SpringPersistenceUnitInfo : No LoadTimeWeaver setup: ignoring JPA class transformer
2025-04-15T12:10:55.550Z INFO 1 --- [ main] org.hibernate.orm.connections.pooling : HHH10001005: Database info:
Database JDBC URL [Connecting through datasource 'HikariDataSource (HikariPool-1)']
Database driver: undefined/unknown
Database version: 2.3.232
Autocommit mode: undefined/unknown
Isolation level: undefined/unknown
Minimum pool size: undefined/unknown
Maximum pool size: undefined/unknown
2025-04-15T12:10:56.718Z INFO 1 --- [ main] o.h.e.t.j.p.i.JtaPlatformInitiator : HHH000489: No JTA platform available (set 'hibernate.transaction.jta.platform' to enable JTA platform integration)
2025-04-15T12:10:56.722Z INFO 1 --- [ main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'
2025-04-15T12:10:57.213Z INFO 1 --- [ main] o.s.d.j.r.query.QueryEnhancerFactory : Hibernate is in classpath; If applicable, HQL parser will be used.
2025-04-15T12:10:58.875Z INFO 1 --- [ main] o.s.b.a.e.web.EndpointLinksResolver : Exposing 14 endpoints beneath base path '/actuator'
2025-04-15T12:10:58.974Z INFO 1 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port 8080 (http) with context path '/'
2025-04-15T12:10:58.991Z INFO 1 --- [ main] o.s.s.petclinic.PetClinicApplication : Started PetClinicApplication in 8.166 seconds (process running for 8.841)
2025-04-15T12:11:07.392Z INFO 1 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'
2025-04-15T12:11:07.392Z INFO 1 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
2025-04-15T12:11:07.394Z INFO 1 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 2 ms
从浏览器可以正常访问:

手工使用pack命令构建在进行部署是比较麻烦的。首先你需要有一个可以访问DockerHub的构建机器,其次还需要有一个docker image registry来托管容器镜像,最后应用部署的工作还要自己来做。
阿里云应用管理支持使用CNB构建应用并部署到云服务器(ECS)上,并支持在代码更新后更新应用,实现GitOps。整个过程完全基于控制台GUI,一键提交部署,非常方便。
应用管理在ECS控制台、OOS控制台都有入口。其中“创建应用”->“通过Git仓库创建”使用了Cloud Native Buildpacks技术。

我们的应用最终会以容器的形式运行,如果代码执行需要参数,运行参数需要通过容器环境变量的形式传入。
如果当前代码是通过别的方式(比如配置文件、命令行参数)传入参数,需要改造成支持环境变量传入。
应用监听端口有以下作用:
下面图示的配置,最终运行容器的命令如下:
docker run -e EnvName=EnvValue -e PORT=8080 -p 8080:8080 <镜像名称>


代码更新后,在“更新应用”->“更新应用程序”里可以拉取最新代码更新容器镜像并重新部署应用。

点击“查看日志”,可以看到CNB构建的日志和云服务器创建的日志:

CNB看起来很美好,但不是任意代码库都能够被CNB支持。
因此在正式使用CNB之前,应用开发者应该了解CNB实现对应用代码的要求。
以Heroku的CNB Builder构建Java应用来举例:
pom.xml。CNB支持的运行时组件的版本会不断更新。如果您在阿里云上使用CNB部署应用遇到问题,可以在应用管理支持钉群(群号:10880003624)里中反馈或提交工单,我们会帮助您解决。