Knative:代码精简之道

本文涉及的产品
容器镜像服务 ACR,镜像仓库100个 不限时长
简介: 本文译自:https://content.pivotal.io/blog/knative-whittling-down-the-code 转载自:http://www.servicemesher.com/blog/knative-whittling-down-the-code/ [**编者案**] > Knative 作为 Google 发起开源的 serverless 项目,给我们

本文译自:https://content.pivotal.io/blog/knative-whittling-down-the-code
转载自:http://www.servicemesher.com/blog/knative-whittling-down-the-code/

[编者案]

Knative 作为 Google 发起开源的 serverless 项目,给我们提供了一套简单易用的 serverless 开源解决方案。本文作者直观地向我们展示了如何使用Knative来一步一步逐渐精简我们的代码,来更加简单容易的开发云原生应用。作者使用实例来逐步向我们讲述如何使用 Knative 提供的 Build、Serving 和 Eventing 三大组件来发挥威力,逐渐精简代码。如果您对 Knative 有兴趣,本文对于你通过 Knative 实践 serverless 一定会有所启发,希望您能喜欢。

对我来说,2018年最好的开源项目是Knative,这是一个建立在Kubernetes之上的serverless平台。不仅是为了serverless平台本身,也是为了它所倡导的整个开发范式。事件驱动开发并不新鲜,但Knative为围绕事件构建生态系统奠定了基础。

如果您不熟悉Knative,那么您读到的任何文档都将它分为三大组件:

  • 构建(Build) —— 我如何构建代码和打包代码?
  • 服务(Serving) —— 我的代码如何为请求提供服务?它是如何伸缩的?
  • 事件(Eventing) —— 我的代码如何被各种事件触发?

事实上这并不是一篇“Knative入门”的文章(在不久的将来会有更多关于这方面的内容),但是我最近一直在思考的是,随着开发人员越来越多地利用Knative提供的功能,他们如何减少自己需要编写的代码。这是最近Twitter上一个特别热门的话题,尤其是在KubeCon时代。我注意到的一个常见问题是,“如果您正在编写Dockerfile,它真的是一个serverless的平台吗?” 但是,其他人认为将代码打包为容器可能是最合理的解决方案,因为它是可移植的、全面的,并且具有所有依赖项。不乏强烈持有这种观点的人们,他们非常渴望争辩。

与其火上浇油,不如让我们看看Knative给开发人员提供了哪些选项来逐渐减少我们编写的代码量。我们将从最冗长的示例开始—我们自己构建的预构建容器(prebuilt container)。从这里开始,我们将逐渐减少基准代码量,减少构建自己的容器的需要,减少编写自己的Dockerfile的需要,最后减少编写自己的配置的需要。最重要的是,我们将看到Pivotal Function Service (PFS)的强大功能,以及它如何允许开发人员关注代码而不是配置。

我们将看到的所有代码都包含在两个git repos中:knative-hello-worldpfs-hello-world

预构建(Prebuilt)的Docker容器

我们将看到的第一个场景是为Knative提供一个预构建的容器镜像,该镜像已经上传到我们选择的容器镜像库。您将在Knative中看到的大多数Hello World示例都采用直接构建和管理容器的方式。这是有意义的,因为它很容易理解,而且没有引入很多新概念,这是一个很好的起点。这个概念非常简单直接:传给Knative一个暴露端口的容器,它将处理剩余的所有事情。它不关心你的代码是用GoRuby还是Java写的;它会接收传入的请求并将它们发送到你的应用程序。

让我们从一个使用Express web框架基于node.js实现的 hello world应用程序开始。

const express = require("express");
const bodyParser = require('body-parser')

const app = express();
app.use(bodyParser.text({type: "*/*"}));

app.post("/", function(req, res) {
 res.send("Hello, " + req.body + "!");
});

const port = process.env.PORT || 8080;
app.listen(port, function() {
 console.log("Server started on port", port);
});

是不是漂亮且简洁。这段代码将启动一个web服务器,监听端口8080(除非端口已被占用),并通过返回Hello来响应HTTP POST请求。当然,还需要package.json文件,它定义了一些东西(如何启动应用程序,依赖关系等),但这有点超出了我们所看到的范围。另一部分是Dockerfile,它描述如何将所有内容打包到一个容器中。

FROM node:10.15.1-stretch-slim

