无需 Dockerfile 的镜像构建:BuildPack vs Dockerfile

e94cddde97998ee81666e8fa638ba33b.gif

作者 | Addo Zhang

来源 | 云原生指北

过去的工作中,我们使用微服务、容器化以及服务编排构建了技术平台。为了提升开发团队的研发效率,我们同时还提供了 CICD 平台,用来将代码快速的部署到 Openshift(企业级的 Kubernetes) 集群。

部署的第一步就是应用程序的容器化,持续集成的交付物从以往的 jar 包、webpack 等变成了容器镜像。容器化将软件代码和所需的所有组件(库、框架、运行环境)打包到一起,进而可以在任何环境任何基础架构上一致地运行,并与其他应用“隔离”。

我们的代码需要从源码到编译到最终可运行的镜像,甚至部署,这一切在 CICD 的流水线中完成。最初,我们在每个代码仓库中都加入了三个文件,也通过项目生成器(类似 Spring Initializer)在新项目中注入:

•Jenkinsfile.groovy:用来定义 Jenkins 的 Pipeline,针对不同的语言还会有多种版本•Manifest YAML:用于定义 Kubernetes 资源,也就是工作负载及其运行的相关描述•Dockerfile:用于构建对象

这个三个文件也需要在工作中不断的演进,起初项目较少(十几个)的时候我们基础团队还可以去各个代码仓库去维护升级。随着项目爆发式的增长,维护的成本越来越高。我们对 CICD 平台进行了迭代,将“Jenkinsfile.groovy”和 “manifest YAML”从项目中移出,变更较少的 Dockerfile 就保留了下来。

随着平台的演进,我们需要考虑将这唯一的“钉子户” Dockerfile 与代码解耦,必要的时候也需要对 Dockerfile 进行升级。因此调研了一下 buildpacks,就有了今天的这篇文章。

什么是 Dockerfile

Docker 通过读取 Dockerfile 中的说明自动构建镜像。Dockerfile 是一个文本文件,包含了由 Docker 可以执行用于构建镜像的指令。我们拿之前用于测试 Tekton 的 Java 项目[1]的 Dockerfile 为例:

