Knative 系列(二):兵马未动粮草先行之 Build 篇

阅读数:6625 2019 年 6 月 11 日

在该系列的第一篇文章中,主要介绍了 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 的集群中执行以下命令即可:

复制代码
   kubectl apply --filename https://github.com/knative/build/releases/download/v0.6.0/build.yaml

执行成功以后,可以通过以下命令查看:

复制代码
kubectl get pods --namespace knative-build

可以看到,在 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 文件:

复制代码
apiVersion: build.knative.dev/v1alpha1
kind: Build
metadata:
  name: kaniko-build
spec:
  serviceAccountName: build-bot   // 如果源码或者仓库为公开可以不用创建 serviceAccount
  source:
    git:
      url: https://github.com/my-user/my-repo   // 你的源码仓库地址
      revision: master                          // 你的源码分支地址
  template:
    name: kaniko                               
    arguments:
    - name: IMAGE
      value: us.gcr.io/my-project/my-app         // 构建成功以后镜像存放的镜像仓库地址

以下是其中的几个关键配置:

serviceAccountName 需要先创建一个 serviceAccount 资源,里边包含了构建过程中拉取代码或者 pull/push 镜像的认证信息,如果你的代码和镜像都放在一个公开的仓库里则可以不用定义这个资源。
source source 中指定了你的代码源,revision 是代码的分支
template 使用的 buildtemplate 的名称,也是由 build 定义的一个 CRD 资源

如果想在自己的代码仓库尝试用 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 是什么样子。

复制代码
apiVersion: build.knative.dev/v1alpha1
kind: BuildTemplate
metadata:
  name: kaniko
spec:
  parameters:
  - name: IMAGE
    description: The name of the image to push
  - name: DOCKERFILE
    description: Path to the Dockerfile to build.
    default: /workspace/Dockerfile
  steps:
  - name: build-and-push
    image: gcr.io/kaniko-project/executor
    args:
    - --dockerfile=${DOCKERFILE}
    - --destination=${IMAGE}
    env:
    - name: DOCKER_CONFIG
      value: /builder/home/.docker

buildtempate 中也有几个关键配置:

steps 定义构建的步骤
builder builders 就是每个 steps 中定义的 image,每个 step 中必须要定义一个 builder,builder 是 steps 具体的执行者,后续在到 build 的实现中我们可以看到为什么每个 step 一定要去指定一个 image

kaniko 的 buildtemplate 十分简单,只有一个 step,然后传入两个参数 DOCKERFILE 和 IMAGE 即可,DOCKERFILE 是工程中 dockerfile 所在的文件路径,IMAGE 是要推送的镜像仓库地址。

这两个文件都准备好以后你只需要执行以下两条命令, 一切顺利的话一段时间时候以后,你就可以在你的镜像仓库里看到你刚刚构建好的镜像了。

复制代码
kubectl create -f kaniko.yaml
kubectl create -f build.yaml

如果只是想体验一次 Build 带来的基于原生 K8S 的快捷构建,到这里你的体验之旅就已经结束了,如果想问到底执行完以后发生了什么,那就再花点时间看看到底发生了什么?

Build 构建实现

在上述步骤创建完 build.yaml 以后执行

复制代码
kubectl get pod

我们发现多出了一个 pod,用 describe 查看 POD 可以看到以下信息:

复制代码
Name:               kaniko-build-pod-a4f897
Namespace:          default
Controlled By:      Build/kaniko-build
Init Containers:
build-step-credential-initializer:
Image:          gcr.io/knative-releases/github.com/knative/build/cmd/creds-init@sha256:101f537b53b895b28b84ac3c74ede7d250845e24c51c26516873d8ccb23168ce
  .......
  build-step-git-source-0:
    Image:         gcr.io/knative-releases/github.com/knative/build/cmd/git-init@sha256:ce2c17308e9cb81992be153861c359a0c9e5f69c501a490633c8fe54ec992d53
    Args:
      -url
      https://github.com/lihua871205/2048.git
      -revision
      master
  ......
  build-step-build-and-push:
    Image:         gcr.io/kaniko-project/executor
    Args:
      --dockerfile=/workspace/Dockerfile
      --destination=swr.cn-north-1.myhuaweicloud.com/l00283074/sample:latest
  ......

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 系列(一):基本概念和原理解读》

收藏

评论

微博

发表评论

注册/登录 InfoQ 发表评论

最新评论

陈锋 2019 年 06 月 11 日 13:11 1 回复
Proposal: Knative Build deprecation in favor of Tekton Pipelines #614 https://github.com/knative/build/issues/614
月亮走我也走 2019 年 06 月 11 日 12:31 0 回复
专业
没有更多了