WORKDIR /usr/src/app
COPY . .
RUN npm install

ENV PORT 8080
EXPOSE $PORT

ENTRYPOINT ["npm", "start"]

这里也没什么好惊讶的。我们将我们的镜像建立在官方node.js镜像的基础之上,将我们的代码复制到容器中并安装依赖项,然后告诉它如何运行我们的应用程序。剩下的就是将其上传到Docker Hub。

$ docker build . -t brianmmcclain/knative-hello-world:prebuilt

$ docker push brianmmcclain/knative-hello-world:prebuilt

如果您曾经在类似于Kubernetes的应用程序上运行过,那么所有这些看起来应该非常熟悉。将代码放入容器中,让调度器处理以确保它处于正常状态。我们可以告诉Knative关于这个容器的信息,再加上一点metadata,它会处理所有的东西。随着请求数量的增长,它将扩展实例的数量,缩减到0,路由请求,连接事件——竭尽所能。我们真正需要告诉Knative的是调用我们的应用程序,运行它的名称空间,以及容器镜像的位置。

apiVersion: serving.knative.dev/v1alpha1
kind: Service
metadata:
 name: knative-hello-world-prebuilt
 namespace: default
spec:
 runLatest:
   configuration:
     revisionTemplate:
       spec:
         container:
           image: docker.io/brianmmcclain/knative-hello-world:prebuilt

$ kubectl apply -f 01-prebuilt.yaml

几分钟后,我们将看到一个新的pod运行起来,准备为请求服务,如果在一段时间内没有收到任何流量,Pod 数量将会缩减为0。我们可以POST一些数据,看看我们收到的响应。首先,让我们获取Kubernetes集群的Ingress IP,并将其分配给$SERVICE_IP变量:

$ export SERVICE_IP=`kubectl get svc istio-ingressgateway -n istio-system -o jsonpath="{.status.loadBalancer.ingress[*].ip}"`

然后使用IP向我们的服务发送请求,在我们的请求中设置HOST header:

$ curl -XPOST http://$SERVICE_IP -H "Host: knative-hello-world-prebuilt.default.example.com" -d "Prebuilt"

Hello, Prebuilt!

Kaniko容器构建器

上面介绍的一切可以很好的工作,但是我们甚至还没有开始接触Knative的“Build”部分。实际上,我们没有碰它,我们自己构建了这个容器。您可以在Knative文档中阅读所有关于构建以及它们如何工作的信息。总的来说,knative有一个名为“Build Templates”的概念,我喜欢这样描述他们:他们是关于如何从代码到容器的可共享逻辑。这些构建模板中的大多数模板都能够完成我们构建容器和上传镜像的需要。这些模板中最基本的可能是Kaniko Build Templates

顾名思义,它基于谷歌的Kaniko, Kaniko是在容器中构建容器镜像的工具,不依赖于正在运行的Docker守护进程。向Kaniko容器镜像提供Dockerfile和一个上传结果的位置,它就可以据此构建镜像。我们无需拉取代码、在本地构建镜像、上传到 Docker Hub,然后从 Knative 拉取镜像,我们可以让Knative为我们做这些,只需要多做一点配置。

但是,在执行此操作之前,我们需要告诉Knative如何根据容器注册中心进行身份验证。为此,我们首先需要在Kubernetes中创建一个Secret,这样我们就可以对Docker Hub进行身份验证,然后创建一个服务帐户来使用该Secret并运行构建。让我们从创造Secret开始:

apiVersion: v1
kind: Secret
metadata:
 name: dockerhub-account
 annotations:
   build.knative.dev/docker-0: https://index.docker.io/v1/
type: kubernetes.io/basic-auth
data:
 # 'echo -n "username" | base64'
 username: dXNlcm5hbWUK
 # 'echo -n "password" | base64'
 password: cGFzc3dvcmQK

uesrname和password作为base64编码的字符串发送给Kubernetes。(对于有安全意识的读者来说,这是一种传输机制,而不是安全机制。有关Kubernetes如何存储Secret的更多信息,请在有空时查看关于on encrypting secret data at rest)。提交之后,我们将创建一个名为build-bot的服务帐户,并告诉它在推送到Docker Hub时使用这个Secret:

apiVersion: v1
kind: ServiceAccount
metadata:
  name: build-bot
secrets:
- name: dockerhub-account

