Build(构建)

Knative 的 Serving(服务)组件是解决如何从容器到 URL 的,而 Build 组件是解决如何从源代码到容器的。Build resource 允许您定义如何编译代码和构建容器,而不是指向预构建的容器镜像。这确保了在将代码发送到容器镜像库之前以一种一致的方式编译和打包代码。本章中将会向您介绍一些新的组件:

  • Build

驱动构建过程的自定义 Kubernetes 资源。在定义构建时,您需要定义如何获取源代码以及如何创建容器镜像来运行代码。

  • Build Template

封装可重复构建步骤集合以及允许对构建进行参数化的模板。

  • Service Account

允许对私有资源(如 Git 仓库或容器镜像库)进行身份验证。

[备注] 在撰写本章时,社区正在积极的将 Build 迁移到 Build Pipeline(构建流水线),对 Build 中的流水线进行重构使其更接近 Knative 的 CI/CD 流水线风格。这意味着除了编译和打包代码外,Knative 中的构建还可以轻松地运行测试并发布这些结果。请密切关注 Knative 的未来版本,了解这一变化。

Service Account(服务账户)

在开始配置构建之前会面临一个亟待解决的问题:如何在构建时获得需要验证的服务?如何从私有的 Git 仓库拉取代码或者如何把容器镜像推送到 Docker Hub 中?为此,你可以利用两个 Kubernetes 原生组件的组合:SecretService Account 。Secret 可以让您安全地存储这些经过身份验证的请求所需的凭据,Service Account 可以让您灵活地为多个构建提供和维护凭据,而无需每次构建新应用程序时手动配置它们。

例 3-1 中,首先创建一个 Secret ,命名为 dockerhub-account,里面包含需要使用的凭据。当然,可以像应用其他 YAML 一样应用它,如例 3-2 所示。

例 3-1. knative-build-demo/secret.yaml

  1. apiVersion: v1
  2. kind: Secret
  3. metadata:
  4. name: dockerhub-account
  5. annotations:
  6. build.knative.dev/docker-0: https://index.docker.io/v1/
  7. type: kubernetes.io/basic-auth
  8. data:
  9. # 'echo -n "username" | base64'
  10. username: dXNlcm5hbWUK
  11. # 'echo -n "password" | base64'
  12. password: cGFzc3dvcmQK

例 3-2. kubectl apply

  1. kubectl apply -f knative-build-demo/secret.yaml

首先要注意的是,usernamepassword 在传递给 Kubernetes 时都是 base64 编码的。还应注意到,使用 basic-auth 根据 Docker Hub 进行身份验证,这意味着将使用用户名和密码进行身份验证,而不是类似于 access token(访问令牌)的东西。此外,Knative 还附带了开箱即用的 ssh-auth,这允许使用 SSH 私钥从私有 Git 存储库中拉取代码。

除了将 Secret 命名为 dockerhub-account 之外,还对 Secret 进行了注解。Annotation(注解)是说明连接到特定主机时使用哪些凭据的一种方式。在例 3-3 中,定义了连接到 Docker Hub 时使用的基于身份的验证凭证集。

我的凭据安全吗?

使用 base64 编码对凭证进行编码不是为了安全性,而是为了可靠地将这些字符串传输到 Kubernetes 。在后端,Kubernetes 提供了关于如何加密 Secret 的更多选项。有关加密 Secret 的详细资料,请参考 Kubernetes 文档

一旦创建了名为 dockerhub-account 的 Secret ,接下来必须创建要运行应用程序的 Service Account ,以便它能够访问 Kubernetes 中的凭据。配置很简单,如例 3-3 所示。

Example 3-3. knative-build-demo/serviceaccount.yaml

  1. apiVersion: v1
  2. kind: ServiceAccount
  3. metadata:
  4. name: build-bot
  5. secrets:
  6. - name: dockerhub-account

例中创建了一个名为 build-bot 的 ServiceAccount ,允许它访问 dockerhub-account Secret 。在例中当推送容器镜像时,Knative 使用这些凭证对 Docker Hub 进行身份验证。

Build Resource(构建资源)

首先从 Hello World 应用程序开始。这是一个简单的 Go 应用程序,它监听端口 8080 并以 “Hello from Knative!” 作为 HTTP GET 请求的响应。代码如例 3-4 所示。

例 3-4. knative-helloworld/app.go

  1. package main
  2. import (
  3. "fmt"
  4. "log"
  5. "net/http"
  6. )
  7. func handlePost(rw http.ResponseWriter, req *http.Request) {
  8. fmt.Fprintf(rw, "%s", "Hello from Knative!")
  9. }
  10. func main() {
  11. log.Print("Starting server on port 8080...")
  12. http.HandleFunc("/", handlePost)
  13. log.Fatal(http.ListenAndServe(":8080", nil))
  14. }

然后编写一个 Dockerfile 来构建代码和容器,如例 3-5 所示。

例 3-5. knative-helloworld/Dockerfile

  1. FROM golang
  2. ADD . /knative-build-demo
  3. WORKDIR /knative-build-demo
  4. RUN go build
  5. ENTRYPOINT ./knative-build-demo
  6. EXPOSE 8080

在前面的第 2 章中,您已经在本地构建了容器并手动将其推送到容器镜像库。然而,Knative 为在 Kubernetes 集群中使用 Build 来完成这些步骤提供了一种更好的方式。与 Configuration (配置)和 Route(路由)一样,Build 也可以简单地作为 Kubernetes 自定义资源(CRD)来通过 YAML 定义的方式实现。在深入研究每个组件之前,先来看一看例 3-6 ,看看 Build 的配置是什么样的。

