在该系列的第一篇文章中,主要介绍了Knative的基本概念及诞生背景,并提到 Knative 主要由 Build、Serving 和 Eventing 三大核心组件组成,本文将重点 Build 的使用方法。
具体来说,Build 提供源码到容器镜像的构建能力;Serving 提供 Serverless 应用或函数的部署能力,并通过 istio 实现服务管理,同时提供了容器扩缩容能力;Eventing:提供事件触发通道。
Knative 的这三个组件提供了一套完善的 Serverless 方案,让开发者可以只关心自己的代码。提交代码以后,Build 会将源码构建成镜像,Serving 会自动实现应用部署,Eventing 提供事件触发入口,接下来就可以访问到最新应用了。对使用者来说,从源码直接到应用,省去了中间复杂的环节。
Build 完全基于 Kubernetes,设计非常灵活,用户可以利用 Build 定制构建流程,虽然官方文档宣称现在 Knaitve 还不能提供完整的 CI/CD 方案,但是利用 Build 的灵活性完全可以实现 CI 平台搭建,这部分内容会在后面的实现中着重介绍。
本文,我们把 Build 组件拆开揉碎,全面分享给读者。如果现在手头刚好有一个K8s集群,可以跟着文档尝试操作,整个过程甚至不需要占用一杯咖啡的时间。
Build 组件安装
Build 可以作为一个独立组件单独安装,只需要在 K8s 的集群中执行以下命令即可:
执行成功以后,可以通过以下命令查看:
可以看到,在 knative-build 的 namespace 下,新增了两个容器 build-controller 和 build-webhook,build-controller 是 Build 核心模块,其基本业务流程是监控自己创建的 CRD 资源从而实现构建,build-webhook 和大多数的 webhook 功能一样,通过 webhook 的方式对自己的 api 进行校验。
到这里恭喜你,Build 组件已经安装成功了,接下来就可以利用它来进行构建。
build 和 buildtemplate
构建之前,我们需要先了解两个概念:build 和 buildtemplate。这里的 build 不是 knative 的 Buid 组件,而是 Build 组件通过 CRD 定义的一个资源文件,build 通过自己定义资源文件去控制构建流程,所以说,Build 完全基于 K8s 生态,只要有 K8s 集群就可以完成构建而不需要依赖其他外部组件,同时,yaml 定义的资源文件也可以很轻易的移植到其他集群上去。
为了方便理解,我们先看一个 build 的 yaml 文件:
以下是其中的几个关键配置:
如果想在自己的代码仓库尝试用 build 进行构建,只需要修改上面蓝色的部分即可。看起来,build.yaml 非常简单,而且在 yaml 中也没有看到关于构建过程的体现,是因为在这个 build.yaml 里定义了一个 buildtemplate,buildtemplate 中定义了实际构建过程中的 steps(关于 steps 的内容我们稍后会讲到),当我有多个代码库,或者代码库下有多个分支,抑或是代码想用不同的方式去构建,每次都要定义一个完整的 build 文件就显得非常麻烦,这个时候利用 buildtemplate 可以定义很多构建模板,然后只需要像上面的 build.yaml 一样简单指定代码仓库即可。那么,buildtemplate 是必须的么?当然不是,我们可以直接把 steps 写在 buid.yaml 里,但是 buildtemplate 极大的提高了 build 的灵活性和可移植、可重用性。为了方便快速实现构建,knative 的 build-template 代码库中已经预置了大量的 buildtemplate,包括bazel,buildpacks,kaniko等近十个模板,这里我们先用 Kaniko 的 build-template 体验一下 build 的构建过程。
Kaniko 是 Google 推出的构建工具,它基于 Dockerfile 进行构建但是却不需要 docker daemon,我们先来看一下 Kaniko 的 buildtemplate 是什么样子。
buildtempate 中也有几个关键配置:
kaniko 的 buildtemplate 十分简单,只有一个 step,然后传入两个参数 DOCKERFILE 和 IMAGE 即可,DOCKERFILE 是工程中 dockerfile 所在的文件路径,IMAGE 是要推送的镜像仓库地址。
这两个文件都准备好以后你只需要执行以下两条命令,一切顺利的话一段时间时候以后,你就可以在你的镜像仓库里看到你刚刚构建好的镜像了。
如果只是想体验一次 Build 带来的基于原生 K8S 的快捷构建,到这里你的体验之旅就已经结束了,如果想问到底执行完以后发生了什么,那就再花点时间看看到底发生了什么?
Build 构建实现
在上述步骤创建完 build.yaml 以后执行
我们发现多出了一个 pod,用 describe 查看 POD 可以看到以下信息:
POD 里边包含三个 Init Containers:build-step-credential-initializer, build-step-git-source-0 以及 build-step-build-and-push
build-step-credential-initializer:如果 git 和 docker 需要认证的对 git 和 docker 进行认证
build-step-git-source-0:负责将代码拉取到 workspace 下
build-step-build-and-push:是用户自己定义的构建 step,它负责将源码构建成镜像
从这里,我们可能已经猜到 build 的构建实现,利用 Init Containers 的特性,build 先将 source 中的配置生成一个默认的 build-step-git-source-0 接下来再将用户 step 中配置的信息依次解析成多个 Init Containers,当 POD 运行的时候会依次执行所有的 Init Containers 从而实现代码获取,源码构建的流程。这也回答了上面的两个问题:
1、为什么每个 step 都要有一个 builder?这是 Init Containers 的特性决定的,即使是 Source 这个步骤其实也是使用了 Build-Controller 内置的一个镜像;
2、为什么 build 非常灵活?用户可根据自己的场景,自己定制构建镜像,Build 只提供构建流程,但是不提供构建实现,这也是为什么当前有这么多 buildtemplate 的原因。我们再回顾下 Build 的基本流程:
总结
Knative 的 Build 利用 init container 实现了一个基于 K8s 生态的构建流程,用户可以自己定制构建场景,或者利用丰富的 build-template 实现构建,它可以作为一个独立的组件减少 K8s 构建的烦恼,更重要的是可以嵌入到 serving 中(偷偷预告一下后面的章节会讲到 build 如何和 serving 集成到一起)形成完整的 Serverless 生态,只有通过 Build 快捷地将源码变成镜像,才能让 serving 有源源不断的“粮草”大展身手。
相关文章:《Knative 系列(一):基本概念和原理解读》
评论 2 条评论