有关身份验证的更多信息,请确保查看knative文档中的how-authentication-work -in- knative文档。

构建模板(Build Templates)的好处是任何人都可以创建并与社区共享它们。我们可以告诉Knative通过传递一些YAML来安装这个构建模板:

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

然后我们需要在我们的应用YAML中添加更多:

apiVersion: serving.knative.dev/v1alpha1
kind: Service
metadata:
 name: knative-hello-world-kaniko
 namespace: default
spec:
 runLatest:
   configuration:
     build:
       serviceAccountName: build-bot
       source:
         git:
           url: https://github.com/BrianMMcClain/knative-hello-world.git
           revision: master
       template:
         name: kaniko
         arguments:
         - name: IMAGE
           value: docker.io/brianmmcclain/knative-hello-world:kaniko
     revisionTemplate:
       spec:
         container:
           image: docker.io/brianmmcclain/knative-hello-world:kaniko

虽然直接比较有点困难,但是我们实际上只向YAML中添加了一个部分—“Build”部分。我们添加的内容可能看起来很多,但如果你花时间逐条查看的话,它实际上并不坏:

  • serviceAccountName:在Knative auth文档中,它遍历了设置服务帐户的过程。所有这些都是通过设置一个Kubernetes Secret来验证我们的容器镜像库,然后将其封装到一个服务帐户中。
  • source:代码所在的位置。例如,git repository。
  • template:要使用哪个Build Template。在本例中,我们将使用Kaniko Build Template。

让我们向应用程序的新版本发送一个请求,以确保一切正常:

$ curl -XPOST http://$SERVICE_IP -H "Host: knative-hello-world-kaniko.default.example.com" -d "Kaniko"

Hello, Kaniko!

尽管这可能是一种更预先的配置,但权衡的结果是,现在我们不必每次更新代码时都构建或推送我们自己的容器镜像。相反,Knative将为我们处理这些步骤!

Buildpack Build Template

所以,这个博客的重点是我们如何编写更少的代码。虽然我们已经使用Kaniko Build Template删除了部署的一个操作组件,但是我们仍然在代码之上维护一个Dockerfile和一个配置文件。但是如果我们可以抛弃Dockerfile呢?

如果您具有使用PaaS的习惯,那么您可能已经习惯了简单地向上推代码,然后发生了一些神奇的事情,然后您就有了一个正常工作的应用程序。你不在乎这是怎么做到的。我们所知道的是,您不必编写Dockerfile来将其放入容器中,而且它可以正常工作。在Cloud Foundry,这是通过名为buildpacks的框架实现的,该框架为应用程序提供运行时和依赖项。

实际上给我们带来两大好处。不仅有一个使用buildpacks的Build Template,还有一个用于Node.js的buildpacks。就像Kaniko Build Template一样,我们将在Knative中安装buildpack Build Template:

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

现在,让我们看看使用Buildpack Build Template的YAML是什么样子的:

apiVersion: serving.knative.dev/v1alpha1
kind: Service
metadata:
 name: knative-hello-world-buildpack
 namespace: default
spec:
 runLatest:
   configuration:
     build:
       serviceAccountName: build-bot
       source:
         git:
           url: https://github.com/BrianMMcClain/knative-hello-world.git
           revision: master
       template:
         name: buildpack
         arguments:
         - name: IMAGE
           value: docker.io/brianmmcclain/knative-hello-world:buildpack
     revisionTemplate:
       spec:
         container:
           image: docker.io/brianmmcclain/knative-hello-world:buildpack

这与我们使用Kaniko Build Template时非常相似。实际上,我们来做个比较:

<   name: knative-hello-world-kaniko
>   name: knative-hello-world-buildpack
---
<           name: kaniko
>           name: buildpack
---
<             value: docker.io/brianmmcclain/knative-hello-world:kaniko
>             value: docker.io/brianmmcclain/knative-hello-world:buildpack
---
<             image: docker.io/brianmmcclain/knative-hello-world:kaniko
>             image: docker.io/brianmmcclain/knative-hello-world:buildpack

那么区别是什么呢?首先,我们可以完全抛弃Dockerfile。Buildpack Build Template将分析我们的代码,确定它是一个Node.js应用程序,并通过下载Node.js运行时和依赖项为我们构建一个容器。虽然Kaniko Build Template将我们从Docker容器生命周期的管理工作中解放出来,但Buildpack Build Template更进一步,完全不需要管理Dockerfile了。