FROM openjdk:8-jdk-alpine
RUN mkdir /app
WORKDIR /app
COPY target/*.jar /app/app.jar
ENTRYPOINT ["sh","-c","java -Xmx128m -Xms64m -jar app.jar"]

镜像分层

你可能会听过 Docker 镜像包含了多个层。每个层与 Dockerfile 中的每个命令对应,比如 RUNCOPYADD。某些特定的指令会创建一个新的层,在镜像构建过程中,假如某些层没有发生变化,就会从缓存中获取。

在下面的 Buildpack 中也同样通过镜像分层和 cache 来加速镜像的构建。

什么是 Buildpack

BuildPack[2] 是一个程序,它能将源代码转换成容器镜像的并可以在任意云环境中运行。通常 buildpack 封装了单一语言的生态工具链。适用于 Java、Ruby、Go、NodeJs、Python 等。

b590dfb71d1aa0dffeb982d48a40ff6b.png
buildpacks.io

Builder 是什么?

一些 buildpacks 按顺序组合之后就是 builder,除了 buildpacks, builder 中还加入了 生命周期[3] 和 stack 容器镜像。

8782796c51e58da9dfc1496352693a2e.png

stack 容器镜像由两个镜像组成:用于运行 buildpack 的镜像 build image,以及构建应用镜像的基础镜像 run image。如上图,就是 builder 中的运行环境。

Buildpack 的工作方式

0eaf29fb20074b968b0ef56f026ff5de.png
how buildpack works

每个 buildpack 运行时都包含了两个阶段:

5831c9029f3659c3544c0bda033466ee.png
phases

1. 检测阶段

通过检查源代码中的某些特定文件/数据,来判断当前 buildpack 是否适用。如果适用,就会进入构建阶段;否则就会退出。比如:

•Java maven 的 buildpack 会检查源码中是否有 pom.xml•Python 的 buildpack 会检查源码中是否有 requirements.txt 或者 setup.py 文件•Node buildpack 会查找 package-lock.json 文件。

2. 构建阶段

在构建阶段会进行如下操作:

1.设置构建环境和运行时环境2.下载依赖并编译源码(假如需要的话)3.设置正确的 entrypoint 和启动脚本。

比如:

•Java maven buildpack 在检查到有 pom.xml 文件之后,会执行 mvn clean install -DskipTests•Python buildpack 检查到有 requrements.txt 之后,会执行 pip install -r requrements.txt•Node build pack 检查到有 package-lock.json 后执行 npm install

BuildPack 上手

那到底如何在没有 Dockerfile 的情况下使用 builderpack 构建镜像的。看了上面这些,大家基本上也都能了解到这个核心就在 buildpack 的编写和使用的。

其实现在有很多开源的 buildpack 可以用,没有特定定制的情况下无需自己手动编写。比如下面的几个大厂开源并维护的 Buildpacks:

•Heroku Buildpacks[4]•Google Buildpacks[5]•Paketo[6]

但是正式详细介绍开源的 buildpacks 之前,我们还是通过自己创建 buildpack 的方式来深入了解 Buildpacks 的工作方式。测试项目呢,我们还是用测试 Tekton 的 Java 项目[7]

下面所有的内容都提交到了 Github[8] 上,可以访问:https://github.com/addozhang/buildpacks-sample 获取相关代码。

最终的目录buildpacks-sample结构如下:

├── builders
│   └── builder.toml
├── buildpacks
│   └── buildpack-maven
│       ├── bin
│       │   ├── build
│       │   └── detect
│       └── buildpack.toml
└── stacks
├── build
│   └──Dockerfile
├── build.sh
└── run
└──Dockerfile

创建 buildpack

pack buildpack new examples/maven \
--api 0.5 \
--path buildpack-maven \
--version 0.0.1 \
--stacks io.buildpacks.samples.stacks.bionic

看下生成的 buildpack-maven 目录:

buildpack-maven
├── bin
│   ├── build
│   └── detect
└── buildpack.toml

各个文件中都是默认的初试数据,并没有什么用处。需要添加些内容:

bin/detect

#!/usr/bin/env bash
if[[!-f pom.xml ]];then
exit100
fi
plan_path=$2
cat >>"${plan_path}"<<EOL
[[provides]]
name ="jdk"
[[requires]]
name ="jdk"
EOL

bin/build

#!/usr/bin/env bash
set-euo pipefail
layers_dir="$1"
env_dir="$2/env"
plan_path="$3"
m2_layer_dir="${layers_dir}/maven_m2"
if[[!-d ${m2_layer_dir}]];thenmkdir -p ${m2_layer_dir}echo "cache = true"> ${m2_layer_dir}.toml
fi
ln -s ${m2_layer_dir} $HOME/.m2
echo "---> Running Maven"
mvn clean install -B -DskipTests
target_dir="target"
for jar_file in $(find "$target_dir"-maxdepth 1-name "*.jar"-type f);docat >>"${layers_dir}/launch.toml"<<EOL
[[processes]]
type ="web"
command ="java -jar ${jar_file}"
EOL
break;
done

buildpack.toml

api ="0.5"
[buildpack]id ="examples/maven"version ="0.0.1"
[[stacks]]id ="com.atbug.buildpacks.example.stacks.maven"

创建 stack

构建 Maven 项目,首选需要 Java 和 Maven 的环境,我们使用 maven:3.5.4-jdk-8-slim 作为 build image 的 base 镜像。应用的运行时需要 Java 环境即可,因此使用 openjdk:8-jdk-slim作为 run image 的 base 镜像。

在 stacks 目录中分别创建 build 和 run 两个目录:

build/Dockerfile

FROM maven:3.5.4-jdk-8-slim
ARG cnb_uid=1000
ARG cnb_gid=1000
ARG stack_id
ENV CNB_STACK_ID=${stack_id}
LABEL io.buildpacks.stack.id=${stack_id}
ENV CNB_USER_ID=${cnb_uid}
ENV CNB_GROUP_ID=${cnb_gid}
# Install packages that we want to make available at both build and run time
RUN apt-get update && \apt-get install -y xz-utils ca-certificates && \rm -rf /var/lib/apt/lists/*
# Create user and group
RUN groupadd cnb --gid ${cnb_gid}&& \useradd --uid ${cnb_uid}--gid ${cnb_gid}-m -s /bin/bash cnb
USER ${CNB_USER_ID}:${CNB_GROUP_ID}

run/Dockerfile

FROM openjdk:8-jdk-slim
ARG stack_id
ARG cnb_uid=1000
ARG cnb_gid=1000
LABEL io.buildpacks.stack.id="${stack_id}"
USER ${cnb_uid}:${cnb_gid}

然后使用如下命令构建出两个镜像:

export STACK_ID=com.atbug.buildpacks.example.stacks.maven
docker build --build-arg stack_id=${STACK_ID}-t addozhang/samples-buildpacks-stack-build:latest ./build
docker build --build-arg stack_id=${STACK_ID}-t addozhang/samples-buildpacks-stack-run:latest ./run

创建 Builder

有了 buildpack 和 stack 之后就是创建 Builder 了,首先创建 builder.toml 文件,并添加如下内容:

[[buildpacks]]
id ="examples/maven"
version ="0.0.1"
uri ="../buildpacks/buildpack-maven"
[[order]]
[[order.group]]
id ="examples/maven"
version ="0.0.1"
[stack]
id ="com.atbug.buildpacks.example.stacks.maven"
run-image ="addozhang/samples-buildpacks-stack-run:latest"
build-image ="addozhang/samples-buildpacks-stack-build:latest"

然后执行命令,注意这里我们使用了 --pull-policy if-not-present 参数,就不需要将 stack 的两个镜像推送到镜像仓库了

pack builder create example-builder:latest --config ./builder.toml --pull-policy if-not-present

测试

有了 builder 之后,我们就可以使用创建好的 builder 来构建镜像了。

这里同样加上了 --pull-policy if-not-present 参数来使用本地的 builder 镜像:

# 目录 buildpacks-sample  与 tekton-test 同级,并在 buildpacks-sample  中执行如下命令
pack build addozhang/tekton-test --builder example-builder:latest --pull-policy if-not-present --path ../tekton-test

如果看到类似如下内容,就说明镜像构建成功了(第一次构建镜像由于需要下载 maven 依赖耗时可能会比较久,后续就会很快,可以执行两次验证下):

...
===> EXPORTING
[exporter]Adding1/1 app layer(s)
[exporter]Reusing layer 'launcher'
[exporter]Reusing layer 'config'
[exporter]Reusing layer 'process-types'
[exporter]Adding label 'io.buildpacks.lifecycle.metadata'
[exporter]Adding label 'io.buildpacks.build.metadata'
[exporter]Adding label 'io.buildpacks.project.metadata'
[exporter]Settingdefault process type 'web'
[exporter]Saving addozhang/tekton-test...
[exporter]***Images(0d5ac1158bc0):
[exporter]       addozhang/tekton-test
[exporter]Adding cache layer 'examples/maven:maven_m2'
Successfully built image addozhang/tekton-test

启动容器,会看到 spring boot 应用正常启动:

docker run --rm addozhang/tekton-test:latest
.   ____          _            __ _ _
/\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
(()\___ |'_ | '_||'_ \/ _`| \ \ \ \\\/  ___)||_)|||||||(_||))))
'  |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
::SpringBoot::(v2.2.3.RELEASE)
...

总结

其实现在有很多开源的 buildpack 可以用,没有特定定制的情况下无需自己手动编写。比如下面的几个大厂开源并维护的 Buildpacks:

•Heroku Buildpacks[9]•Google Buildpacks[10]•Paketo[11]

上面几个 buildpacks 库内容比较全面,实现上会有些许不同。比如 Heroku 的执行阶段使用 Shell 脚本,而 Paketo 使用 Golang。后者的扩展性较强,由 Cloud Foundry 基金会支持,并拥有由 VMware 赞助的全职核心开发团队。这些小型模块化的 buildpack,可以通过组合扩展使用不同的场景。

当然还是那句话,自己上手写一个会更容易理解 Buildpack 的工作方式。

引用链接

[1] 测试 Tekton 的 Java 项目: https://github.com/addozhang/tekton-test
[2] BuildPack: https://buildpacks.io/
[3] 生命周期: https://buildpacks.io/docs/concepts/components/lifecycle/
[4] Heroku Buildpacks: https://github.com/heroku/
[5] Google Buildpacks: https://github.com/GoogleCloudPlatform/buildpacks
[6] Paketo: https://github.com/paketo-buildpacks
[7] 测试 Tekton 的 Java 项目: https://github.com/addozhang/tekton-test
[8] Github: https://github.com/addozhang/buildpacks-sample
[9] Heroku Buildpacks: https://github.com/heroku/
[10] Google Buildpacks: https://github.com/GoogleCloudPlatform/buildpacks
[11] Paketo: https://github.com/paketo-buildpacks

8f40c37754a9d714f0534e00f6410405.gif

cbb500f4510669ceef1509990378abf2.png

往期推荐

云计算到底是谁发明的?

从Docker的信号机制看容器的优雅停止

Redis会遇到的坑,你踩过几个?

内容整理志愿者招募了!

d0b11596e1702761bee9d139b01d6fd5.gif

点分享

933b26b5c8501f1ef6e393c1fb218205.gif

点收藏

85c5f26e9ebb07d3983d4bb4b8bd43ad.gif

点点赞

f7264d2ee6c0156cfeece2238785a811.gif

点在看

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/513035.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

android studio json插件_热门Android Studio 插件,这里是Top 20

Android Studio是Google基于IntelliJ开发的一款功能强大的开发工具&#xff0c;它具有构建出色Android应用所需要的一切。借助基于IntelliJ IDEA的强大的功能&#xff0c;插件非常丰富。正确的使用插件可以帮助你提高工作效率&#xff0c;更智能&#xff0c;更快。但是&#xf…

云原生时代,企业多活容灾体系构建思路与最佳实践

简介&#xff1a; 对于云原生的概念解读&#xff0c;大家经常会听到微服务、容器这些&#xff0c;那么这些技术跟企业容灾到底有什么样的关系&#xff1f;其实容灾的需求各行各业都有&#xff0c;比如金融行业对于容灾也有强烈的需求。但是怎么把容灾和多活能力构建起来&#x…

MaxCompute 挑战使用SQL进行序列数据处理

简介&#xff1a; MaxCompute 挑战使用SQL进行序列数据处理 --而不是用MR和函数 日常编写数据加工任务&#xff0c;主要的方法就是使用SQL。第一是因为自己对SQL掌握的比较好&#xff08;十多年数据开发经验&#xff0c;就这几个关键字&#xff0c;也不敢跟别人说自己不行&…

低代码发展专访系列之四:低代码平台会带动企业的组织变革吗?

前言&#xff1a;2019年开始&#xff0c;低代码爆火。有人认为它是第四代编程语言&#xff0c;有人认为它是开发模式的颠覆&#xff0c;也有人认为是企业管理模式的变革……有很多声音&#xff0c;社区讨论很热烈。CSDN随后展开低代码平台产品系列活动&#xff0c;包括低代码开…

esclip直接快捷键构造函数_史上最全IntelliJ IDEA mac版快捷键文档

IntelliJ IDEA 是一款功能强大的Java IDE编辑器&#xff0c;支持java体系的web、客户端、安卓等开发。做为一款优秀的IDE&#xff0c;想要提高效率&#xff0c;最好是记住常用的快捷键&#xff0c;能让你事半功倍&#xff0c;小编整理了IDEA所有的快捷键&#xff0c;让你摆脱鼠…

禁止访问 共享计算机,win7如何禁止局域网用户访问电脑

为了方便共享资源&#xff0c;很多人都会设置网络共享文件夹&#xff0c;但是有些用户觉得在局域网内共享资源是件不安全的事情&#xff0c;那么win7如何禁止局域网用户访问电脑?这里小编就给大家分享一下win7旗舰版32位系统设置用户禁止访问局域网的方法。win7如何禁止局域网…

基于实时深度学习的推荐系统架构设计和技术演进

简介&#xff1a; 整理自 5 月 29 日 阿里云开发者大会&#xff0c;秦江杰和刘童璇的分享&#xff0c;内容包括实时推荐系统的原理以及什么是实时推荐系统、整体系统的架构及如何在阿里云上面实现&#xff0c;以及关于深度学习的细节介绍 本文整理自 5 月 29 日阿里云开发者大会…

阿里云肖力:跳过量变过程的安全质变

简介&#xff1a; 作者肖力从事网络安全工作将近20年&#xff0c;处理过各类攻击威胁&#xff0c;经历了云下云上安全的建设。云计算的安全工作从10年前开始&#xff0c;他们搭建了阿里云平台的防护体系&#xff0c;帮助各行业用户在云上构建企业安全能力。云原生的出现进一步加…

echarts bar 控制大小_echarts基本配置参数

网址&#xff1a;https://www.echartsjs.com/zh/tutorial.html#5%20%E5%88%86%E9%92%9F%E4%B8%8A%E6%89%8B%20ECharts五分钟上手 基本配置1.矩形参数<!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name&q…

opencv opencl加速_回放 | OpenCV Webinar 3:OpenCV深度学习应用与原理分析

OpenCV DNN模块提供了深度学习的推理&#xff0c;支持Caffe、Tensoflow、Torch、Darknet、ONNX等格式的模型&#xff0c;无需用户安装对应的深度学习框架&#xff0c;也无需进行模型格式转换&#xff0c;直接调用DNN模块接口即可创建深度学习应用。DNN模块自2017年8月3.3版本从…

云原生架构应该怎么设计?

简介&#xff1a; 阿里巴巴为大量各行各业的企业客户提供了基于阿里云服务的解决方案和最佳实践&#xff0c;以帮助企业完成数字化转型&#xff0c;并积累了大量经验和教训。阿里巴巴将企业的核心关注点、企业组织与 IT 文化、工程实施能力等多个方面与架构技术相结合&#xff…

360数科知微实验室发布反诈报告:揭秘黑灰产数据流转真相

近日&#xff0c;360数科旗下信息安全知微实验室通过反诈分析研究&#xff0c;追踪溯源网络黑灰产数据非法交易链条&#xff0c;发布系列反诈研究《黑灰产数据流转分析报告》&#xff08;以下简称“报告”&#xff09;。报告称&#xff0c;目前在网络黑产平台流转的数据主要来源…

【详谈 Delta Lake 】系列技术专题 之 Streaming(流式计算)

简介&#xff1a; 本文翻译自大数据技术公司 Databricks 针对数据湖 Delta Lake 的系列技术文章。众所周知&#xff0c;Databricks 主导着开源大数据社区 Apache Spark、Delta Lake 以及 ML Flow 等众多热门技术&#xff0c;而 Delta Lake 作为数据湖核心存储引擎方案给企业带来…

jdbc驱动程序_JDBC操作数据库的步骤

package mysql;import java.sql.Connection;import java.sql.Driver;import java.sql.DriverManager;/** JDBC操作数据库的步骤* 1.注册驱动* 告知JVM使用的是哪一个数据库驱动* 2.获得连接* 使用JDBC中的类&#xff0c;完成对Mysql数据库连接* 3.获得语句执行平台* 通过连接对…

一睹为快 | 施耐德电气全生命周期智能制造解决方案亮相线上工博

作家瓦科拉夫斯米尔在《国家繁荣为什么离不开制造业》曾说过&#xff1a;“制造业始终是技术创新的基本源泉&#xff0c;也是经济增长的原动力。” 反过来看&#xff0c;技术创新该如何推动制造业的发展&#xff0c;从而促进经济增长呢&#xff1f; 12 月 1 日&#xff0c;在…

教程系列——用模板快速生成《客户意见反馈表》

简介&#xff1a; 【开箱即用的模板使用系列教程】将会手把手教给大家如何快速启用钉钉宜搭提供各类模板。今天第二讲&#xff0c;介绍《客户意见反馈表》的模板启用。 【开箱即用的模板使用系列教程】将会手把手教给大家如何快速启用钉钉宜搭提供各类模板。今天第1讲&#xff…

重温设计模式之 Factory

简介&#xff1a; 创建型模式的核心干将&#xff0c;工厂、简单工厂、抽象工厂&#xff0c;还记得清么&#xff0c;一文回顾和对比下。 作者 | 弥高 来源 | 阿里技术公众号 前言 创建型模式的核心干将&#xff0c;工厂、简单工厂、抽象工厂&#xff0c;还记得清么&#xff0c…

云端上的字节,引擎火力全开

作者 | 贾凯强出品 | CSDN云计算&#xff08;ID&#xff1a;CSDNcloud&#xff09;十二月&#xff0c;在产业最震撼的一条消息莫过于字节跳动旗下火山引擎终于出云产品了。字节跳动的业务早已跑在云上&#xff0c;这早已是行业公开的信息。可是这朵云究竟有多大呢&#xff1f;在…

收件服务器信息,收件服务器配置信息

收件服务器配置信息 内容精选换一换SAP HANA运行在SAP HANA云服务器上。需要根据部署场景&#xff0c;创建一台或多台HANA云服务器&#xff0c;用于部署SAP HANA软件。请参见方案和数据规划相关章节&#xff0c;确定HANA云服务器数量及相关规划信息。在集群场景下创建多台HANA云…

Nacos 2.0 升级前后性能对比压测

简介&#xff1a; Nacos 2.0 通过升级通信协议和框架、数据模型的方式将性能提升了约 10 倍&#xff0c;解决继 Nacos 1.0 发布逐步暴露的性能问题。本文通过压测 Nacos 1.0&#xff0c;Nacos 1.0 升级 Nacos 2.0 过程中&#xff0c;Nacos 2.0 进行全面性能对比&#xff0c;直观…