例 3-6. knative-build-demo/service.yaml

  1. apiVersion: serving.knative.dev/v1alpha1
  2. kind: Service
  3. metadata:
  4. name: knative-build-demo
  5. namespace: default
  6. spec:
  7. runLatest:
  8. configuration:
  9. build:
  10. serviceAccountName: build-bot
  11. source:
  12. git:
  13. url: https://github.com/gswk/knative-helloworld.git
  14. revision: master
  15. template:
  16. name: kaniko
  17. arguments:
  18. - name: IMAGE
  19. value: docker.io/gswk/knative-build-demo:latest
  20. revisionTemplate:
  21. spec:
  22. container:
  23. image: docker.io/gswk/knative-build-demo:latest

在构建步骤之前,您还会在源代码部分看到源码存放位置的定义。目前,Knative 发布了三个代码源选项:

  • git:Git 仓库,可以选择使用参数来定义分支、标记或提交 SHA 。

  • gcs:位于谷歌云存储中的存档文件。

  • 自定义:任意容器镜像仓库。这允许用户编写自己的源代码,只要将源代码放在 /workspace 目录中即可。

只需要安装一个额外的组件,即 Build Template(构建模板)。将会在 “Build template” 一节中向你更深入地介绍这些内容,但是现在,先将继续使用在 YAML 中定义的方式,在本例中是 Kaniko Build Template 如例 3-7 所示。

例 3-7. 安装 Kaniko Build Template

  1. kubectl apply -f https://
  2. raw.githubusercontent.com/knative/build-templates/master/kaniko/kaniko.yaml

通过应用模板,可以像在 Serving 例中那样部署服务,配置如例 3-8 所示。

例 3-8. 部署应用程序

  1. kubectl apply -f knative-build-demo/service.yaml

然后,该构建将运行以下步骤:

  1. gswk/knative-helloworld 的 GitHub repo 中拉取代码。
  2. 在 repo 中使用 Kaniko Build Template(下一节将详细描述)。
  3. 使用前面设置的 “build-bot” Service Account 将容器推送到 DockerHub 的 gswk/knative-build-demo 仓库。
  4. 使用新构建的容器部署应用程序。

Build Template(构建模板)

例 3-6 中,使用了一个 Build Template ,但还从未真正讲解过 Build Template 是什么和怎样运行的。简单来说,Build Template 是可共享的、封装的、参数化的构建步骤集合。目前,Knative 已经支持多个 Build Template ,包括:

  • Kaniko

在运行的容器中构建容器镜像,而不依赖于运行 Docker daemon 。

  • Jib

为 Java 应用程序构建容器镜像。

  • Buildpack

自动检测应用程序的运行时,并建立一个容器镜像使用 Cloud Foundry Buildpack。

虽然这并不是可用模板的完整列表,但是可以轻松地集成 Knative 社区开发的新模板。安装 Build Template 就像应用 YAML 文件安装 Service(服务)、Route(路由)或 Build configuration(构建配置)一样简单:

  1. kubectl apply -f https://raw.githubusercontent.com/knative/
  2. build-templates/master/kaniko/kaniko.yaml

然后可以像其他配置一样应用例 3-6 来部署应用程序,同时向它发送请求,就像在第 2 章中所做的那样:

  1. kubectl apply -f knative-build-demo/service.yml
  2. $ curl -H "Host: knative-build-demo.default.example.com"
  3. http://$KNATIVE_INGRESS

例 3-9 中继续使用 Kaniko 作为参考来进一步观察 Build Template 。

例 3-9. https://github.com/knative/build-templates/blob/master/kaniko/kaniko.yaml

  1. apiVersion: build.knative.dev/v1alpha1
  2. kind: BuildTemplate
  3. metadata:
  4. name: kaniko
  5. spec:
  6. parameters:
  7. - name: IMAGE
  8. description: The name of the image to push
  9. - name: DOCKERFILE
  10. description: Path to the Dockerfile to build.
  11. default: /workspace/Dockerfile
  12. steps:
  13. - name: build-and-push
  14. image: gcr.io/kaniko-project/executor
  15. args:
  16. - --dockerfile=${DOCKERFILE}
  17. - --destination=${IMAGE}

Build Template 的 steps 部分具有与 Build 完全相同的语法,只是使用命名变量进行模板化。实际上,除了用变量替换路径之外,steps 部分看起来非常类似于例 3-6 的模板部分。parameters 部分在 Build Template 所期望的参数周围放置了一些结构。Kaniko Build Template 需要一个定义在何处推送容器镜像的 IMAGE 参数,但是有一个可选的 DOCKERFILE 参数,如果没有定义该参数,则提供一个默认值。

结论

Knative 中的 Build 在部署应用程序时去掉了许多手动步骤。此外,Build Template 提供了一些构建代码和去掉手动管理组件数量的好方法。随着时间的推移,可能会有越来越多的 Build Template 被构建并与 Knative 社区分享,这可能是最值得关注的事情之一。

我们已经花了很多时间来构建和运行应用程序,但是 Serverless 的最大承诺之一是,它可以使您的服务轻松地连接到事件源。在下一章中,将研究 Knative 的 Eventing(事件)组件以及开箱即用的所有可用事件源。