$ kubectl apply -f 03-buildpack.yaml
service.serving.knative.dev "knative-hello-world-buildpack" configured

$ curl -XPOST http://$SERVICE_IP -H "Host: knative-hello-world-buildpack.default.example.com" -d "Buildpacks"
Hello, Buildpacks!

Pivotal Function Service

让我们检查一下代码库的剩余部分。我们有响应POST请求的Node.js代码,使用Express框架设置web服务器。package.json文件定义了我们的依赖项。虽然这不是真正的代码,但我们也在维护定义Knative服务的YAML。不过,我们可以继续削减。

进入Pivotal Function Service (PFS),这是构建在Knative之上的Pivotal的商业serverless产品。PFS旨在消除管理代码以外的任何东西的需要。这包括我们在代码库中管理自己的web服务器。使用PFS,我们的代码如下:

module.exports = x => "Hello, " + x + "!";

就是这样,没有Dockerfile,没有YAML。只要一行代码。当然,像所有优秀的节点开发人员一样,我们仍然需要有自己的package.json文件,尽管它不依赖于Express。一旦部署完毕,riff将使用这一行代码并将其封装在自己的托管容器镜像中。它将把它与调用代码所需的逻辑打包在一起,并像运行在Knative上的任何其他函数一样提供服务。

PFS CLI使得部署我们的函数变得非常容易。我们将给函数命名为pfs-hello-world,为它提供到代码所在的GitHub存储库的链接,并告诉它将生成的容器映像上传到我们的私有容器镜像库中。

pfs function create pfs-hello-world --git-repo https://github.com/BrianMMcClain/pfs-hello-world.git --image $REGISTRY/$REGISTRY_USER/pfs-hello-world --verbose

几分钟后,我们将看到我们的函数进入运行状态,我们可以像任何其他Knative函数一样,向其发送请求:

$ curl -XPOST http://$SERVICE_IP -H "Host: pfs-hello-world.default.example.com" -H "Content-Type: text/plain" -d "PFS"

Hello, PFS!

或者,更简单的是,使用riff CLI来调用我们的函数:

$ pfs service invoke pfs-hello-world --text -- -d "PFS CLI"

Hello, PFS CLI!

我们终于实现了目标! 由23行YAML、14行代码和一个10行Dockerfile组成的简化代码行。

是不是一下子对PFS感兴趣了呢?要申请提前访问,只需填写这张快速表格!

接下来工作?

越来越多的构建模板。这是Knative最令人兴奋的特性之一,因为它有很大的潜力为各种场景打开一个自定义构建模板的社区。现在,您可以为JibBuildKit等工具使用模板。已经有一个pull request来更新Buildpack构建模板,以支持Cloud Native Buildpacks

2018年是一个激动人心的开始,但是更让我兴奋的是看到Knative社区在2019年的增长。我们当然可以期望从社区获得更多的构建模板和更多的事件源。不仅如此,我们还可以期望与现有技术更好地集成,例如Spring,它已经对此功能提供了强大的支持

如果您希望开始使用Knative进行开发,那么Bryan Friedman和我将在2月21日主持一个很棒的网络研讨会,讨论developing serverless applications on Kubernetes with Knative。我们将深入研究Knative的三个组件,它们是如何工作的,以及作为开发人员如何利用它们来编写更好的代码。

如果你4月2-4日在费城,请加入我们的CF Summit! Bryan和我将讨论the way to build serverless on Knative,或者如果您看到我们,就说声hi!

相关实践学习
通过workbench远程登录ECS,快速搭建Docker环境
本教程指导用户体验通过workbench远程登录ECS,完成搭建Docker环境的快速搭建,并使用Docker部署一个Nginx服务。
深入解析Docker容器化技术
Docker是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux机器上,也可以实现虚拟化,容器是完全使用沙箱机制,相互之间不会有任何接口。Docker是世界领先的软件容器平台。开发人员利用Docker可以消除协作编码时“在我的机器上可正常工作”的问题。运维人员利用Docker可以在隔离容器中并行运行和管理应用,获得更好的计算密度。企业利用Docker可以构建敏捷的软件交付管道,以更快的速度、更高的安全性和可靠的信誉为Linux和Windows Server应用发布新功能。 在本套课程中,我们将全面的讲解Docker技术栈,从环境安装到容器、镜像操作以及生产环境如何部署开发的微服务应用。本课程由黑马程序员提供。 &nbsp; &nbsp; 相关的阿里云产品:容器服务 ACK 容器服务 Kubernetes 版(简称 ACK)提供高性能可伸缩的容器应用管理能力,支持企业级容器化应用的全生命周期管理。整合阿里云虚拟化、存储、网络和安全能力,打造云端最佳容器化应用运行环境。 了解产品详情: https://www.aliyun.com/product/kubernetes
目录
相关文章
|
监控 Devops 中间件
阿里巴巴DevOps实践指南(十四)| 测试环境与路由
在阿里巴巴内部,随着业务规模和技术栈的拓展和更新,业务侧对测试环境的使用也逐步打破原固有模式,快速向多场景、多样化、多职能方向发展,如何能够跟上业务发展速度,及时满足业务侧对测试环境新场景的诉求,基于环境和路由模型的测试环境解决方案是解决问题的关键。
阿里巴巴DevOps实践指南(十四)| 测试环境与路由
|
测试技术 数据库 安全
带你读《C++代码整洁之道:C++17 可持续软件开发模式实践》之二:构建安全体系
如果想用C++语言编写出易维护的、扩展性良好的以及生命力强的软件,那么,对于所有的软件开发人员、软件设计人员、对现代C++代码感兴趣或想降低开发成本的项目领导者来说,本书都是必需品。如果你想自学编写整洁的C++代码,那么本书也是你需要的。本书旨在通过一些示例帮助各个技术层次的开发人员编写出易懂的、灵活的、可维护的和高效的C++代码。即使你是一名资深的开发工程师,在本书中也可以找到有价值的知识点。
|
2月前
|
小程序 JavaScript 前端开发
【经验分享】如何实现小程序代码热更新| 江海计划
【经验分享】如何实现小程序代码热更新| 江海计划
43 1
|
11月前
|
存储 机器学习/深度学习 消息中间件
「无服务器架构」动手操作Knative -第二部分
「无服务器架构」动手操作Knative -第二部分
|
11月前
|
Kubernetes Serverless C#
「无服务器架构」动手操作Knative -第1部分
「无服务器架构」动手操作Knative -第1部分
|
测试技术 Python
【第五篇-完结篇】XiaoZaiMultiAutoAiDevices之改造扩展
在前面系列文章中有讲到,使用configparser,ini格式的文件作为配置文件,在新增或者删除其中的值时,会丢失所有注释,所以在框架源码注释中我有写到,如果对这方面比较介意或者是有需求的话,可以进行更改配置文件。
106 0
|
Kubernetes Cloud Native Dubbo
Higress 开源后,我们整理了开发者最关心的 15 个问题
云原生网关 Higress 开源后,引起了开发者们的热烈讨论,我们整理了大家在 GitHub、钉群、微信群讨论的问题,并将回答汇总如下,方便各位更准确的读懂 Higress,也非常欢迎您和我们一起共建、定义 Higress。
284 1
Higress 开源后,我们整理了开发者最关心的 15 个问题
|
Kubernetes Cloud Native 安全
Higress 开源后,我们整理了开发者最关心的15个问题
云原生架构下,网关承载着流量管理、服务调用、安全管理等多重职能,在稳定性、性能、安全性、易用性上存在着更高的要求。在 CNCF Landscpae 编排和管理的 API Gateway 领域中,已经有不少开源的网关选择,开发者们也有着不小的选型诉求。
Higress 开源后,我们整理了开发者最关心的15个问题
|
JSON Kubernetes Cloud Native
【云原生Kubernetes系列第七篇】一文掌握k8s之YAML文件(少攀谈,多沉潜,清醒而独立)(二)
【云原生Kubernetes系列第七篇】一文掌握k8s之YAML文件(少攀谈,多沉潜,清醒而独立)(二)
196 0
【云原生Kubernetes系列第七篇】一文掌握k8s之YAML文件(少攀谈,多沉潜,清醒而独立)(二)
|
XML JSON Kubernetes
【云原生Kubernetes系列第七篇】一文掌握k8s之YAML文件(少攀谈,多沉潜,清醒而独立)(一)
【云原生Kubernetes系列第七篇】一文掌握k8s之YAML文件(少攀谈,多沉潜,清醒而独立)(一)
172 0