Kubernetes无服务器应用手册全绝不原创的飞龙

Kubernetes是近年来突出的技术之一;它已被所有主要公共云提供商采用为容器集群和编排平台,并迅速成为行业标准。

再加上Kubernetes是开源的,您就拥有了在多个公共和私有提供商上托管自己的平台即服务或PaaS的完美基础;您甚至可以在笔记本电脑上运行它,并且由于其设计,您将在所有平台上获得一致的体验。

它的设计也使其成为运行无服务器函数的理想平台。在本书中,我们将研究几个可以部署在Kubernetes上并与之集成的平台,这意味着我们不仅拥有PaaS,还有一个强大的FaaS平台在您的Kubernetes环境中运行。

本书主要面向运维工程师、云架构师和开发人员,他们希望在Kubernetes集群上托管他们的无服务器函数。

第一章,无服务器景观,解释了什么是无服务器。此外,我们将在公共云上使用AWSLambda和AzureFunctions来运行无服务器函数,获得一些实际经验。

第二章,Kubernetes简介,讨论了Kubernetes是什么,它解决了什么问题,并且还回顾了它的背景,从谷歌的内部工程工具到开源强大工具。

第三章,在本地安装Kubernetes,解释了如何通过实践经验来使用Kubernetes。我们将使用Minikube安装本地单节点Kubernetes集群,并使用命令行客户端与其交互。

第四章,介绍Kubeless函数,解释了在本地运行Kubernetes后如何使用Kubeless启动第一个无服务器函数。

第五章,使用Funktion进行无服务器应用,解释了使用Funktion来调用无服务器函数的一种略有不同的方法。

第六章,在云中安装Kubernetes,介绍了在DigitalOcean、AWS、GoogleCloud和MicrosoftAzure上启动集群的过程,以及在本地使用Kubernetes进行一些实践经验后的操作。

第七章,ApacheOpenWhisk和Kubernetes,解释了如何在我们新推出的云Kubernetes集群上启动、配置和使用最初由IBM开发的无服务器平台ApacheOpenWhisk。

第八章,使用Fission启动应用程序,介绍了部署Fission的过程,这是Kubernetes的流行无服务器框架,并附带了一些示例函数。

第九章,了解OpenFaaS,介绍了OpenFaaS。虽然它首先是一个用于Docker的函数即服务框架,但也可以部署在Kubernetes之上。

第十章,无服务器考虑因素,讨论了安全最佳实践以及如何监视您的Kubernetes集群。

第十一章,运行无服务器工作负载,解释了Kubernetes生态系统的快速发展以及您如何跟上。我们还讨论了您应该使用哪些工具,以及为什么您希望将无服务器函数部署在Kubernetes上。

操作系统:

macOSHighSierra

Ubuntu17.04

Windows10专业版

软件:

在本书中,我们将安装几个命令行工具;每个工具都将在各章节中提供安装说明和其要求的详细信息。请注意,虽然提供了Windows系统的说明,但我们将主要使用最初设计为在Linux/Unix系统上运行的工具,如Ubuntu17.04和macOSHighSierra,并且本书将偏向这些系统。虽然在撰写时已尽最大努力验证这些工具在基于Windows的系统上的运行情况,但由于一些工具是实验性构建的,我们无法保证它们在更新的系统上仍然能够正常工作,因此,我建议使用Linux或Unix系统。

硬件:

Windows10专业版和Ubuntu17.04系统要求:

使用2011年或之后推出的处理器(CPU),核心速度为1.3GHz或更快,除了基于Llano和Bobcat微架构的英特尔Atom处理器或AMD处理器

最低4GBRAM,建议使用8GBRAM或更多

AppleMac系统要求:

iMac:2009年底或更新

MacBook/MacBook(Retina):2009年底或更新

MacBookPro:2010年中期或更新

MacBookAir:2010年末或更新版本

Macmini:2010年中期或更新版本

MacPro:2010年中期或更新版本

至少可以访问以下公共云服务之一:

您可以按照以下步骤下载代码文件:

选择“支持”选项卡。

单击“代码下载和勘误”。

在搜索框中输入书名,然后按照屏幕上的说明操作。

下载文件后,请确保使用最新版本的以下软件解压缩文件夹:

WinRAR/7-ZipforWindows

Zipeg/iZip/UnRarXforMac

7-Zip/PeaZipforLinux

本书中使用了许多文本约定。

CodeInText:指示文本中的代码词、数据库表名、文件夹名、文件名、文件扩展名、路径名、虚拟URL、用户输入和Twitter用户名。这是一个例子:“这包含一个名为index.html的单个文件。”

一段代码设置如下:

apiVersion:apps/v1beta1kind:Deploymentmetadata:name:cli-hello-worldlabels:app:nginx任何命令行输入或输出都将按照以下方式编写:

$brewcaskinstallminikube粗体:表示一个新术语,一个重要的词,或者你在屏幕上看到的词。例如,菜单或对话框中的单词会在文本中以这种方式出现。这是一个例子:“在页面底部,您将有一个按钮,可以让您为您的帐户创建访问令牌和访问令牌密钥。”

警告或重要提示会以这种方式出现。提示和技巧会以这种方式出现。

欢迎来到《用于无服务器应用的Kubernetes》的第一章。在本章中,我们将讨论以下内容:

我们所说的无服务器和函数作为服务是什么意思?

有哪些服务?

亚马逊网络服务的Lambda的一个例子。

AzureFunctions的一个例子

使用无服务器工具包

我们可以使用无服务器和函数作为服务解决什么问题?

我认为重要的是我们首先要解决房间里的大象,那就是无服务器这个术语。

当你对某人说无服务器时,他们首先得出的结论是你在没有任何服务器的情况下运行你的代码。

如果你使用我们将在本章后面讨论的公共云服务之一,这可能是一个相当合理的结论。然而,当在你自己的环境中运行时,你无法避免必须在某种服务器上运行。

在我们讨论无服务器和函数作为服务的含义之前,我们应该讨论我们是如何到达这里的。和我一起工作的人无疑会告诉你,我经常使用“宠物与牛群”这个类比,因为这是一个很容易解释现代云基础设施与更传统方法之间差异的方式。

我第一次接触“宠物与牛群”这个类比是在2012年,当时RandyBias发布了一份幻灯片。这张幻灯片是在RandyBias在云扩展会议上关于开放和可扩展云的架构的演讲中使用的。在演讲的最后,他介绍了宠物与牛群的概念,Randy将其归因于当时在微软担任工程师的BillBaker。

幻灯片主要讨论的是扩展而不是升级;让我们更详细地讨论一下,并讨论自五年前首次进行演示以来所做的一些补充。

我们像给宠物起名字一样给每台服务器起名字。例如,app-server01.domain.com和database-server01.domain.com。

当我们的宠物生病时,你会把它们带到兽医那里。这很像你作为系统管理员重新启动服务器,检查日志,并更换服务器的故障组件,以确保它正常运行。

牛更能代表你应该在公共云中运行的实例类型,比如亚马逊网络服务(AWS)或微软Azure,在那里你启用了自动扩展。

你的牛群里有很多牛,你不给它们起名字;相反,它们被编号和标记,这样你就可以追踪它们。在你的实例集群中,你也可能有太多实例需要命名,所以像牛一样,你给它们编号和标记。例如,一个实例可以被称为ip123067099123.domain.com,并标记为app-server。

当你的牛群中的一头生病时,你会射杀它,如果你的牛群需要,你会替换它。同样地,如果你集群中的一个实例开始出现问题,它会被自动终止并替换为一个副本。

你的牛群生活在一个牧场里,你从远处观察它,就像你不监视集群中的单个实例一样;相反,你监视集群的整体健康状况。如果你的集群需要额外的资源,你会启动更多的实例,当你不再需要资源时,实例会被自动终止,使你回到期望的状态。

鸡比牛更有效率;你可以把更多的鸡放在你的牛群所占用的同样空间里。同样地,你可以在你的集群中放更多的容器,因为你可以在每个实例上启动多个容器。

每只鸡在饲养时需要的资源比你的牧群成员少。同样,容器比实例需要的资源更少,它们只需要几秒钟就可以启动,并且可以配置为消耗更少的CPU和RAM。

昆虫的寿命远低于鸡;事实上,一些昆虫只有几小时的寿命。这符合无服务器和函数即服务的特点,因为它们的寿命只有几秒钟。

在本章的后面,我们将看一下来自AWS和微软Azure的公共云服务,这些服务的计费是以毫秒为单位,而不是小时或分钟。

每片雪花都是独一无二的,无法复制。就像办公室里那台由几年前离开的那个人建造而没有记录的服务器一样。

一旦我解释了宠物、牛群、鸡、昆虫和雪花,我总结道:

“那些拥有宠物的组织正在慢慢将他们的基础设施变得更像牛。那些已经将他们的基础设施运行为牛的人正在向鸡转变,以充分利用他们的资源。那些运行鸡的人将会考虑将他们的应用程序转变为昆虫,通过将他们的应用程序完全解耦成可单独执行的组件来完成。”

最后我这样说:

“没有人想要或者应该运行雪花。”

在这本书中,我们将讨论昆虫,我会假设你对覆盖牛和鸡的服务和概念有一些了解。

如前所述,使用“无服务器”这个词会给人一种不需要服务器的印象。无服务器是用来描述一种执行模型的术语。

在执行这个模型时,作为最终用户的你不需要担心你的代码在哪台服务器上执行,因为所有的决策都是由抽象出来的,与你无关——这并不意味着你真的不需要任何服务器。

现在有一些公共云服务提供了如此多的服务器管理抽象,以至于可以编写一个不依赖于任何用户部署服务的应用程序,并且云提供商将管理执行代码所需的计算资源。

通常,这些服务,我们将在下一节中看到,是按每秒执行代码所使用的资源计费的。

那么这个解释如何与昆虫类比呢?

假设我有一个网站,允许用户上传照片。一旦照片上传,它们就会被裁剪,创建几种不同的尺寸,用于在网站上显示缩略图和移动优化版本。

在宠物和牛的世界中,这将由一个24/7开机等待用户上传图像的服务器来处理。现在这台服务器可能不只是执行这一个功能;然而,如果几个用户都决定上传十几张照片,那么这将在执行该功能的服务器上引起负载问题。

我们可以采用鸡的方法,跨多台主机运行多个容器来分发负载。然而,这些容器很可能也会全天候运行;它们将会监视上传以进行处理。这种方法可以让我们水平扩展容器的数量来处理请求的激增。

使用昆虫的方法,我们根本不需要运行任何服务。相反,函数应该由上传过程触发。一旦触发,函数将运行,保存处理过的图像,然后终止。作为开发人员,你不需要关心服务是如何被调用或在哪里执行的,只要最终得到处理过的图像即可。

在我们深入探讨本书的核心主题并开始使用Kubernetes之前,我们应该看看其他选择;毕竟,我们将在接下来的章节中涵盖的服务几乎都是基于这些服务的。

三大主要的公共云提供商都提供无服务器服务:

这些服务都支持几种不同的代码框架。对于本书的目的,我们不会过多地研究代码框架,因为使用这些框架是一个基于你的代码的设计决策。

我们将研究这两种服务,AWS的Lambda和微软Azure的Functions。

我们要看的第一个服务是AWS的AWSLambda。该服务的标语非常简单:

“无需考虑服务器即可运行代码。”

现在,那些之前使用过AWS的人可能会认为这个标语听起来很像AWS的弹性Beanstalk服务。该服务会检查你的代码库,然后以高度可扩展和冗余的配置部署它。通常,这是大多数人从宠物到牲畜的第一步,因为它抽象了AWS服务的配置,提供了可扩展性和高可用性。

在我们开始启动一个helloworld示例之前,我们将需要一个AWS账户和其命令行工具安装。

虽然单击“创建免费账户”,然后按照屏幕上的说明将为您提供12个月的免费访问多项服务,但您仍然需要提供信用卡或借记卡详细信息,并且可能会产生费用。

一旦您拥有AWS账户,您应该使用AWS身份和访问管理(IAM)服务创建一个用户。该用户可以拥有管理员权限,您应该使用该用户访问AWS控制台和API。

有关创建IAM用户的更多详细信息,请参阅以下页面:

不建议使用AWS根账户启动服务和访问API;如果凭据落入错误的手中,您可能会失去对账户的所有访问权限。使用IAM而不是您的根账户,并且您还应该使用多因素身份验证锁定根账户,这意味着您将始终可以访问您的AWS账户。

最后一个先决条件是您需要访问AWS命令行客户端,我将使用macOS,但该客户端也适用于Linux和Windows。有关如何安装和配置AWS命令行客户端的信息,请参阅:

在配置AWSCLI时,请确保将默认区域配置为您将在AWSWeb控制台中访问的区域,因为没有比在CLI中运行命令然后在Web控制台中看不到结果更令人困惑的事情了。

安装后,您可以通过运行以下命令来测试您是否可以从命令行客户端访问AWSLambda:

$awslambdalist-functions这应该返回一个空的函数列表,就像下面的截图中所示:

在AWS控制台中,单击屏幕左上角的“服务”菜单,然后通过使用过滤框或单击列表中的服务来选择Lambda。当您首次转到AWS控制台中的Lambda服务页面时,您将看到一个欢迎页面:

单击“创建函数”按钮将直接进入启动我们的第一个无服务器函数的过程。

创建函数有四个步骤;我们需要做的第一件事是选择一个蓝图:

对于基本的helloworld函数,我们将使用一个名为hello-world-python的预构建模板;将其输入到过滤器中,您将看到两个结果,一个是Python2.7,另一个使用Python3.6:

选择hello-world-python,然后单击“导出”将为您提供下载用于函数的代码的选项,该代码位于lambda_function.py文件中,以及Lambda在第3步中使用的模板。这可以在template.yaml文件中找到。

代码本身非常基本,就像你想象的那样。它除了返回传递给它的值之外什么也不做。如果您没有跟随,lambda_function.py文件的内容如下:

from__future__importprint_functionimportjsonprint('Loadingfunction')deflambda_handler(event,context):#print("Receivedevent:"+json.dumps(event,indent=2))print("value1="+event['key1'])print("value2="+event['key2'])print("value3="+event['key3'])returnevent['key1']#Echobackthefirstkeyvalue#raiseException('Somethingwentwrong')template.yaml文件包含以下内容:

AWSTemplateFormatVersion:'2010-09-09'Transform:'AWS::Serverless-2016-10-31'Description:AstarterAWSLambdafunction.Resources:helloworldpython:Type:'AWS::Serverless::Function'Properties:Handler:lambda_function.lambda_handlerRuntime:python2.7CodeUri:.Description:AstarterAWSLambdafunction.MemorySize:128Timeout:3Role:!''正如您所看到的,模板文件配置了Runtime和一些合理的MemorySize和Timeout值。

要继续到第2步,请单击函数名称,对我们来说是hello-world-python,您将进入页面,可以选择如何触发函数:

我们暂时不打算使用触发器,我们将在下一个启动的函数中更详细地了解这些内容;所以现在,请单击“下一步”。

第3步是我们配置函数的地方。这里有很多信息要输入,但幸运的是,我们需要输入的许多细节已经从我们之前查看的模板中预填充,如下截图所示:

以下列表显示了所有表单字段及其应输入的内容:

基本信息:

名称:myFirstFunction

描述:一个起始的AWSLambda函数

运行时:Python2.7

Lambda函数代码:

代码输入类型:这包含了函数的代码,无需编辑

启用加密助手:不选中

环境变量:留空

Lambda函数处理程序和角色:

处理程序:lambda_function.lambda_handler

角色:保持选择“从模板创建新角色”

角色名称:myFirstFunctionRole

策略模板:我们不需要为此函数使用策略模板,保持空白

将标签和高级设置保持默认值。输入前述信息后,单击“下一步”按钮,进入第4步,这是函数创建之前的最后一步。

查看页面上的详细信息。如果您确认所有信息都已正确输入,请单击页面底部的“创建函数”按钮;如果需要更改任何信息,请单击“上一步”按钮。

几秒钟后,您将收到一条消息,确认您的函数已创建:

在上述截图中,有一个“测试”按钮。单击此按钮将允许您调用函数。在这里,您可以自定义发送到函数的值。如下截图所示,我已更改了key1和key2的值:

编辑完输入后,点击“保存并测试”将存储您更新的输入,然后调用该函数:

点击执行结果消息中的“详细信息”将显示函数被调用的结果以及使用的资源:

STARTRequestId:36b2103a-90bc-11e7-a32a-171ef5562e33Version:$LATESTvalue1=helloworldvalue2=thisismyfirstserverlessfunctionvalue3=value3ENDRequestId:36b2103a-90bc-11e7-a32a-171ef5562e33具有36b2103a-90bc-11e7-a32a-171ef5562e33ID的请求的报告如下:

内存大小:128MB

最大内存使用:19MB

返回到命令行,再次运行以下命令会显示我们的函数现在已列出:

$awslambdalist-functions上述命令的输出如下:

我们也可以通过运行以下命令从命令行调用我们的函数:

$awslambdainvoke\--invocation-typeRequestResponse\--function-namemyFirstFunction\--log-typeTail\--payload'{"key1":"hello","key2":"world","key3":"again"}'\outputfile.txt如您从上述命令中所见,awslambdainvoke命令需要几个标志:

--invocation-type:有三种调用类型:

RequestResponse:这是默认选项;它发送请求,在我们的情况下在命令的--payload部分中定义。一旦请求被发出,客户端就会等待响应。

事件:这会发送请求并触发事件。客户端不等待响应,而是会收到一个事件ID。

DryRun:这会调用函数,但实际上不执行它——这在测试用于调用函数的详细信息是否具有正确的权限时非常有用。

--function-name:这是我们要调用的函数的名称。

--log-type:目前只有一个选项,Tail。这返回--payload的结果,这是我们要发送给函数的数据;通常这将是JSON。

outputfile.txt:命令的最后部分定义了我们要存储命令输出的位置;在我们的情况下,这是一个名为outputfile.txt的文件,它被存储在当前工作目录中。

在从命令行调用命令时,您应该会得到以下结果:

返回到AWS控制台并保持在myFirstFunction页面上,点击“监控”将呈现有关函数的一些基本统计信息:

单击CloudWatch中的查看日志将打开一个列出myFirstFunction日志流的新标签页。单击日志流的名称将带您到一个页面,该页面会显示每次函数被调用的结果,包括在AWS控制台中进行测试以及从命令行客户端进行调用。

监控页面和日志在调试Lambda函数时非常有用。

接下来,我们将看一下微软的无服务器服务AzureFunctions。微软将这项服务描述为:

"AzureFunctions是一个解决方案,可以轻松在云中运行小段代码或“函数”。您可以仅编写您需要解决的问题的代码,而不必担心整个应用程序或运行它的基础架构。"

与Lambda一样,您的Function可以通过多种方式被调用。在这个快速演示中,我们将部署一个通过HTTP请求调用的Function。

在撰写本文时,微软向所有新账户提供了200美元的Azure服务信用额度,就像AWS一样,有几项服务有免费套餐。

我们将使用基于Web的控制面板来创建我们的第一个Function应用程序。一旦您拥有了账户,您应该会看到类似以下页面:

如前面的屏幕截图所示,有相当多的选项。要开始创建您的第一个函数,您应该在左侧菜单顶部单击“+新建”。

从这里,您将进入Azure市场。单击计算,然后在特色市场项目列表中,您应该看到函数应用程序。单击此处,您将进入一个表单,询问您想要创建的函数的一些基本信息:

应用程序名称:随意命名;在我的案例中,我将其命名为russ-test-version。这必须是一个唯一的名称,如果您想要的应用程序名称已经被另一个用户使用,您将收到一条消息,告知您所选的应用程序名称不可用。

订阅:选择要在其中启动您的函数的Azure订阅。

资源组:在输入应用程序名称时,这将自动填充。

托管计划:将其保留为默认选项。

位置:选择离您最近的地区。

存储:这将根据您提供的应用程序名称自动填充,为了我们的目的,请保留选择“创建新”。

固定到仪表板:选中此项,因为这将使我们能够快速找到我们创建的函数。

如果您没有在您的帐户中跟随,我的完成表格看起来像下面的屏幕截图:

填写完表格后,单击表单底部的“创建”按钮,您将被带回到您的仪表板。您将收到一个通知,告知您的函数正在部署,如下图右侧的框中所示:

单击仪表板中的方框或顶部菜单中的通知(带有数字1的铃铛图标)将带您到概述页面;在这里,您可以查看部署的状态:

部署后,您应该有一个空的函数应用程序,可以准备将代码部署到其中:

要部署一些测试代码,您需要在左侧菜单中的函数旁边单击“+”图标;这将带您到以下页面:

选择Webhook+API和CSharp后,单击“创建此函数”;这将向您的函数应用程序添加以下代码:

usingSystem.Net;publicstaticasyncTaskRun(HttpRequestMessagereq,TraceWriterlog){log.Info("C#HTTPtriggerfunctionprocessedarequest.");//parsequeryparameterstringname=req.GetQueryNameValuePairs().FirstOrDefault(q=>string.Compare(q.Key,"name",true)==0).Value;//Getrequestbodydynamicdata=awaitreq.Content.ReadAsAsync();//Setnametoquerystringorbodydataname=namedata.name;returnname==nullreq.CreateResponse(HttpStatusCode.BadRequest,"Pleasepassanameonthequerystringorintherequestbody"):req.CreateResponse(HttpStatusCode.OK,"Hello"+name);}这段代码简单地读取变量name,它通过URL传递,然后作为Hello打印回给用户。

我们可以通过单击页面顶部的“运行”按钮来测试这一点。这将执行我们的函数,并为您提供输出和日志:

测试运行的日志如下:

能够在Azure仪表板的安全环境中进行测试是很好的,但是如何直接访问您的函数应用呢?

如果单击HttpTriggerCSharp1,它将带您回到您的代码,在代码块上方,您将有一个按钮,上面写着“获取函数URL”,单击此按钮将弹出一个包含URL的覆盖框。复制这个:

对我来说,URL是:

前面的URL将不再起作用,因为函数已被移除;它仅用于说明目的,您应该用您的URL替换它。

使用以下命令在命令行上调用该URL:

从返回的内容中可以看出,我们的函数应用返回了HttpStatusCodeBadRequest消息。这是因为我们没有传递name变量。为了做到这一点,我们需要更新我们的命令为:

您还可以在浏览器中输入URL并查看消息:

从主页上可以看到,它支持AWS和MicrosoftAzure,以及GoogleCloud平台和IBMOpenWhisk。您还会注意到有一个注册按钮;单击此按钮并按照屏幕提示创建您的帐户。

注册后,您将收到一些非常简单的关于如何安装工具和部署第一个应用程序的说明;让我们现在遵循这些。首先,我们需要通过运行来安装命令行工具:

$npminstallserverless-g安装将需要几分钟,一旦安装完成,您应该能够运行:

$serverlessversion这将确认上一个命令安装的版本:

要在AWS中启动我们的hello-world函数,我们必须首先创建一个文件夹来保存无服务器工具包创建的工件,并切换到该文件夹;我在我的“桌面”上创建了一个文件夹,使用:

$mkdir~/Desktop/Serverless$cd~/Desktop/Serverless要生成启动我们的hello-world应用程序所需的文件,我们需要运行:

$serverlesscreate--templatehello-world这将返回以下消息:

在我的编辑器中打开serverless.yml,我可以看到以下内容(我已删除了注释):

$serverlessdeploy您可能已经猜到,这将hello-world应用程序部署到了AWS:

使用HTTPie访问终端URL:

转到serverlessdeploy命令末尾提到的URL,可以概览您使用serverless部署到Lambda的函数:

此时,您可能会想,“我的帐户是如何启动的?我没有提供任何凭据!”无服务器工具旨在使用与我们在启动第一个Lambda函数之前安装的AWSCLI相同的凭据-这些凭据可以在您的计算机上的~/.aws/credentials找到。

要删除函数,只需运行:

$serverlessremove这将删除无服务器工具包在您的AWS帐户中创建的所有内容。

尽管到目前为止我们只启动了最基本的应用程序,但我希望您开始看到使用无服务器如何有助于开发您的应用程序。

由于无服务器函数被执行然后立即终止,你不应该担心它在哪里或者如何执行,只要它执行了。这意味着你的应用程序理论上应该是可伸缩的,也比传统的基于服务器的应用程序更容错。

例如,如果在调用你的一个函数时出现问题,例如,如果它崩溃了或者有资源问题,并且你知道下次调用函数时它将被重新启动,你不需要担心你的代码在有问题的服务器上执行。

在本章中,我们快速了解了什么是无服务器,并在AWS和MicrosoftAzure中启动和交互了无服务器函数,还使用了一个名为无服务器的第三方工具,在AWS中创建了一个无服务器函数。

到目前为止,你可能已经注意到我们还没有提到Kubernetes,对于一本名为用于无服务器应用程序的Kubernetes的书来说,这可能有点奇怪。不过不用担心,在下一章中我们将更详细地了解Kubernetes,一切将变得清晰起来。

正如前一章末尾提到的,本章将讨论Kubernetes。我们将讨论:

Kubernetes的简要历史-它从哪里来?

它是如何运作的?

Kubernetes的用例是什么,谁在使用它?

为什么要在服务器上运行无服务器?

“用于自动化部署、扩展和管理容器化应用的开源系统。”

该项目起源于谷歌内部的一个名为Borg的项目。在Docker引起轰动之前,谷歌长期使用容器技术。

谷歌自己的容器之旅始于2006年,当时他们的两名工程师开始了控制组(cgroups)项目。这是Linux内核的一个功能,可以隔离诸如RAM、CPU、网络和磁盘I/O等资源,以供一组进程使用。cgroups最初是在2007年发布的,在2008年初,该功能被合并到Linux内核主线版本2.6.24中。

几年后的2013年10月,谷歌发布了他们自己的容器系统的开源版本,名为lmctfy,实际上是LetMeContainThatForYou的缩写。这个工具实际上是他们在自己的服务器上使用的,用于运行Linux应用容器,它被设计为LXC的替代品。

这就是Borg项目的由来。谷歌大量使用容器,我说的是大量。2014年5月,谷歌的JoeBeda在Gluecon上做了一个名为大规模容器的演讲。演讲中有一些引人注目的引用,比如:

“谷歌所有的东西都在容器中运行。”

而最常谈论的一个是:

“我们每周启动超过20亿个容器。”

虽然Joe详细介绍了谷歌当时如何使用容器,但他并没有直接提到Borg项目;相反,它只是被称为一个集群调度器。

命令式:在那台服务器上启动这个容器

这个概念解释了谷歌是如何能够每周启动超过20亿个容器,而不必真正管理超过20亿个容器。

直到2015年谷歌发表了一篇名为《谷歌Borg的大规模集群管理》的论文,我们才真正了解到了JoeBeda在前一年提到的集群调度器的实践和设计决策。

论文讨论了谷歌内部的工具Borg是如何运行成千上万的作业的,这些作业几乎构成了谷歌所有应用程序的集群,这些集群由成千上万台机器组成。

我建议阅读这篇论文,因为它很好地概述了谷歌是如何处理自己的容器服务的。

另外,如果你在想,Borg是以《星际迷航:下一代》电视剧中的外星种族命名的。

2014年,JoeBeda、BrendanBurns和CraigMcLuckie加入了BrianGrant和TimHockin参与了第七号项目。

这个项目以《星际迷航》中的角色“第七号九”命名,旨在制作一个更友好的Borg版本。在第一次提交时,该项目已经有了一个外部名称,即Kubernetes。

然而,到了2015年7月的1.0版本发布时,谷歌已经意识到它已经远远超出了这个范畴,他们加入了Linux基金会、Twitter、英特尔、Docker和VMware(举几个例子),共同组建了云原生计算基金会。作为这一新合作的一部分,谷歌将Kubernetes项目捐赠为新组织的基础。

此后,其他项目也加入了Kubernetes,比如:

除此之外,像AWS、微软、红帽和甲骨文这样的新成员都在支持和为基金会的项目提供资源。

现在我们对Kubernetes的起源有了一个概念,我们应该逐步了解构成典型Kubernetes集群的所有不同组件。

Kubernetes本身是用Go编写的。虽然项目的GitHub页面显示该项目目前84.9%是Go,其余的5.8%是HTML,4.7%是Python,3.3%是Shell(其余是配置/规范文件等),都是文档和辅助脚本。

Kubernetes有两个主要的服务器角色:主服务器和节点;每个角色都由多个组件组成。

主服务器是集群的大脑,它们决定pod(在下一节中更多介绍)在集群内部部署的位置,并且对集群的健康状况以及pod本身的健康状况进行操作和查看。

主服务器的核心组件包括:

kube-apiserver:这是您的Kubernetes控制面板的前端;无论您使用什么来管理您的集群,它都将直接与此API服务通信。

etcd:etcd是Kubernetes用来存储集群状态的分布式键值存储。

kube-controller-manager:此服务在后台工作,以维护您的集群。它查找加入和离开集群的节点,确保正在运行正确数量的pod,并且它们健康等等。

cloud-controller-manager:这项服务是Kubernetes的新功能。它与kube-controller-manager一起工作,其目的是与AWS、GoogleCloud和MicrosoftAzure等云提供商的API进行交互。它执行的任务示例可能是,如果要从集群中删除一个节点,它将检查您的云服务API,看看节点是否仍然存在。如果存在,则可能会出现问题;如果不存在,则很可能是因为缩放事件而删除了节点。

kube-scheduler:根据一系列规则、利用率和可用性选择pod应该在哪里启动。

接下来我们有节点。一旦部署,主节点与安装在节点上的组件进行交互,以在集群内实现变化;这些是您的pod运行的地方。

组成节点的组件有:

kubelet:这是在节点上运行的主要组件。它负责接受来自主服务器的指令并报告回去。

kube-proxy:这项服务有助于集群通信。它充当节点上所有网络流量的基本代理,并能够配置TCP/UDP转发或充当TCP/UDP轮询负载均衡器到多个后端。

docker或rkt:这些是节点上实际的容器引擎。kubelet服务与它们交互,以启动和管理运行在集群节点上的容器。在接下来的章节中,我们将看到运行这两种节点的示例。

supervisord:这个进程管理器和监视器维护着节点上其他服务的可用性,比如kubelet、docker和rkt。

fluentd:这项服务有助于集群级别的日志记录。

你可能已经注意到,这些服务中唯一提到容器的是docker和rkt。Kubernetes实际上并不直接与您的容器交互;相反,它与一个pod通信。

正如前面提到的,Kubernetes不部署容器;相反,它启动pod。在其最简单的形式中,一个pod实际上可以是一个单一的容器;然而,通常一个pod由多个容器、存储和网络组成。

以下内容仅供说明,不是一个实际的例子;我们将在下一章中通过一个实际的例子来进行讲解。

把一个pod想象成一个完整的应用程序;例如,如果你运行一个简单的web应用程序,它可能只运行一个NGINX容器——这个pod的定义文件将看起来像下面这样:

apiVersion:v1kind:Podmetadata:name:nginxspec:containers:-name:nginximage:nginx:latestports:-containerPort:8080正如你所看到的,我们提供了关于我们的pod的一些简单元数据,这种情况下只是名称,这样我们就可以识别它。然后我们定义了一个单一的容器,它正在运行来自Dockerhub的最新NGINX镜像,并且端口8080是开放的。

就目前而言,这个pod是相当无用的,因为我们只打算显示一个欢迎页面。接下来,我们需要添加一个卷来存储我们网站的数据。为了做到这一点,我们的pod定义文件将如下所示:

apiVersion:v1kind:Podmetadata:name:nginxspec:containers:-name:nginximage:nginx:latestvolumeMounts:-mountPath:/srv/wwwname:web-datareadOnly:trueports:-containerPort:8080volumes:-name:web-dataemptyDir:{}正如你所看到的,我们现在正在创建一个名为web-data的卷,并将其以只读方式挂载到/srv/www,这是我们NGINX容器上的默认网站根目录。但这还是有点毫无意义,因为我们的卷是空的,这意味着我们的所有访问者将只看到一个404页面。

让我们添加第二个容器,它将从AmazonS3存储桶同步我们网站的HTML:

到目前为止,你可能会想到自己;我们有一个从AmazonS3存储桶部署的网站服务的pod,这一切都是真实的。然而,我们还没有完全完成。我们有一个正在运行的pod,但我们需要将该pod暴露给网络,以便在浏览器中访问它。

为了做到这一点,我们需要启动一个服务。对于我们的示例,服务文件看起来可能是这样的:

apiVersion:v1kind:Servicemetadata:name:nginx-servicespec:selector:app:nginxports:-protocol:TCPport:80targetPort:8080正如你所看到的,服务定义看起来与pod的定义类似。我们使用元数据部分设置名称。然后我们选择我们的NGINXpod,并将端口80映射到端口8080,这是我们的pod正在侦听的端口。

如前所述,当我们启动第一个Kubernetes集群时,我们将在下一章更详细地讨论这个问题,但现在,这应该让你对Kubernetes的运作方式有一个很好的了解。

在上一节中,我们看了pod和服务。虽然这些可以手动启动,但你也可以使用控制器来管理你的pod。这些控制器允许执行不同类型的工作负载。我们将快速看一下不同类型的控制器,还讨论何时使用它们。

ReplicaSet可用于启动和维护相同pod的多个副本。例如,使用我们在上一节中讨论的NGINXpod,我们可以创建一个ReplicaSet,启动三个相同pod的副本。然后可以在这三个pod之间进行负载均衡。

我们的三个pod可以分布在多个主机上,这意味着,如果一个主机因任何原因消失,将导致我们的一个pod停止服务,它将自动在健康节点上被替换。你还可以使用ReplicaSet来自动和手动地添加和删除pod。

您可能会认为使用ReplicaSet可以进行滚动升级和回滚。不幸的是,ReplicaSets只能复制相同版本的pod;幸运的是,这就是部署的用武之地。

部署控制器旨在更新ReplicaSet或pod。让我们以NGINX为例。正如您从以下定义中所看到的,我们有3个副本都在运行NGINX版本1.9.14:

apiVersion:apps/v1beta1kind:Deploymentmetadata:name:nginx-deploymentspec:replicas:3template:metadata:labels:app:nginxspec:containers:-name:nginximage:nginx:1.9.14ports:-containerPort:80kubectl是Kubernetes的命令行客户端;我们将在下一章中更详细地讨论这个问题。

我们可以使用以下命令进行部署:

$kubectlcreate-fnginx-deployment.yaml现在假设我们想要更新使用的NGINX图像的版本。我们只需要运行以下命令:

$kubectlsetimagedeployment/nginx-deploymentnginx=nginx:1.13.5deployment"nginx-deployment"imageupdated这将逐个更新每个pod,直到所有的pod都运行新版本的NGINX。

这个控制器是Kubernetes中的新功能,旨在取代PetSets。正如您可能从名称中猜到的那样,pod作为部署的一部分维护其状态。它们被设计为具有:

在整个pod生命周期中保持一致的唯一网络标识符

持久存储

按照您定义的顺序执行的优雅部署和扩展

用户定义和控制的自动滚动更新

因此,虽然名称有所变化,但您应该将StatefulSets视为宠物,将ReplicaSets视为牲畜。

正如我们在本章中已经提到的,Kubernetes几乎可以在任何地方运行,从您的本地机器(我们将在下一章中介绍),到您的本地硬件或虚拟机基础设施,甚至可能跨越AWS、MicrosoftAzure或GoogleCloud的数百个公共云实例。事实上,您甚至可以在Kubernetes集群中跨多个环境。

这意味着无论您在何处运行应用程序,都会获得一致的体验,但也可以利用底层平台的功能,比如负载平衡、持久存储和自动扩展,而无需真正设计应用程序以意识到它是在运行,比如在AWS或MicrosoftAzure上。

阅读成功案例时你会注意到的一个共同点是,人们谈论的是不被锁定在一个特定的供应商上。由于Kubernetes是开源的,他们不会被任何许可成本所限制。如果他们遇到问题或想要添加功能,他们可以直接深入源代码进行更改;他们也可以通过拉取请求将他们所做的任何更改贡献回项目中。

另外,正如前面讨论的,使用Kubernetes使他们不会被锁定在任何一个特定的平台供应商或架构上。这是因为可以合理地假设Kubernetes在安装在其他平台时会以完全相同的方式运行。因此,突然之间,您可以相对轻松地将您的应用程序在不同提供商之间移动。

另一个常见的用例是运维团队将Kubernetes用作基础设施即服务(IaaS)平台。这使他们能够通过API、Web和CLI向开发人员提供资源,这意味着他们可以轻松地融入自己的工作流程。它还为本地开发提供了一个一致的环境,从暂存或用户验收测试(UAT)到最终在生产环境中运行他们的应用程序。

这也是为什么使用Kubernetes执行无服务器工作负载是一个好主意的部分原因。您不会被任何一个提供商锁定,比如AWS或MicrosoftAzure。事实上,您应该把Kubernetes看作是一个云平台,就像我们在第一章中看到的那些;它有一个基于Web的控制台,一个API和一个命令行客户端。

关于Kubernetes的几个案例研究,用户详细介绍了他们在使用Kubernetes过程中的经历:

还有来自以下内容的讨论、采访和演示:

在这一章中,我们谈到了Kubernetes的起源,并介绍了一些其使用案例。我们还了解了一些基本功能。

在下一章中,我们将通过在本地安装Minikube来亲自体验Kubernetes。一旦我们安装好了本地的Kubernetes,我们就可以继续进行第四章,“介绍Kubeless功能”,在那里我们将开始在Kubernetes上部署我们的第一个无服务器函数。

在本章中,我们将看看如何使用Minikube快速搭建本地的Kubernetes安装。一旦我们的本地Kubernetes安装运行起来,我们将学习一些基本功能,并讨论在本地运行Kubernetes的局限性。我们将学习在以下平台上安装Kubernetes:

macOS10.13HighSierra

在我们开始安装之前,让我们快速看一下我们将使用的工具来部署我们的本地Kubernetes集群。

当你阅读上一章时,你可能会想到Kubernetes看起来很复杂。有很多组件需要配置,而且不仅需要配置,还需要监控和管理。

我记得当我最初看Kubernetes时,它刚发布不久,安装说明非常长,而且事情有点儿棘手。

在安装过程的开始阶段误读了一步,你可能会在安装过程的后期陷入麻烦——这让我想起了以前杂志上会包含游戏代码清单的情形。如果你在任何地方打错字,那么事情要么根本不起作用,要么会出现意外崩溃。

随着Kubernetes的成熟,安装过程也在不断改进。相当快地,一些辅助脚本被开发出来,以帮助在各种平台上启动Kubernetes;Minikube就是其中之一。

它的工作就是创建一个本地的Kubernetes节点。考虑到Kubernetes支持的功能范围,它有令人惊讶的多种功能,比如:

DNS,NodePorts和Ingress

ConfigMaps和Secrets

容器运行时的选择;你可以使用Docker或rkt

通过hostPath持久卷

仪表板

通常需要公共云提供商(如AWS,MicrosoftAzure或GoogleCloud)或多个主机的Kubernetes功能是不受支持的。其中一些功能包括:

负载均衡器

高级调度策略

这是因为Minikube只在本地PC上的虚拟机上启动单个节点。但这不应该限制你;请记住,你只会想要在Minikube上进行开发,并且不应该使用它构建生产服务。还有很多其他工具,将在第六章中介绍,在云中安装Kubernetes,更适合在公共云或其他供应商中启动生产就绪的Kubernetes集群。

Minikube由两个核心组件组成:

libmachine:这个来自Docker的库用于在主机上提供虚拟机。它是DockerMachine以及DockerformacOS和DockerforWindows的核心组件。

localkube:这个库是由Redspread(现在是CoreOS的一部分)开发并捐赠给Minikube项目的,它负责在启动虚拟机后部署和维护Kubernetes节点。

不再讨论Minikube能做什么,我们应该看看如何安装它,然后讨论如何与它交互。

我们将看看如何在介绍中提到的三种不同操作系统上安装Minikube。一旦安装完成,与Minikube交互的过程大部分是一致的,这意味着,虽然我在示例中使用的是macOS,但相同的命令也适用于Windows和Linux。考虑到早期Kubernetes安装和配置过程的复杂性,你会惊讶地发现现在的过程是多么简单。

要在macOS上安装Minikube,你首先必须安装Homebrew和Cask。

Homebrew是macOS的基于命令行的软件包管理器。Homebrew用于安装命令行工具和Cask,Cask是一个用于管理桌面应用程序的附加组件。它非常有用,可以管理macOS应用商店中不可用的软件,同时也可以避免你在自己的机器上手动编译软件。

如果你还没有安装Homebrew,你可以通过运行以下命令来安装它:

$brewinstallcask如果你已经安装了Homebrew和Cask,那么你应该确保一切都是最新的,并且准备好使用以下命令运行:

$brewupdate$brewdoctor一旦Homebrew和Cask准备好,你可以通过运行以下命令来安装Minikube:

$brewcaskinstallminikube首先会下载依赖项,然后安装Minikube:

该过程不到一分钟,安装完成后,您应该能够执行以下操作:

$minikubeversion这将显示当前版本;在我的情况下,这是v0.22.2。我们现在已经安装并准备好使用Minikube了。

与我们在macOS上安装Minikube的方式类似,我们将使用一个包管理器;这次叫做Chocolatey。

Chocolatey是Windows的一个包管理器,类似于macOS上的Homebrew。它使您能够从命令行安装软件,并支持PowerShell和cmd.exe。我们将使用PowerShell。

如果您没有安装Chocolatey,可以在以管理员权限启动的PowerShell控制台中运行以下命令:

以下命令是一行,而不是多行。另外,由于我们使用Set-ExecutionPolicyBypass来运行安装命令,您将被询问是否确定。由于我们直接从Chocolatey网站通过HTTPS运行脚本,您应该能够信任该脚本并回答是。

$chocoinstallminikube这将下载并安装依赖项,然后安装Minikube。当您被要求确认是否要运行脚本时,请回答是:

安装后,您将能够运行以下命令:

$minikubeversion这将返回安装的Minikube版本;对我来说,这是v0.22.2。

与macOS和Windows版本不同,我们将不会使用包管理器在Ubuntu17.04上安装Minikube。相反,我们将直接从项目页面下载二进制文件。要做到这一点,只需运行以下命令:

现在Minikube已安装,我们需要下载kubectl。在macOS和Windows安装过程中,这是由包管理器处理的;幸运的是,这个过程与我们刚刚运行以安装Minikube的命令几乎相同:

$minikubeversion当我运行该命令时,它返回v0.22.2,如下截图所示:

Minikube支持多种不同的hypervisors。Hypervisor是一个用于启动虚拟机的进程;它将虚拟机的操作系统与您自己的操作系统隔离开来,同时允许它共享CPU、RAM和磁盘空间等资源。

Minikube默认支持以下hypervisors:

Hyper-V(Windows10):这是本机hypervisor;它适用于Windows10专业版和Windows服务器

KVM(Ubuntu17.04):这是本机Linuxhypervisor,在大多数现代发行版的Linux内核中运行

VirtualBox(macOS,Windows10和Ubuntu17.04):由Oracle发布,VirtualBox是一个开源的x86hypervisor,可以在大量操作系统上运行

VMwareFusion(macOS):Fusion提供了一个经过优化的macOShypervisor,其最大优势是能够在macOS上运行和公开Windows应用程序

xhyve(macOS):这是macOS上的本机hypervisor;就像Linux上的KVM一样,它内置在内核中

对于macOS,我们可以使用Homebrew和Cask来安装VirtualBox:

$brewcaskinstallvirtualbox同样,对于Windows10,您可以使用Chocolatey来安装VirtualBox:

如果启用了Hyper-V,则无法在Windows10上使用VirtualBox。如果您希望跟随操作,请在继续之前禁用Hyper-V。

$chocoinstallvirtualbox最后,对于Ubuntu17.04,您需要运行以下命令来添加存储库和密钥:

$sudoapt-getupdate$sudoapt-getinstallvirtualbox-5.1现在您应该能够在列出的软件程序中看到Virtualbox。

要完成我们的安装,我们需要启动Minikube。要做到这一点,请运行以下命令:

$minikubestart在macOS上,您应该看到类似于这样的东西:

如您所见,用于创建虚拟机的ISO已经下载。虚拟机启动,我们将用于对我们的单节点集群进行身份验证的证书被生成,最后kubectl被配置为使用我们本地Kubernetes集群的详细信息。

在Windows10上运行相同的命令将得到完全相同的步骤:

另外,正如您可能已经猜到的那样,在Ubuntu17.04上运行会得到相同的结果。运行以下命令:

$minikubestatus您将收到一条消息,确认一切正常运行,并且kubectl已正确配置以与您的Kubernetes集群通信:

如果您打开VirtualBox,您应该会看到您的Minikube虚拟机正在运行;例如,当我在Windows10上打开VirtualBox时就是这种情况:

尽管我们在三种不同的操作系统上启动了Minikube,除了初始安装之外,您已经可以体验我们在第二章中讨论的内容了:没有供应商锁定和一致的体验,而且这是在我们开始使用新安装的Kubernetes集群之前。

到目前为止,我们已经使用了minikubestart和minikubestatus命令来启动我们的单节点Kubernetes集群,并检查一切是否按预期运行。在我们开始与Kubernetes交互之前,我想介绍一些更基本的Minikube命令。

由于我们将我们的单节点Kubernetes集群作为虚拟机在您的主机上运行,您可能不希望它一直运行,占用资源。

有两种选项可以实现这一点,第一种是minikubestop。这个命令将停止您的节点,并保持虚拟机完整。如果您计划在下次通过运行minikubestart启动节点时继续之前的工作,您应该使用这个命令。

虽然minikubestop命令会停止您的虚拟机在主机上使用CPU和RAM资源,但用于托管虚拟机的硬盘映像仍将存在于您的机器上。虽然新启动的集群不会占用主机硬盘上太多空间,在我的macOS安装中大约为650MB;一旦您开始使用集群,您可能会发现这个空间至少会翻倍。

这就是我们下一个命令发挥作用的地方。minikubedelete命令将完全删除集群,包括所有虚拟机文件,释放主机机器上使用的空间。

在写作时,运行minikubedelete将立即删除您的虚拟机,无论其是否正在运行。不会有提示询问您是否确定,也没有从该命令返回的方法(除非您有备份),因此请确保谨慎使用此命令。

当您再次运行minikubestart时,您的集群将从头开始启动,就像我们在上一节中首次体验到的那样。

接下来,我们有一些命令,显示有关虚拟机的信息,以及Minikube在您的设备上配置的环境。

首先,我们有一个非常简单的命令minikubeip。这个命令只是返回虚拟机的IP地址。如果您想通过脚本与集群交互,这将非常有用。您可以包含命令的输出,以引用集群的当前IP地址,而无需在脚本中硬编码实际的IP地址。

我们要看的下一个命令是minikubedocker-env。运行此命令应该会在屏幕上打印出类似以下输出:

$minikubedocker-envexportDOCKER_TLS_VERIFY="1"exportDOCKER_HOST="tcp://192.168.99.101:2376"exportDOCKER_CERT_PATH="/Users/russ/.minikube/certs"exportDOCKER_API_VERSION="1.23"#Runthiscommandtoconfigureyourshell:#eval$(minikubedocker-env)输出的作用是允许您(如果已安装)配置本地Docker客户端与Minikube虚拟机上的Docker安装进行通信。然而,这样做也有一个缺点。目前作为Minikube虚拟机镜像的一部分分发的Docker版本略落后于当前版本。您可以通过运行eval$(minikubedocker-env),然后dockerversion来查看这一点。当我运行这两个命令时,得到了以下结果:

$eval$(minikubedocker-env)$dockerversionClient:Version:17.06.2-ceAPIversion:1.23Goversion:go1.8.3Gitcommit:cec0b72Built:TueSep520:12:062017OS/Arch:darwin/amd64Server:Version:1.12.6APIversion:1.24(minimumversion)Goversion:go1.6.4Gitcommit:78d1802Built:WedJan1100:23:162017OS/Arch:linux/amd64Experimental:false从输出中可以看出,写作时Minikube使用的Docker版本比我在macOS上安装的最新稳定版本要落后两个版本。在本书涵盖的内容范围内,运行旧版本的Docker并不是问题,也不需要担心,因为我们不会直接与其交互。

$sshdocker@$(minikubeip)-i$(minikubessh-key)这将动态生成虚拟机的IP地址和私钥路径:

我们要快速查看的最后一个命令是minikubelogs。这会显示localkube实例生成的所有日志:

这些日志用于帮助调试您的Minikube安装中的问题。它们不包含任何用户数据,这意味着您不能使用它们来帮助跟踪您启动的服务或pod的任何问题。

现在我们的单节点Kubernetes集群已经运行起来了,使用Minikube,我们可以尝试启动一个服务。我们将首先使用仪表板,然后再转向命令行客户端。

每个Minikube安装都带有一个基于Web的仪表板。这可以通过运行minikubedashboard来访问,它会立即在您的默认浏览器中打开仪表板:

点击页面左上角的+创建按钮,将带您到一个表单,让您部署一个容器化应用程序。

在部署容器化应用页面上,您会找到几个选项。保持启用下面的指定应用程序详细信息选项,填写如下:

应用名称:dashboard-hello-world

容器镜像:nginx:latest

Pod数量:1

服务:外部

端口:8080

目标端口:80

协议:TCP

对于我们的目的,我们不需要填写在“显示高级选项”下找到的任何选项。只需点击表单底部的“部署”按钮。过一会儿,您的仪表板应该显示您有一个部署、pod、ReplicaSet和服务,所有这些都带有dashboard-hello-world的名称:

您可以通过运行以下命令查看服务:

$minikubeservicedashboard-hello-world这将返回以下消息:

Openingkubernetesservicedefault/dashboard-hello-worldindefaultbrowser...打开您的浏览器,在那里您应该看到默认的NGINX页面:

虽然这只是一个非常基本的例子,但它确实展示了使用仪表板启动简单应用程序有多简单。现在让我们看看如何转移到命令行。

在上一章中,我们简要介绍了如何使用YAML或JSON文件来定义您的pod、ReplicaSets和服务。让我们使用kubectl来启动一个与前一个应用程序相同的应用程序。

首先,我们需要一个要启动的文件;您可以在本书的代码包和GitHub存储库的Chapter03文件夹中找到名为cli-hello-world.yml的副本:

apiVersion:v1kind:Servicemetadata:name:cli-hello-worldspec:selector:app:cli-hello-worldtype:NodePortports:-protocol:TCPport:8000targetPort:80---apiVersion:apps/v1beta1kind:Deploymentmetadata:name:cli-hello-worldlabels:app:nginxspec:replicas:1selector:matchLabels:app:cli-hello-worldtemplate:metadata:labels:app:cli-hello-worldspec:containers:-name:nginximage:nginx:latestports:-containerPort:80您可能已经注意到,虽然这是一个单独的文件,但实际上我们有两个不同的部分。第一个启动外部服务,在端口8000上公开它,以便与我们在上一节使用仪表板启动的外部服务不发生冲突。第二部分定义了pod和复制集;这与我们使用仪表板启动的内容非常相似。

要启动应用程序,我们只需要运行以下命令:

$kubectlapply-fcli-hello-world.yml您几乎立即会收到已创建服务和部署的确认:

service"cli-hello-world"createddeployment"cli-hello-world"created创建后,您应该能够运行以下命令在浏览器中打开应用程序:

$minikubeservicecli-hello-world再次,您应该会看到默认的NGINX页面。

我相信当我们打开仪表板时,您点击了页面左侧可以找到的菜单项。所有这些信息也可以在命令行中找到,所以让我们简要地看一下我们可以使用的一些命令来了解有关我们集群的更多信息。

您将要运行的更常见的命令之一是kubectlget。这将获取pod、ReplicaSets和服务的列表,以及更多内容。运行以下命令应该给我们一个类似于仪表板概述的视图:

$kubectlgetpods$kubectlgetreplicasets$kubectlgetservices$kubectlgetsecrets正如您从以下终端输出中所看到的,所有内容都列出了其当前状态:

您可以获得很多选项;例如,尝试运行这个:

$kubectlgetendpoints$kubectlgetevents$kubectlgetstorageclasses只运行kubectlget将列出您可以使用的所有不同参数。现在我们有了完整的pod名称,在我的情况下是cli-hello-world-3678853705-f41d2,我们可以通过运行kubectldescribe命令来了解更多关于它的细节。例如,我运行了这个:

$kubectldescribepods/cli-hello-world-3678853705-f41d2当您在本地运行命令时,请更新pod名称以反映您自己的名称。Kubernetes在启动时为每个pod添加一个唯一ID,以确保您可以在任何给定的主机上运行多个相同的pod。

我得到了以下信息:

$kubectldescribeservices/cli-hello-world$kubectldescribereplicasets/cli-hello-world-3678853705$kubectldescribestorageclasses/standard同样,您可以通过仅运行kubectldescribe来了解更多信息。在接下来的章节中,我们将介绍更多命令,以便在本书结束时,您将能够充分利用kubectl。

在完成本章之前,我希望我们能够快速看一下如何将存储从本地机器挂载到Minikube虚拟机内部,然后再挂载到我们的pod内部。

您将在Chapter03文件夹中找到一个名为html的文件夹。其中包含一个名为index.html的单个文件。在Chapter03文件夹中运行以下命令将挂载HTML到虚拟机内部:

$minikubemount./html:/data/html您可以从运行命令后显示的消息中看到这一点:

您需要保持此进程运行,因此在本节的其余部分中打开一个新的终端或PowerShell窗口以供使用。

运行以下命令:

如您所见,我们的index.html文件在/data/html/中的集群节点上可用。返回到Chapter03文件夹,您应该会看到一个名为cli-hello-world-storage.yml的文件。其中包含使用此挂载文件夹的服务和部署信息。

服务部分看起来与本节中先前使用的很相似;但是,在部署部分有一个额外的内容:

apiVersion:apps/v1beta1kind:Deploymentmetadata:name:cli-hello-world-storagelabels:app:nginxspec:replicas:1selector:matchLabels:app:cli-hello-world-storagetemplate:metadata:labels:app:cli-hello-world-storagespec:volumes:-name:htmlhostPath:path:/data/htmlcontainers:-name:nginximage:nginx:latestports:-containerPort:80volumeMounts:-mountPath:/usr/share/nginx/htmlname:html正如您所看到的,在部署的spec部分中,我们现在正在定义一个名为html的volume,然后在容器部分中,我们正在使用mountPath选项将名为html的卷挂载到/usr/share/nginx/html,这是我们在容器中使用的NGINX容器映像的默认网页根目录。

使用kubectlapply命令启动您的应用程序,然后使用minikubeservice命令在浏览器中打开服务:

$kubectlapply-fcli-hello-world-storage.yml$minikubeservicecli-hello-world-storage您应该看到以下页面:

如果您在本地机器上的html文件夹中编辑index.html,当您刷新浏览器窗口时,更改将立即反映出来。

在我们进入下一章之前,我们应该删除本章中使用的Minikube虚拟机,以便我们从头开始。首先,我们有一个进程,它正在保持我们主机机器上的html文件夹挂载。要终止此进程,请返回到终端或PowerShell并按下Ctrl+C;这将向进程发送终止信号并将您返回到命令行。然后我们可以运行:

$minikubedelete这将删除当前的虚拟机,这意味着当我们下次启动Minikube时,它将从头开始。

有关本章中使用的工具的更多信息,请访问它们的项目页面:

在本章中,我们使用Minikube在本地机器上安装了单节点Kubernetes集群;我们看了如何在macOS、Windows10和UbuntuLinux上实现这一点。一旦安装完成,我们发现无论我们的本地机器运行哪个操作系统,我们都可以以完全相同的方式与我们的单节点Kubernetes集群进行交互。

然后,我们首次启动了Pods、ReplicaSets和服务,使用了Kubernetes仪表板和名为kubectl的Kubernetes命令行客户端。

在下一章中,我们将在我们目前在本地运行的单节点Kubernetes集群上启动我们的第一个无服务器工具,名为Kubeless。

现在我们的Kubernetes安装已经运行起来了,我们可以开始运行我们的第一个无服务器应用程序;我们将通过一些示例来安装和运行Kubeless。我们将涵盖以下主题:

安装Kubeless

Kubeless概述

使用Kubeless运行我们的第一个函数-“helloworld”示例

更高级的示例-发布推文

无服务器插件

让我们开始在我们的三个目标操作系统上安装Kubeless。

Kubeless有两个组件;第一个是在Kubernetes上运行的堆栈,第二部分是您用来与Kubeless集群交互的命令行客户端。

我们首先将看看如何让Kubeless在Kubernetes上运行起来。一旦运行起来,我们将看看如何在我们的三个目标操作系统上安装命令客户端。

我们将在上一章中安装和配置的单节点Minikube集群上安装Kubeless。我们需要做的第一件事是确保我们从一个干净的Kubernetes安装开始。为此,我们只需要运行以下两个命令:

请记住,运行minikubedelete命令将立即删除当前正在运行的虚拟机,而不会发出警告,这意味着您的Minikube单节点集群上当前活动的所有内容都将丢失。

$minikubedelete$minikubestart现在我们的新的单节点Kubernetes集群已经运行起来了,我们需要通过运行以下命令为Kubeless创建一个命名空间:

$kubectlcreatenskubeless然后通过运行以下命令安装Kubeless本身:

$kubectlgetpods-nkubeless$kubectlgetdeployment-nkubeless$kubectlgetstatefulset-nkubeless这应该会显示类似以下输出:

或者,您也可以使用Kubernetes仪表板来检查状态。要做到这一点,运行以下命令打开仪表板:

$minikubedashboard当仪表板首次打开时,它被配置为显示默认命名空间,因为我们执行的第一个命令创建了一个名为kubeless的新命名空间。我们需要切换到kubeless命名空间以查看其中部署的Pods、Deployments和StatefulSets。

一旦您更改了命名空间,您应该在以下页面上看到一些内容:

正如您所看到的,我们只用两个命令就部署了一组相当复杂的服务。所有繁重的工作和复杂性都已完全抽象化。

现在Kubeless已经安装在我们的单节点Kubernetes集群上,我们可以考虑安装命令行客户端;这是我们将与我们的Kubeless集群进行交互的方式。

由于我们已经在上一章安装了Homebrew,我们将使用brew命令来安装Kubeless。为此,我们需要添加Kubelesstap;tap是一个包含软件安装说明的第三方存储库。一旦tap被添加,我们就可以以与我们在第二章中安装Minikube相同的方式安装Kubeless。

要安装tap,然后安装Kubeless命令行客户端,请运行以下两个命令:

$brewtapkubeless/tap$brewinstallkubeless安装完成后,您可以通过运行以下命令来检查已安装的客户端的版本:

$kubelessversion如果这返回的客户端版本与您安装的软件不同,不要太担心;这不应该是一个问题。

不幸的是,Kubeless没有可用的Chocolatey安装程序,因此我们必须手动下载和解压可执行文件。要在PowerShell中执行此操作,请运行以下命令:

$./kubelessversion这将返回命令行客户端的版本。

就像Windows10版本的Kubeless命令行客户端一样,我们需要下载发布版本,解压缩并将可执行文件移动到指定位置。要做到这一点,请运行以下命令:

$kubelessversion我们已经准备好在我们的UbuntuLinux主机上使用Kubeless。

在我们继续之前,我们还可以安装Kubeless的Web界面。就像Kubeless本身一样,只需运行以下命令即可轻松安装:

$minikubeserviceui--namespacekubeless从上述命令中可以看出,由于ui服务已部署在kubeless命名空间中,我们需要通过传递--namespace标志来让Minikube知道这是服务的访问位置。KubelessWeb界面可能需要几分钟才能启动,但当它启动时,您应该会看到一个类似以下内容的页面:

正如我们已经提到的,安装过程非常简单——在我们的单节点Kubernetes集群上安装Kubeless时,安装过程基本上是一样的,即使我们在由多个节点组成的Kubernetes上安装它也是如此。

Kubeless是一个支持在Kubernetes集群上部署无服务器函数的框架,它允许您使用HTTP和事件触发器来执行Python、Node.js或Ruby代码。该框架是使用核心Kubernetes功能构建的,如部署、服务、ConfigMaps等。这使得Kubeless的代码库很小,并且意味着开发人员不必重复大量的调度逻辑,因为它已经存在于Kubernetes核心中。

它通过利用Kubernetes控制器来工作。使用控制器,Kubeless开发人员已扩展了KubernetesAPI,以在Kubernetes中添加一个函数对象。Kubeless控制器作为部署在Kubernetes集群中运行,其主要工作是监视函数端点的调用。当调用端点时,将执行包含函数代码的运行时;这些是预构建的Docker镜像,用于包装您的函数,使用ConfigMaps注入到Kubernetes集群中的ApacheKafka消费者或HTTP服务器中,您可以像调用任何其他网页一样调用它们。

ApacheKafka是一个分布式流平台,让您可以发布和订阅信息流。在我们的情况下,这个信息流是触发的事件,Kubeless控制器订阅了这个事件。

所有这些意味着我们可以在我们运行的单节点集群中获得与我们在第一章无服务器景观中涵盖的AWS和MicrosoftAzure的无服务器服务类似的体验,包括我们本地运行的Kubernetes集群。

Bitnami多年来一直是分发预打包的开源和商业支持许可应用的领导者,在撰写本文时有超过140个应用程序,以可预测和一致的方式跨多个不同平台和公共云进行分发和支持,因此支持和开发Kubernetes对他们来说是一个自然的选择。

他们是Helm的核心贡献者,与微软和谷歌一起,Helm是由CloudNativeComputingFoundation论坛维护的Kubernetes的包管理器,我们知道来自第二章Kubernetes简介。

Kubeless命令行客户端有几个命令。在我们使用Kubeless在Kubernetes上启动我们的第一个无服务器函数之前,我们应该快速讨论一些我们将要使用的命令。

我们将要使用的最常见的命令是kubelessfunction。这允许我们部署、删除、编辑和列出函数。此外,我们可以通过使用call执行我们的函数,并检查日志。

接下来,我们有kubelessingress;使用此命令,我们可以创建、删除和列出到我们函数的路由。

最后,我们还将看一下kubelesstopic;与ingress一样,它允许我们创建、删除和列出主题,以及向主题发布消息。

首先,我们将看一下部署两个非常简单的helloworld函数。第一个简单地打印HelloWorld!,第二个接受输入,然后将其显示回给你。

首先,我们需要我们的函数。静态的hello-world函数需要以下三行Python代码:

importjsondefhandler():return"HelloWorld!"将前面的代码放在名为hello.py的文件中,该文件也可以在伴随本书的GitHub存储库的Chapter04/hello-world文件夹中找到。

现在我们有了我们的函数,我们可以通过运行以下命令将其部署到默认命名空间中:

您可能已经注意到,当您运行命令时,没有任何反馈,所以要检查函数是否已创建,您可以运行以下命令:

$kubelessfunctionls在前面的命令中有几列:

名称:这是函数的名称

命名空间:函数部署到的命名空间的名称

处理程序:要运行的处理程序的名称—在我们的情况下,处理程序只是处理程序,因此它正在调用hello-world.handler

运行时:Kubeless支持的每种语言都有单独的运行时

类型:这是函数被调用的方式,在我们的情况下这是HTTP

主题:如果我们订阅消息队列,这将是我们要观察消息的主题

另外,正如前一节中提到的,Kubeless将函数对象添加到Kubernetes中。您可以运行以下命令来检查我们的函数是否被列在函数对象中:

$kubectlgetfunctions通过这些命令运行应该会给您一些类似以下结果:

现在我们的函数已部署,我们可以执行它。要运行此操作,请运行:

$kubelessfunctioncallhello这将产生以下结果:

我们调用函数的另一种方式是使用KubelessWeb界面。通过运行以下命令打开它:

$minikubeserviceui--namespacekubeless打开后,您应该在左侧列出函数hello。单击hello将显示函数中的代码,并且右侧有一个标有RUNFUNCTION的按钮;单击此按钮将执行hello函数并返回HelloWorld!:

我们与函数交互的最终方式是创建Ingress规则;但是,在执行此操作之前,我们必须在Minikube中启用Ingress插件。要执行此操作,请运行以下命令:

$minikubeaddonsenableingress现在Ingress插件已启用,我们需要使用Kubeless创建Ingress路由。要执行此操作,我们只需要运行以下命令:

$kubelessingresscreate--functionhellohello-ingress我们需要知道Kubeless创建的主机,以便访问我们的服务。要执行此操作,请运行以下命令:

nip.io是一个简单且免费的DNS服务,允许您创建DNS记录将您的主机映射到IP地址。Kubeless使用此服务创建有效的主机以路由到您的服务。

在我的浏览器中打开此URL返回HelloWorld!,通过HTTPie运行它也是如此,我们在第一章中介绍了HTTPie,您可以从以下终端输出中看到:

现在我们的第一个函数已经运行起来了,让我们看看如何创建一个可以传递并打印数据的函数。

我们的新函数代码仍然非常简单:

importjsondefhandler(context):printcontext.jsonreturncontext.json此代码的全部作用只是接收我们发布的JSON并将其显示给我们。将其放入名为hello-name.py的文件中,或者使用GitHub存储库中Chapter04/hello-world/文件夹中的文件。一旦有了文件,您可以通过运行以下命令创建函数:

$kubelessfunctionls您应该看到列出了两个函数,hello和hello-name。现在我们已经创建了新函数,可以通过运行以下命令来调用它:

$kubelessfunctioncallhello-name--data'{"name":"Russ"}'请注意,这次我们使用--data标志将数据传递给函数。运行所有命令后,您应该看到类似以下终端输出:

在使用Web界面调用函数时,我们还需要传递数据。要做到这一点,再次打开界面,运行:

$minikubeserviceui--namespacekubeless打开后,点击hello-name函数。在点击RUNFUNCTION按钮之前,使用下拉菜单将GET更改为POST,并在请求表单中输入以下内容:

{"name":"Russ"}现在,点击RUNFUNCTION按钮。这将返回与kubelessfunctioncall命令相同的结果:

我们还可以通过配置Ingress路由直接与服务交互:

$kubelessingresscreate--functionhello-namehello-name-ingress$kubelessingresslist这将为我们的两个函数提供URL:

为什么会这样,尽管我们使用kubelessfunctioncall命令和KubelessWeb界面调用时都没有错误?

通过简单地将URL输入到浏览器中,我们没有发布任何数据供函数返回;这就是为什么会生成错误的原因。我们可以通过检查日志来确认这一点。要做到这一点,刷新浏览器中的页面几次,然后运行以下命令:

$kubelessfunctionlogshello-name您应该看到类似以下的内容:

前面日志输出的第一行是内部健康检查,它是成功的,因为生成了200状态,您可以在GET之后看到。接下来的几行包含我们要查找的错误;正如您所看到的,我们得到了Traceback,然后是以下内容:TypeError:handler()takesexactly1argument(0given)。这意味着函数期望传递数据,但没有传递。下一行是来自我们浏览器的请求;正如您在GET之后看到的,有一个500的状态。

那么,我们如何与需要POST数据而不是GET的函数进行交互呢?在macOS和Linux命令行上,您可以通过几种方式实现这一点,但在Windows上,您将不得不运行其他东西。与其通过不同的示例来工作,我要安装一个名为Postman的软件。这个桌面软件适用于我们在书中涵盖的所有三种操作系统,并且它将为我们与hello-name函数以及我们启动的任何其他函数进行交互提供一个很好的图形界面。

要在macOS10.13HighSierra上使用Homebrew安装Postman,只需运行:

$brewcaskinstallpostmanPostman有一个Chocolatey软件包,因此如果您使用的是Windows10专业版,可以运行:

$chocoinstallpostman要在Ubuntu17.04上安装Postman,我们需要运行一些额外的步骤。首先,我们需要下载、解压缩并移动文件到指定位置,确保清理和移动我们需要的文件。为此,请运行以下命令:

$cat>~/.local/share/applications/postman.desktop<

点击BUILDINGBLOCKS下的Request选项;这将带您进入保存对话框。在这里,输入hello-name的请求名称,然后点击+CreateCollection。在这里,创建一个名为Kubeless的集合,然后点击SavetoKubeless按钮。

要输入数据,请单击Body,然后选择原始选项。当您选择原始选项时,输入字段将发生变化,您应该看到单词Text和旁边的下拉图标。单击这个图标,然后选中JSON(application/json)选项。一旦更改,输入以下内容到主字段中:

单击保存按钮将保存设置,如果您想重新运行它们的话。

在我们继续下一节之前,我们应该整理一下我们的函数。要做到这一点,我们只需要运行:

$kubelessingressdeletehello$kubelessfunctiondeletehello$kubelessingressdeletehello-name$kubelessfunctiondeletehello-name这将删除我们的两个helloworld函数和Ingress路由。您还可以在Kubelessweb界面和Kubernetes仪表板中再次检查是否已删除了所有内容;您可以通过运行以下命令打开它们:

$minikubeserviceui--namespacekubeless$minikubedashboard如果您发现任何剩余的内容,无论是hello还是hello-name,您都可以从仪表板中删除服务、pod,甚至Ingress路由。

KubelessGitHub账户有一些更多的示例应用程序,这些应用程序不仅可以打印静态内容或转发您发送的数据。在这个例子中,我们将看看如何创建一个可以发布到Twitter账户的函数。

在我们看如何启动函数之前,我们需要为我们的函数生成密钥,以便对Twitter进行身份验证,然后发布到您的账户。为此,您需要以下内容:

Twitter账户

与账户注册的手机号码

名称*:MedialGlassesKubeless

描述:使用Kubeless测试发布到Twitter

回调URL:留空

开发者协议:同意协议

填写完上述信息后,点击“创建Twitter应用”按钮。创建应用程序后,您将被带到一个页面,允许您管理您的应用程序。页面上的一个选项卡是“密钥和访问令牌”;点击这个选项卡将显示您的消费者密钥(API密钥)和消费者秘钥(API秘钥)—请记下这些信息。

在页面底部,您将有一个按钮,允许您为您的帐户创建访问令牌和访问令牌秘钥;点击按钮将生成这些令牌—再次,请记下这些信息。

虽然以下示例将包含我生成的密钥,但它们已被撤销,您应该使用您自己的密钥。此外,由于它们允许对您的Twitter帐户进行读写访问,将它们存储在GitHub、Gists或其他版本控制软件等公开可访问的地方可能导致第三方未经您的许可就完全访问您的Twitter帐户。

现在我们已经配置了Twitter应用程序,并且拥有了发布推文所需的所有令牌,我们需要将它们添加到Kubernetes中。Kubernetes允许您定义秘密;这些是您的应用程序需要使用的API密钥和令牌等变量。但是,您可能不希望将它们放在源代码控制下或嵌入到您的应用程序中,因为相同代码的各种部署使用不同的密钥与API进行交互—例如,代码的开发版本使用与生产版本不同的API凭据。

要添加前一节中记下的令牌,您只需要运行以下命令,用您的令牌和密钥替换大写的占位符:

$kubectlcreatesecretgenerictwitter\--from-literal=consumer_key=YOUR_CONSUMER_KEY\--from-literal=consumer_secret=YOUR_CONSUMER_SECRET\--from-literal=token_key=YOUR_TOKEN_KEY\--from-literal=token_secret=YOUR_TOKEN_SECRET对我来说,命令看起来像下面这样:

这样就创建了一个名为twitter的秘密,其中包含我们传递给命令的四个不同的键和令牌。您可以通过运行以下命令来列出这些秘密:

$kubectlgetsecret这将列出您的Kubernetes集群中的所有秘密,如下面终端输出所示:

这里有默认的Kubernetes服务账户令牌,包含三个项目,以及我们的twitter秘密,其中包含四个键和令牌。您也可以在Kubernetes仪表板中查看秘密:

从前面的屏幕截图中可以看出,您还可以通过单击眼睛图标来显示秘密。

现在我们的环境准备好了,我们可以部署函数了。为此,我们需要两个文件;第一个是requirements.txt文件,其中只包含两行:

python-twitterkubernetes==2.0.0requirements.txt文件让Python知道要与我们的代码一起部署的外部库。在我们的文件中,我们使用twitter库,以便可以轻松地发布推文,还使用kubernetes库来解码我们在上一节中创建的秘密。使用这些库意味着我们的代码非常简化,因为所有的繁重工作都发生在我们的核心函数之外。函数的代码如下:

importbase64importtwitterfromkubernetesimportclient,configconfig.load_incluster_config()v1=client.CoreV1Api()forsecretsinv1.list_secret_for_all_namespaces().items:ifsecrets.metadata.name=='twitter':consumer_key=base64.b64decode(secrets.data['consumer_key'])consumer_secret=base64.b64decode(secrets.data['consumer_secret'])token_key=base64.b64decode(secrets.data['token_key'])token_secret=base64.b64decode(secrets.data['token_secret'])api=twitter.Api(consumer_key=consumer_key,consumer_secret=consumer_secret,access_token_key=token_key,access_token_secret=token_secret)defhandler(context):msg=context.jsonstatus=api.PostUpdate(msg['tweet'])将此内容放入名为tweet.py的文件中。与以前一样,requirements.txt和tweet.py文件都可以在GitHub存储库Chapter04/twitter/中找到。

部署函数的命令在部署命令中有一个附加项。由于我们现在正在加载外部库,我们需要让Kubeless知道我们想要使用requirements.txt文件,方法是添加--dependencies标志:

现在我们的函数已经部署,我们可以开始发推文了。要发送我们的第一条推文,您只需运行以下命令:

$kubelessfunctioncalltwitter--data'{"tweet":"TestingtwitterfunctionfromKubeless!"}'您将不会收到任何反馈,但如果您转到您的Twitter帐户,您应该会看到这条推文:

您还可以使用Postman发送推文。首先,通过运行以下命令创建一个Ingress路由:

$kubelessingresscreate--functiontwittertwitter-ingress$kubelessingresslist这将创建路由并给我们提供访问函数所需的主机:

现在我们可以打开Postman,并且像以前一样配置它,但是这个文件将以下内容作为发布内容:

{"tweet":"TestingtwitterfunctionfromKubelessusing@postmanclient!"}单击发送将发布推文,并且与使用kubelessfunctioncall命令调用函数时一样,不会给我们任何反馈:

检查Twitter应该会显示第二条推文,这次提到了@postmanclient。您可以在以下URL查看我的两条测试推文:

再次,在继续下一部分之前,我们应该删除我们的函数并整理一下:

回到第一章,无服务器景观,我们安装了Serverless框架来部署AWSLambda函数;无服务器也适用于Kubeless。

如果你还没有安装无服务器,这里是如何在我们正在涵盖的三个操作系统上安装它的快速回顾。

尽管已经尽一切努力确保以下说明适用于所有支持的平台,但由于插件所需的一些依赖项的兼容性问题,Kubeless无服务器插件在基于Windows的操作系统上的运行成功程度有所不同。

对于macOS10.13HighSierra,运行以下命令使用Homebrew安装Node.js:

$brewinstallnode如果你正在使用Windows10专业版,你可以通过运行Chocolatey来安装Node.js:

$chocoinstallnodejs最后,如果你使用的是Ubuntu17.04,你可以使用以下命令安装Node.js:

$serverlesslogin现在无服务器已安装,我们可以通过运行以下命令启动演示Kubeless函数:

$serverlesscreate--templatekubeless-python--pathnew-project$cdnew-project$npminstall如果你没有跟着做,运行这些命令会得到以下输出:

这安装了Kubeless无服务器插件并创建了定义我们函数的serverless.yml文件。其中包含以下内容:

service:new-projectprovider:name:kubelessruntime:python2.7plugins:-serverless-kubelessfunctions:hello:handler:handler.hello正如你所看到的,这段代码告诉无服务器我们正在使用Kubeless,并且它应该使用Kubeless插件。它还定义了一个名为hello的函数和处理程序。该函数可以在handler.py文件中找到。这包含以下代码,与我们在本章前面看过的hello-world示例非常相似:

importjsondefhello(request):body={"message":"GoServerlessv1.0!Yourfunctionexecutedsuccessfully!","input":request.json}response={"statusCode":200,"body":json.dumps(body)}returnresponse现在我们有了示例函数,我们可以通过运行以下命令部署服务:

$serverlessdeploy-v服务部署完成后,最后一步是部署函数本身。要做到这一点,请运行:

$serverlessdeployfunction-fhello使用无服务器本身来调用函数可能会导致以下错误,如果出现这种情况,不要担心:

您仍然可以使用Kubeless访问该函数:

$kubelessfunctionlist$kubelessfunctioncallhello--data'{"Kubeless":"Welcome!"}'这将返回预期的结果:

要删除示例函数,请运行以下命令:

$serverlessremove在完成本章之前,让我们看一个使用事件而不是HTTP的示例。在GitHub存储库的Chapter04/serverless-event/文件夹中,有一个监听事件的示例应用程序。

serverless.yml文件与之前的HTTP示例不同,除了处理程序外,还添加了一个包含触发器/主题的事件部分:

service:eventsprovider:name:kubelessruntime:python2.7plugins:-serverless-kubelessfunctions:events:handler:handler.eventsevents:-trigger:'hello_topic'handler.py文件可能包含迄今为止我们所看到的最简单的代码:

defevents(context):returncontext要启动示例,只需从Chapter04/serverless-event/文件夹中运行以下命令:

从前面的终端输出中可以看出,我们有一个PubSub类型和一个hello_topic主题。现在我们可以通过运行以下命令在hello_topic主题中发布事件:

$kubelesstopicpublish--topichello_topic--data'testinganevent!'$kubelesstopicpublish--topichello_topic--data'andanotherevent!'最后,我们可以通过运行日志来检查这两个事件是否已经被处理:

$serverlesslogs-fevents从以下输出中可以看出,事件已成功发布并由我们的测试函数处理:

在进入下一章之前,我们可以通过运行以下命令删除我们的KubelessKubernetes单节点集群:

$minikubedelete摘要在本章中,我们已经将Kubeless部署到了我们使用Minikube启动的单节点Kubernetes上。我们安装了Kubernetes命令行客户端和基于Web的界面。一旦集群部署并安装了工具,我们就在Kubeless安装上部署和执行函数。

在安装一个更有用的发布推文的函数之前,我们先安装了两个基本的测试函数。然后,我们看了一下如何使用Serverless框架与Kubeless进行交互。

在下一章中,我们将看一下一个名为Funktion的基于事件的框架。

在我们继续在公共云中启动Kubernetes集群之前,我们将再看一个本地示例;这次我们将看一下Funktion。我们将涵盖以下主题:

介绍Funktion

安装和配置Funktion

使用Funktion运行我们的第一个函数

Twitter流

Funktion的标语将其描述为基于事件的KubernetesLambda编程。从表面上看,Funktion似乎与Kubeless和我们在前几章讨论过的其他无服务器框架非常接近。然而,它有自己的特色,使其与我们正在研究的其他框架有所不同。

我们正在研究的大多数无服务器函数都支持两种基本事件类型:

HTTP:这是通过标准HTTP请求将数据传递给框架的地方;通常数据将被发布为JSON对象

为了让您了解ApacheCamel和因此Funktion支持的一些事件流,以下是一些亮点:

AWS-SNS支持与亚马逊的简单通知服务(SNS)一起使用

Braintree允许与Braintree支付网关服务进行交互

etcd允许您与etcd键值存储进行交互

Facebook开放了完整的FacebookAPI

GitHub允许您监听来自GitHub的事件

Kafka-像Kubeless一样,您可以订阅Kafka流

Twitter让您能够监听标签、帖子等

还有许多其他服务,如LinkedIn、Slack、各种SQL和NoSQL数据库、来自AWS的S3的文件服务、Dropbox和Box等等。

所有这些选择使其与我们一直在研究和将要研究的其他框架相比,成为一个非常好的选择。

Funktion部署由几个不同的组件组成。首先是一个函数;这就是代码本身,由KubernetesConfigMap管理。

单独的函数本身并不是很有用,因为它只存在于ConfigMap中。因此,我们需要一个运行时,一个在调用时执行函数的Kubernetes部署。当Funktion操作员(稍后会详细介绍)检测到添加了新函数时,将自动创建运行时。

接下来,我们有一个连接器;这是一个事件源的表示,就像我们在本节前面讨论的那些一样——它包含有关事件类型、配置(如API凭据)以及数据搜索参数的信息。

然后我们有流程;这是一系列步骤,可以从调用函数的连接器中消耗事件。

最后,我们有Funktion操作员。这是在Kubernetes中运行的一个pod,监视构成我们的Funktion部署的所有组件,如函数、运行时、连接器和流程。它负责创建提供Funktion功能的Kubernetes服务。

Funktion是开源的,根据Apache许可证2.0发布;它是由fabric8开发的,fabric8是RedHat的JBoss中间件平台的上游项目。fabric8本身是一个基于Docker、Kubernetes和Jenkins的面向Java的微服务平台。它也与RedHat自己的OpenShift平台很好地配合。

现在我们对Funktion与其他框架的区别有了一些背景了,我们可以看看如何在我们的单节点Kubernetes集群上安装它。

使用Funktion有三个步骤。首先,我们需要安装命令行。这是大部分部署和管理我们的Funktion部署的命令将被输入的地方。一旦命令行客户端安装完成,我们可以使用Minikube启动我们的单节点Kubernetes集群,然后使用FunktionCLI引导我们的环境。

与我们正在介绍的许多框架一样,Funktion是用Go语言编写的。这意味着我们的三个平台都有独立的可执行文件。

然而,在撰写本文时,无论是在macOS上使用Homebrew还是在Windows10专业版上使用Chocolatey,都没有可用的安装程序,这意味着我们将在所有三个平台上进行手动安装。

让我们从如何在macOS上安装开始。

在macOS上安装很简单,因为该项目已发布了未压缩的独立可执行文件。我们只需要下载正确的软件包并使其可执行。要做到这一点,请运行以下命令:

$funktionversionFunktion版本将返回如下:

如您所见,虽然安装过程非常简单,但软件包不在Homebrew中可用也有一个缺点。如果在Homebrew中可用,那么更新到较新版本将更容易,因为Homebrew会在您运行时负责检查和安装升级:

$brewupdate$brewupgrade目前,如果需要升级,您将不得不删除当前版本并下载新版本来替换它。

在Windows上安装Funktion命令行客户端的过程与macOS类似。首先,以管理员用户身份打开PowerShell窗口,方法是从任务栏中的PowerShell菜单中选择以管理员身份运行。一旦打开,您应该看到您在文件夹C:\WINDOWS\system32中;如果没有,请运行:

$cdC:\WINDOWS\system32一旦您在C:\WINDOWS\system32文件夹中,请运行以下命令:

同样,由于我们没有使用软件包管理器来安装Funktion,因此如果要升级,您将不得不删除旧的可执行文件,然后重复安装过程,并确保更新URL中的版本号以反映您所需的版本。

最后,我们有Ubuntu17.04。安装过程与我们为macOS执行的命令基本相同。但是,要确保我们下载正确的可执行文件,并且在/usr/local/bin文件夹的权限在操作系统之间略有不同时,我们还需要使用sudo命令:

$funktionversion你应该看到类似以下的内容:

现在我们在三个操作系统上都安装了命令行客户端,我们可以继续部署。

你可能已经注意到,我们再次发现自己处于一个位置,现在可以在任何操作系统上使用相同的命令。这意味着本章剩余的命令将能够在我们的三个目标操作系统上运行。

在使用Minikube启动我们的单节点Kubernetes集群之前,可以通过运行以下命令检查是否有任何更新。macOS10.13HighSierra用户可以运行:

$brewupdate$brewupgrade然后,要检查和更新Minikube,请运行以下命令,从以下开始:

$brewcaskoutdated这将向您呈现可以更新的软件包列表。如果Minikube在列表中,请运行以下命令:

$brewcaskreinstallminikubeWindows10专业版用户可以运行:

$chocoupgradeallUbuntu17.04用户需要检查第三章中的发布页面详细信息,在本地安装Kubernetes,删除旧的二进制文件,并使用更新的版本重复安装过程。

一旦您检查了Minikube的更新,可以通过运行以下命令启动您的集群:

$minikubestart根据第三章,在本地安装Kubernetes和第四章,介绍Kubeless功能,这将启动单节点Kubernetes集群,并配置您的本地Kubernetes客户端与其交互。如果您已经更新了Minikube,您可能还会注意到下载并安装了一个更新版本的Kubernetes:

如果你已经升级了Minikube,可以使用以下命令检查一切是否正常运行:

$minikubestatus$kubectlgetall$minikubedashboard现在我们的单节点Kubernetes集群已经重新启动运行,Funktion安装的最后阶段是引导部署。

安装Funktion非常简单,事实上,只需要一个命令:

$funktioninstallplatform这将给出以下输出:

一两分钟后,您应该能够运行:

$kubectlgetpods$kubectlgetdeployments上述命令将检查部署的状态:

您还应该能够在Kubernetes仪表板中看到Pods和Deployments:

运行以下命令应该返回一个空列表:

$funktiongetfunction这证明了Funktion命令行客户端可以连接到您新安装的Funktion部署并与其交互。

现在我们的Funktion部署已经运行起来了,我们可以看一下部署一个非常简单的helloworld示例。在支持本书的GitHub存储库中的/Chapter05/hello-world/src文件夹中,您会找到一个名为hello.js的文件。这个文件包含以下代码:

module.exports=function(context,callback){varname=context.request.query.name||context.request.body||"World";callback(200,"Hello"+name+"!!");};在/Chapter05/hello-world/文件夹中运行以下命令将使用上述代码创建我们的第一个函数:

$funktioncreatefn-fsrc/hello.js输出应该如下所示:

从终端输出中可以看出,这创建了一个名为hello的function。现在,我们运行以下命令:

$funktiongetfunction这应该返回一些结果。从以下输出中可以看出,我们现在可以看到NAME,PODS和URL列出:

我们可以运行以下命令来仅返回函数的URL,或在浏览器中打开它:

$funktionurlfnhello$funktionurlfnhello-o您应该看到以下结果:

打开的浏览器窗口显示如下。我相信您会同意这不是最令人兴奋的页面:

但它确实证明了我们的函数正在工作并显示内容。您可以通过运行以下命令来显示函数的日志:

$funktionlogsfunctionhello这将实时将日志内容流式传输到您的终端窗口。您可以通过刷新浏览器几次来查看,您应该看到您的页面请求与内部健康检查请求一起被记录。

现在我们已经创建了我们的第一个函数,我们可以安装一些连接器。要这样做,请运行以下命令:

$funktiongetflow您应该看到以下内容:

正如您所看到的,流程称为timer-foo1;我们在与其交互时需要使用此名称。例如,您可以通过运行以下命令来检查流程的日志:

$funktionlogsflowtimer-foo1或者在Kubernetes仪表板中,您可以找到名为timer-foo1的pod,并在那里检查日志:

通过运行以下命令检查函数的日志:

$funktionlogsfunctionhello您应该看到每五秒有一个来自用户代理为Apache-HttpClient/4.5.2的客户端的页面请求。这是计时器流程:

要删除流程,只需运行:

$funktiondeleteflowtimer-foo1这将删除运行连接器的pod,并且您的函数将停止接收自动请求。

返回Kubernetes仪表板,单击ConfigMaps应该显示Funktion创建的所有内容的列表。正如您所看到的,Funktion的大部分部分都有一个ConfigMap:

单击hello的ConfigMaps将显示类似以下页面的内容:

正如您所看到的,这包含了我们函数的代码,并且它已自动检测到它是用Node.js编写的,还有它是从src文件夹部署的。

在查看更高级示例之前,还有一件可能会让您感兴趣的事情,那就是与ChromeDev工具的集成。要做到这一点,请运行以下命令:

$funktiondebugfnhello这将在前台打开一个进程,并为您提供一个URL放入GoogleChrome中:

一旦您打开GoogleChrome并指向您的函数,您可以执行诸如直接在浏览器中编辑代码之类的任务:

要删除我们的hello函数,我们只需要运行:

$funktiondeletefunctionhello这应该让我们得到一个干净的安装,准备进行更高级的示例。

在上一节中我们安装了Twitter连接器,让我们看看如何配置它来拉取一些数据。首先,您可以通过运行以下命令查看连接器的所有可配置选项:

$funktioneditconnectortwitter-l你应该看到类似以下的终端输出:

如您所见,您可以配置代理,并提供accessToken、accessTokenSecret、consumerKey和consumerSecret。您应该从上一章中获得这些信息。如果没有,那么请使用第四章中的说明重新生成它们,介绍Kubeless功能。

就像我将用来演示您需要运行的命令的令牌和密钥一样,前面截图中列出的详细信息是默认的虚拟占位符详细信息,不是有效的。

要使用您自己的详细信息更新连接器,请运行以下命令,并确保用您自己的详细信息替换它们:

$funktioneditconnectortwitter\accessToken=1213091858-REJvMEEUeSoGA0WPKp7cv8BBTyTcDeRkHBr6Wpj\accessTokenSecret=WopER9tbSJtUtASEz62lI8HTCvhlYBvDHcuCIof5YzyGg\consumerKey=aKiWFB6Q7Ck5byHTWu3zHktDF\consumerSecret=uFPEszch9UuIlHt6nCxar8x1DSYqhWw8VELqp3pMPB571DwnDg您应该收到连接器已更新的确认。现在,我们可以启动使用Twitter适配器的流程。为此,我们应该运行以下命令:

$funktioncreateflow--nametwitsearch"twitter://searchtype=polling&keywords=kubernetes&delay=120s"$funktiongetflows我们将看到以下内容:

一旦您启动了pod,您可以通过运行以下命令来检查日志:

$funktionlogsflowtwitsearch或者通过在仪表板中查看twitsearchpod的日志:

如您所见,Camel正在打印包含单词Kubernetes的一系列推文。您的应用程序可以订阅此流,并对推文进行处理。最后,运行以下命令将删除流程:

$funktiondeleteflowtwitsearch然后,您可以使用minikubedelete命令删除您的Minikube机器。

在本章中,我们简要介绍了Funktion。我们安装了命令行客户端,然后将其安装在我们的单节点Kubernetes集群上。部署后,我们启动了一个测试函数,并与其交互,然后使用其中的一个事件流来搜索包含Kubernetes的推文。

在下一章中,我们将讨论如何将我们的Kubernetes集群从本地单节点扩展到托管在公共云上的多节点集群。

到目前为止,我们一直在本地机器上运行Kubernetes。这确实有一些缺点,其中之一是处理能力。我们将开始研究一些更复杂和强大的框架,因此我们需要一些额外的能力。因此,我们将尝试在几个不同的公共云上安装Kubernetes,每次使用不同的工具:

在DigitalOcean上启动Kubernetes

在AWS上启动Kubernetes

在MicrosoftAzure上启动Kubernetes

在Google云平台上启动Kubernetes

然后,我们将研究公共云提供商之间的差异,并尝试在其中一个平台上安装Kubeless。

我们将首先研究的公共云平台是DigitalOcean。DigitalOcean与我们将在接下来的章节中研究的三大云平台有所不同,因为它的功能较少。例如,在产品页面上,DigitalOcean列出了八个功能,而AWS产品页面列出了十八个主要领域,每个领域又分为六个或更多的功能和服务。

不要因此而认为DigitalOcean比我们在本章中将要研究的其他公共云提供商差。

DigitalOcean的优势在于它是一个非常简单易用的托管平台。通过其直观的API和命令行工具,支持服务和出色的管理界面,可以在不到一分钟内轻松启动功能强大但价格竞争力极强的虚拟机。

Droplets是DigitalOcean对其计算资源的术语。对于我们的Kubernetes,我们将启动三个Ubuntu17.04Droplets,每个Droplet配备1GB的RAM,1个CPU和30GB的SSD存储。

在撰写本文时,这个由三个Droplet组成的集群每月大约需要花费30美元才能保持在线。如果您打算在需要时保持在线,那么这三个Droplets每小时的费用将是0.045美元。

接下来,我们需要生成一个SSH密钥并将其上传到DigitalOcean。如果您已经有一个带有SSH密钥的帐户,可以跳过此任务。如果您没有密钥,请按照给定的说明操作。

如果您使用的是macOSHighSierra或Ubuntu17.04,则可以运行以下命令:

$ssh-keygen-trsa这将要求您选择一个位置来存储您新生成的私钥和公钥,以及一个密码。密码是可选的,但如果您的SSH密钥的私有部分落入错误的手中,它确实会增加另一层安全性:

生成密钥后,您需要记下密钥的公共部分。为此,请运行以下命令,并确保更新密钥路径以匹配您自己的路径:

$cat/Users/russ/.ssh/id_rsa.pub您应该看到类似以下的内容:

对于Windows10专业版用户来说,你很可能正在使用PuTTY作为你的SSH客户端。如果你没有PuTTY,你可以通过运行以下命令来安装它:

$chocoinstallputty一旦PuTTY安装完成,你可以通过运行以下命令打开PuTTYgen程序:

$PUTTYGEN.exe打开后,点击生成并按照提示在空白区域移动你的光标。一秒钟后,你应该会生成一个密钥:

如前面的截图所示,你可以选择添加一个密码,这将用于解锁你的密钥的私有部分;再次强调,这是可选的。

点击保存公钥,也保存私钥,并记下公钥的内容。

现在你已经为你的账户分配了一个SSH密钥,你可以使用它来创建你的Droplets,并且无需密码即可访问它们。要创建你的Droplets,点击屏幕右上角的创建按钮,然后从下拉菜单中选择Droplets。

在Droplet创建页面上有几个选项:

选择一个镜像:选择Ubuntu16.04镜像

选择一个大小:选择每月10美元的选项,其中包括1GB、1CPU和30GBSSD

添加块存储:保持不变

选择数据中心区域:选择离你最近的区域;我选择了伦敦,因为我在英国

选择附加选项:选择私人网络连接。

添加你的SSH密钥:选择你的SSH密钥

完成并创建:将Droplets的数量增加到3,现在保持主机名不变

填写完前面的部分后,点击页面底部的创建按钮。这将启动你的三个Droplets,并向你反馈它们创建过程的进度。一旦它们启动,你应该会看到类似以下页面的内容:

如你所见,我有三个Droplets,它们的IP地址,还有一条很好的激励性信息。现在我们可以开始使用kubeadm部署我们的Kubernetes集群。

$apt-getupdate$apt-getupgrade现在我们已经是最新的了,我们可以安装先决条件软件包。要做到这一点,请运行以下命令:

现在我们已经安装了先决条件,我们可以通过运行以下命令来添加Kubernetes存储库:

$apt-getupdate$apt-getinstallkubeletkubeadmkubectl安装完成后,您可以通过运行以下命令来检查已安装的kubeadm的版本:

$kubeadmversion现在我们已经安装了所需的一切,我们可以通过运行以下命令来引导我们的Kubernetes主节点:

完成后,您应该看到以下消息,但是带有您的令牌等:

记下底部的kubeadmjoin命令,我们很快会看到它。我们应该运行消息中提到的命令:

$mkdir-p$HOME/.kube$sudocp-i/etc/kubernetes/admin.conf$HOME/.kube/config$sudochown$(id-u):$(id-g)$HOME/.kube/config接下来,我们需要启用Pod网络。您可以选择几种选项,所有这些选项都为您的Kubernetes集群提供了多主机容器网络:

对于我们的安装,我们将使用WeaveNet。要安装它,只需运行以下命令:

如您所见,这使用了kubectl命令来部署pod网络。这意味着我们的基本Kubernetes集群已经运行起来了,尽管只在单个节点上。

为了准备其他两个集群节点,打开两者的SSH会话,并在两者上运行以下命令:

$kubeadmjoin--token0c74f5.4d5492bafe1e0bb9139.59.180.255:6443--discovery-token-ca-cert-hashsha256:3331ba91e4a3a887c99e59d792b9f031575619b4646f23d8fe2938dc50f89491您需要运行收到的命令,因为令牌将绑定到您的主节点。在两个节点上运行该命令,您应该会看到类似以下终端输出的内容:

一旦您在剩余的两个节点上运行了该命令,请返回到您的主节点并运行以下命令:

$kubectlgetnodes这应该返回您的Kubernetes集群中的节点列表:

要在macOSHighSierra或Ubuntu17.04上执行此操作,请运行以下命令,确保将IP地址替换为您的主节点的IP地址:

$scproot@139.59.180.255:/etc/kubernetes/admin.conf如果您使用的是Windows10专业版,您将需要使用诸如WinSCP之类的程序。要安装它,请运行以下命令:

$chocoinstallwinscp安装后,通过输入WINSCP.exe来启动它,然后按照屏幕提示连接到您的主节点并下载admin.conf文件,该文件位于/etc/kubernetes/中。

一旦您有了admin.conf文件的副本,您就可以在本地运行以下命令来查看您的三节点Kubernetes集群:

$kubectl--kubeconfig./admin.confgetnodes一旦我们确认可以使用本地的kubectl副本连接,我们应该将配置文件放在适当的位置,这样我们就不必每次使用--kubeconfig标志。要做到这一点,请运行以下命令(仅适用于macOS和Ubuntu):

$mv~/.kube/config~/.kube/config.mini$mvadmin.conf~/.kube/config现在运行以下命令:

$kubectlgetnodes这应该显示您的三个Droplets:

这是在低规格服务器上手动部署Kubernetes。在接下来的几节中,我们将看看如何在其他公共云中部署Kubernetes,首先是AWS。

我们可以使用几种工具在AWS上启动Kubernetes集群;我们将介绍一个叫做kube-aws的工具。不幸的是,kube-aws不支持基于Windows的机器,因此以下说明只适用于macOSHighSierra和Ubuntu17.04。

kube-aws是一个命令行工具,用于生成AWSCloudFormation模板,然后用于启动和管理CoreOS集群。然后将Kubernetes部署到CoreOS实例的集群中。

AWSCloudFormation是亚马逊的本地脚本工具,允许您以编程方式启动AWS服务;它几乎涵盖了所有AWSAPI。CoreOS是一个专注于运行容器的操作系统。它的占用空间极小,并且设计为可以在云提供商上直接进行集群和配置。

在第一章中,无服务器景观,我们看了一下创建Lambda函数。为了配置这个,我们安装了AWSCLI。我假设您仍然配置了这个,并且您配置的IAM用户具有管理员权限。您可以通过运行以下命令来测试:

$awsec2describe-instances这应该返回类似以下内容:

现在我们在正确的区域,点击密钥对选项,在左侧菜单的NETWORK&SECURITY部分下可以找到。页面加载后,点击导入密钥对按钮,然后像DigitalOcean一样,输入您的密钥对的名称,并在其中输入您的id_rsa.pub文件的内容。

接下来,我们需要一个AWSKMS存储。要创建这个,运行以下命令,确保根据需要更新您的区域:

$awskms--region=eu-west-1create-key--description="kube-awsassets"这将返回几个信息,包括一个Amazon资源名称(ARN)。记下这个信息以及KeyId:

接下来,我们需要一个AmazonS3存储桶。使用AWSCLI运行以下命令来创建一个,确保更新区域,并且使存储桶名称对您来说是唯一的:

现在我们已经导入了我们的公共SSH密钥,有了KMSARN和一个S3存储桶,我们只需要决定集群的DNS名称。

我将使用kube.mckendrick.io,因为我已经在AmazonRoute53DNS服务上托管了mckendrick.io。您应该选择一个可以在其上配置CNAME的域或子域,或者一个托管在Route53上的域。

现在我们已经掌握了基础知识,我们需要安装kube-aws二进制文件。要做到这一点,如果您正在运行macOSHighSierra,您只需要运行以下命令:

$brewinstallkube-aws如果您正在运行UbuntuLinux17.04,您应该运行以下命令:

在我们开始创建集群配置之前,我们需要创建一个工作目录,因为将会创建一些工件。让我们创建一个名为kube-aws-cluster的文件夹并切换到它:

$mkdirkube-aws-cluster$cdkube-aws-cluster现在我们在我们的工作目录中,我们可以创建我们的集群配置文件。要做到这一点,运行以下命令,确保用之前部分收集的信息替换值:

如果您没有使用Route53托管的域,删除--hosted-zone-id标志。

kube-awsinit\--cluster-name=kube-aws-cluster\--external-dns-name=kube.mckendrick.io\--hosted-zone-id=Z2WSA56Y5ICKTT\--region=eu-west-1\--availability-zone=eu-west-1a\--key-name=russ\--kms-key-arn="arn:aws:kms:eu-west-1:687011238589:key/2d54175d-41e1-4865-ac57-b3c40d0c4c3f"这将创建一个名为cluster.yaml的文件,这将是我们配置的基础:

接下来,我们需要创建将被我们的Kubernetes集群使用的证书。要做到这一点,请运行以下命令:

接下来,我们需要生成AWSCloudFormation模板。要做到这一点,请运行以下命令:

$kube-awsrenderstack这将在名为stack-templates的文件夹中创建模板:

在您的工作目录中运行ls应该会显示已创建的几个文件和文件夹:

最后,我们可以运行以下命令来验证并上传文件到我们的S3存储桶,记得用您自己的存储桶名称更新命令:

$kube-awsvalidate--s3-uris3://kube-aws-russ/kube-aws-cluster现在我们可以启动我们的集群。要做到这一点,只需运行以下命令,确保您更新存储桶名称:

$kube-awsup--s3-uris3://kube-aws-russ/kube-aws-cluster这将开始使用AWSCloudFormation工具启动我们的集群:

这个过程将需要几分钟;您可以在AWS控制台的命令行上查看其进度。要在控制台中查看它,请转到服务菜单并选择CloudFormation。一旦打开,您应该会看到列出的一些堆栈;选择其中一个,然后单击事件选项卡:

从事件和资源选项卡中可以看出,后台有很多事情正在进行。有:IAM角色、VPC和网络、EC2实例、负载均衡器、DNS更新、自动缩放组等正在创建。

一旦完成,您应该会看到三个CloudFormation堆栈,一个主要的称为kube-aws-cluster,另外两个嵌套堆栈,一个称为kube-aws-cluster-Controlplane,另一个称为kube-aws-cluster-Nodepool1。两个嵌套堆栈都将在其名称后附加一个唯一的ID。您将在命令行上收到集群已启动的确认:

在我们的工作目录中运行以下命令将列出AWSKubernetes集群中的节点:

要启动商店,我们需要从工作目录中运行以下命令:

$kubectl--kubeconfig=kubeconfig-nsock-shopgetpods等待每个pod获得运行状态,如下截图所示:

然后,我们应该能够访问我们的应用程序。要做到这一点,我们需要将其暴露给互联网。由于我们的集群在AWS中,我们可以使用以下命令启动一个弹性负载均衡器,并让它指向我们的应用程序:

$kubectl--kubeconfig=kubeconfig-nsock-shopexposedeploymentfront-end--type=LoadBalancer--name=front-end-lb要获取有关我们的负载均衡器的信息,我们可以运行以下命令:

正如您所见,应用程序正在端口8079上暴露,但我们无法完全看到弹性负载均衡器的URL。要获得这个,我们可以运行以下命令:

输入您的URL应该显示以下页面:

要删除SockShop应用程序,只需运行:

$kubectl--kubeconfig=kubeconfigdeletenamespacesock-shop这将删除我们创建的所有pod、服务和弹性负载均衡器。

让我们不要忘记,当集群正在运行时,它会花费我们的钱。要删除集群和CloudFormation脚本创建的所有服务,请运行以下命令:

我们还需要删除我们创建的S3存储桶和KMS;要做到这一点,请运行以下命令:

$awss3rbs3://kube-aws-russ--force$awskms--region=eu-west-1disable-key--key-id2d54175d-41e1-4865-ac57-b3c40d0c4c3f您可以从您在本节早期创建KMS时所做的备注中找到--key-id。

在第一章中,《无服务器景观》,我们看了微软AzureFunctions;然而,我们没有进展到比Azureweb界面更多的地方来启动我们的Function。要使用Azure容器服务(AKS),我们需要安装Azure命令行客户端。

值得一提的是,AKS目前不支持Windows10PowerShellAzure工具。但是,如果您使用Windows,不用担心,因为命令行客户端的Linux版本可以通过Azureweb界面获得。

Azure命令行工具可以通过macOSHighSierra上的Homebrew获得,这样安装就像运行以下两个命令一样简单:

$brewupdate$brewinstallazure-cliUbuntu17.04用户可以运行以下命令:

现在我们已经安装并连接到我们的账户的命令行工具,我们可以启动我们的Kubernetes集群。

首先,我们需要注册AKS服务。要做到这一点,运行以下命令:

$azprovidershow-nMicrosoft.ContainerService一旦看到registrationState为Registered,您就可以开始了。要启动集群,我们首先需要创建一个资源组,然后创建集群。目前,AKS在ukwest或westus2都可用:

$azgroupcreate--nameKubeResourceGroup--locationukwest$azakscreate--resource-groupKubeResourceGroup--nameAzureKubeCluster--agent-count1--generate-ssh-keys一旦您的集群启动,您可以运行以下命令配置您的本地kubectl副本以对集群进行身份验证:

$azaksget-credentials--resource-groupKubeResourceGroup--nameAzureKubeCluster最后,您现在可以运行以下命令,开始与您的集群进行交互,就像与任何其他Kubernetes集群一样:

您会注意到我们只有一个节点;我们可以通过运行以下命令添加另外两个节点:

您应该能够在AzureWeb界面中看到所有已启动的资源:

现在我们的集群中有三个节点,让我们启动SockShopdemo应用程序。

这些命令与我们之前运行的命令略有不同,因为我们不必为kubectl提供配置文件:

$kubectl-nsock-shopgetpods一旦所有的pod都在运行,您可以通过运行以下命令暴露应用程序:

要删除应用程序,我只需要运行:

$azaksdelete--resource-groupKubeResourceGroup--nameAzureKubeCluster$azgroupdelete--nameKubeResourceGroup删除后,转到AzureWeb界面,并手动删除任何其他剩余的资源/服务。我们接下来要看的下一个和最后一个公共云是GoogleCloud。

所有三个操作系统都有安装程序。如果您使用的是macOSHighSierra,则可以使用Homebrew和Cask通过运行以下命令安装GoogleCloudSDK:

$brewcaskinstallgoogle-cloud-sdkWindows10专业版用户可以使用Chocolatey并运行以下命令:

$chocoinstallgcloudsdk最后,Ubuntu17.04用户需要运行以下命令:

回到您的终端,现在应该会提示您创建一个项目。出于测试目的,请回答是(y)并输入一个项目名称。这个项目名称必须对您来说是唯一的,所以可能需要尝试几次。如果一开始失败,您可以使用以下命令:

$gcloudprojectscreateruss-kubernetes-cluster如您所见,我的项目名为russ-kubernetes-cluster。您应该在命令中引用您自己的项目名称。最后的步骤是将我们的新项目设置为默认项目以及设置区域。我使用了以下命令:

$gcloudconfigsetprojectruss-kubernetes-cluster$gcloudconfigsetcompute/zoneus-central1-b现在我们已经安装了命令行工具,我们可以继续启动我们的集群。

您可以使用单个命令启动集群。以下命令将启动一个名为kube-cluster的集群:

$gcloudcontainerclusterscreatekube-cluster当您第一次运行该命令时,可能会遇到一个错误,指出您的项目未启用Google容器API:

您可以通过按照错误中给出的链接并按照屏幕上的说明启用API来纠正此错误。如果您的项目没有与之关联的计费,您可能还会遇到错误:

一旦您启用了API并将您的项目链接到一个计费账户,您应该能够重新运行以下命令:

如您所见,kubectl的配置已经自动更新,这意味着我们可以运行以下命令来检查我们是否可以与新的集群通信:

您还应该能够在GoogleCloud网络界面的容器引擎部分看到您的集群:

现在我们的集群已经运行起来了,让我们再次启动SockShop应用程序。

与Azure一样,这次也不需要提供配置文件,所以我们只需要运行以下命令:

此外,在GoogleCloud网络界面中,单击发现与负载平衡还应该显示我们创建的负载均衡器:

单击界面中的链接,或将您的URL粘贴到浏览器中,应该会显示您熟悉的商店前台:

运行以下命令应该删除SockShop应用程序:

$kubectldeletenamespacesock-shop运行Kubeless在删除GoogleCloud三节点Kubernetes集群之前,让我们快速回顾一下Kubeless。要部署Kubeless,请运行以下命令:

$kubectlgetpods-nkubeless$kubectlgetdeployment-nkubeless$kubectlgetstatefulset-nkubeless您还可以在GoogleCloud网络界面的Google容器引擎部分检查工作负载和发现与负载平衡。一旦Kubeless部署完成,返回到本书附带的存储库中的/Chapter04/hello-world文件夹,并运行以下命令部署测试函数:

$kubectlgetfunctions$kubelessfunctionls您可以通过运行以下命令调用该函数:

此外,您可以使用以下命令公开该函数:

$kubectlexposedeploymenthello--type=LoadBalancer--name=hello-lb一旦负载均衡器创建完成,您可以运行以下命令确认IP地址和端口:

$kubectlgetserviceshello-lb一旦您知道IP地址和端口,您可以在浏览器中打开该函数,或者使用curl或HTTPie查看该函数:

现在我们已经使用SockShop应用程序测试了我们的集群,并部署了一个Kubeless函数,我们应该考虑终止我们的集群。

要删除集群,只需运行以下命令:

$gcloudcontainerclustersdeletekube-cluster它会问你是否确定,回答是,一两分钟后,您的集群将被删除。再次,您应该在GoogleCloud网页界面上仔细检查您的集群是否已被正确删除,以免产生任何意外费用。

在本章中,我们看了四个云提供商。前两个,DigitalOcean和AWS,目前不支持原生的Kubernetes,因此我们使用kubeadm和kube-aws来启动和配置我们的集群。对于MicrosoftAzure和GoogleCloud,我们使用他们的命令行工具来启动他们原生支持的Kubernetes服务。我相信您会同意,在撰写本文时,这两项服务比我们看过的前两项要友好得多。

一旦集群运行起来,与Kubernetes交互是一个相当一致的体验。当我们发出诸如kubectlexpose的命令时,我们实际上并不需要为集群运行的位置做出任何让步:Kubernetes知道它在哪里运行,并使用提供商的原生服务来启动负载均衡器,而无需我们干预任何特殊设置或考虑。

您可能会想知道为什么我们没有在DigitalOcean上启动SockShop应用程序。由于机器的规格相当低,应用程序运行非常缓慢,并且DigitalOcean是我们看过的四个提供商中唯一一个不支持Kubernetes当前不支持提供商的原生负载均衡服务。我相信这将在未来几个月内得到纠正。

此外,您可能会感到惊讶,AWS上没有原生的Kubernetes经验。在撰写本文时是这种情况;然而,有传言称自从AWS加入了云原生基金会后,他们正在努力开发原生的Kubernetes服务。

在下一章中,我们将介绍ApacheOpenWhisk,这是最初由IBM开发的开源无服务器云平台。

在本章中,我们将看看ApacheOpenWhisk。虽然不严格是一个仅限于Kubernetes的项目,比如Kubeless和Fission(这些将在下一章中介绍),但它可以部署并利用Kubernetes。

我们将看三个主要主题:

ApacheOpenWhisk概述

使用Vagrant在本地运行ApacheOpenWhisk

在Kubernetes上运行ApacheOpenWhisk

让我们首先了解更多关于OpenWhisk。

ApacheOpenWhisk是一个开源的无服务器云计算平台,旨在以与本书其他章节中涵盖的所有工具类似的方式工作。ApacheOpenWhisk最初是IBM公共云服务Bluemix的FunctionsasaService部分,现在仍然是。

它在2016年12月发布了普遍可用版本。随着宣布的新闻稿中有一句来自Santander集团平台工程和架构负责人LuisEnriquez的引用,他是IBMCloudFunctions的一位客户,Luis说:

“微服务和容器正在改变我们构建应用程序的方式,但由于无服务器,我们可以进一步推动这种转变,OpenWhisk为我们提供了处理强烈任务和工作负载意外高峰的即时基础设施,并且是我们转向实时和事件驱动架构的关键构建块。”

你可能已经注意到,这听起来很像AWS和MicrosoftAzureFunctions的Lambda——IBM的服务与竞争对手的区别在于IBM已经将OpenWhisk提交给了Apache孵化器,这是所有外部开发项目成为Apache软件基金会努力的一部分的入口。

Apache软件基金会成立于1999年,是一个慈善组织,负责监督和管理超过350个开源软件项目的开发和管理,这是为了公共利益。

那么为什么IBM要这样做呢?嗯,IBM不仅是Apache软件基金会的金牌赞助商,将其FunctionsasaService提供开源化对他们来说是有意义的,因为它是唯一一个可以避免供应商锁定的公共云提供商,因为你可以在本地或自己的硬件或虚拟机上运行ApacheOpenWhisk。

这使您可以自由地在任何地方运行和部署ApacheOpenWhisk。但是,如果您想像Santander集团一样进行规模化运行,那么您可以选择在IBM支持的企业级公共云上运行它。

我们首先将研究在本地运行ApacheOpenWhisk。我们将通过使用VirtualBox和Vagrant来实现这一点。

在启动本地ApacheOpenWhisk服务器之前,我们需要安装由HashiCorp开发的Vagrant。我能描述Vagrant的最好方式是作为一个开源的虚拟机管理器,您可以使用易于遵循的文本配置文件编写机器配置。

安装Vagrant非常简单。在macOS10.13HighSierra上,我们可以使用Homebrew和Cask:

$brewcaskinstallvagrant如果您正在运行Windows10专业版,您可以使用Chocolatey并运行以下命令:

$chocoinstallvagrant最后,如果您正在运行Ubuntu17.04,您可以通过运行以下命令直接从Ubuntu核心存储库安装Vagrant:

$sudoapt-getupdate$sudoapt-getinstallvagrant请注意,Ubuntu提供的版本可能会比使用Homebrew和Chocolatey安装的版本稍微滞后;但是对于我们的目的,这不应该造成任何问题。

您可以通过运行以下命令测试Vagrant安装:

所有这些都是使用以下配置定义的:

Vagrant.configure("2")do|config|config.vm.box="ubuntu/xenial64"end如果您打开Vagrantfile,您会注意到有很多配置选项,比如RAM和CPU分配,网络和脚本,这些脚本在虚拟机成功启动后执行。您可以运行以下命令以SSH连接到Vagrant虚拟机:

$vagrantssh如果您正在运行Windows10专业版,则需要安装SSH客户端。当您执行上述命令时,Vagrant将为您提供一些选项。

运行以下命令将关闭您的虚拟机并将其删除:

我还建议通过运行清除您的工作文件夹:

$cd../$rm-rfvagrant-test现在我们已经安装了Vagrant,并且快速查看了如何启动和与虚拟机交互,我们现在可以使用它来启动我们自己的本地安装ApacheOpenWhisk。

正如我们已经提到的,ApacheOpenWhisk附带一个Vagrantfile,其中包含从头开始部署本地ApacheOpenWhisk安装的所有命令。要下载ApacheOpenWhisk存储库并部署虚拟机,请运行以下命令:

正如您所看到的,它只有将近200行,这与上一节中我们测试Vagrantfile的三行有很大不同。Vagrantfile使用bash脚本和Ansible的组合来启动、安装和配置我们的ApacheOpenWhisk虚拟机。

在过程结束时,它将执行一个基本的helloworld检查,如下控制台输出所示:

在我们继续之前,请注意以wskpropertyset命令开头的输出。我们将需要这个来配置本地客户端,接下来我们将看到如何安装。

由于您的本地安装使用自签名SSL证书,当在浏览器中打开时,您可能会收到警告。您需要接受这些警告才能继续访问该网站。此过程因浏览器而异,因此您需要按照屏幕上的提示进行操作。

要在macOS10.13HighSierra上安装客户端,我们只需要运行以下命令:

要在Windows10专业版上下载,请运行以下命令。我建议从IBM下载,以避免自签名SSL证书和PowerShell的问题。为此,首先以管理员用户身份打开PowerShell窗口。您可以通过从任务栏中的PowerShell菜单中选择以管理员身份运行来执行此操作。打开后,您应该看到您在C:\WINDOWS\system32文件夹中;如果不是,则运行以下命令:

$wskhelp最后,在Ubuntu17.04上,您需要运行以下命令:

$wskhelp现在我们已经安装了客户端,我们需要对我们的安装进行身份验证。为此,请运行您在上一节末尾做的笔记中的命令,减去--namespaceguest部分。对我来说,这个命令是这样的:

$wskpropertyset--apihost192.168.33.13--auth`vagrantssh--catopenwhisk/ansible/files/auth.guest`如果您不是从启动机器的文件夹运行vagrantssh命令,该命令将失败,因为它将无法找到您的机器配置。现在,您的本地客户端已对本地安装的ApacheOpenWhisk进行了身份验证,我们可以通过运行以下命令执行与自动安装相同的helloworld命令:

$wsk-iactioninvoke/whisk.system/utils/echo-pmessagehello--result这应该返回以下终端输出的消息hello:

现在我们有了本地客户端,我们可以尝试下载和执行另一个示例。

现在,我们可以部署一个更复杂的解决方案,而不仅仅是使用内置的echo实用程序返回消息。与我们之前使用的helloworld脚本类似,我们将部署一个使用Node.js编写的函数,该函数接受输入并将其显示回给我们。

首先,让我们创建一个工作目录:

functionmain(args){varmsg="youdidn'ttellmewhoyouare."if(args.name){msg=`hello${args.name}!`}return{body:`

${msg}

`}}现在我们有了要部署的函数,首先我们需要创建一个包,然后创建一个暴露给Web的操作:

$wsk-ipackagecreate/guest/demo$wsk-iactioncreate/guest/demo/hellohello.js--webtrue现在我们已经创建了包和操作,您的终端应该看起来像以下内容:

这意味着您可以使用浏览器在以下URL调用您的函数:

您应该会看到以下页面:

您可以通过在macOS或Ubuntu上使用HTTPie来查看更多信息,方法是运行以下命令:

您可以通过运行以下命令列出软件包和操作,并删除它们:

完成本地安装后,您可以运行以下命令来停止和销毁虚拟机:

$vagrantdestroy请记住,您必须在openwhisk/tools/vagrant/文件夹中运行此命令,否则Vagrant将无法找到您的虚拟机配置。

现在我们已经在本地安装并与ApacheOpenWhisk进行了交互,让我们看看如何在公共云中的Kubernetes上部署它。

现在我们知道如何与ApacheOpenWhisk进行交互以及其基本概念,我们可以考虑在Kubernetes集群之上部署一个副本。为此,我将通过运行以下命令在GoogleCloud中启动一个三节点集群:

$gcloudcontainerclusterscreatekube-cluster一旦集群运行起来,您可以通过运行以下命令来检查是否可以看到三个节点:

现在我们有了我们的Kubernetes,我们可以继续进行ApacheOpenWhisk的部署。

在开始部署之前,所有在Kubernetes上部署ApacheOpenWhisk所需的配置都可以在GitHub上找到,因此我们应该通过运行以下命令克隆存储库。

$kubectlcreatenamespaceopenwhisk现在我们可以通过启动CouchDB来开始我们的部署。

要部署CouchDB,请从openwhisk-kube文件夹内运行以下命令:

$kubectlapply-fkubernetes/couchdb/couchdb.yml这将启动一个使用couchdb.yml文件中定义的参数运行CouchDB的pod。您可以通过获取pod的名称来检查部署是否正常。您可以通过运行以下命令来执行此操作:

$kubectl-nopenwhiskgetpods一旦您获得了名称,对我来说是couchdb-1146267775-v0sdm,然后您可以运行以下命令,确保更新pod的名称为您自己的:

$kubectl-nopenwhisklogscouchdb-1146267775-v0sdm在日志输出的最后,您应该看到以下消息:

现在我们的CouchDBpod正在运行,我们可以继续下一个,即Redis。

要启动Redispod,我们只需要运行以下命令:

$kubectlapply-fkubernetes/redis/redis.ymlAPI网关接下来我们有API网关;通过运行以下命令来启动它:

$kubectlapply-fkubernetes/apigateway/apigateway.ymlZooKeeper现在我们可以使用以下命令启动ApacheZooKeeper:

$kubectlapply-fkubernetes/zookeeper/zookeeper.yml卡夫卡现在是时候启动另一个Apache项目,Kafka了:

$kubectlapply-fkubernetes/kafka/kafka.yml此时,我们应该仔细检查我们启动的所有pod是否正在运行。要做到这一点,请运行以下命令:

$kubectl-nopenwhiskgetpods您应该看到couchdb,redis,apigateway,zookeeper和kafka的pod,所有这些pod都在没有记录重启并且READY列中为1/1运行:

接下来是控制器。这与我们部署的其他pod略有不同,因为它是以有状态的方式部署的:

$kubectlapply-fkubernetes/controller/controller.yml您应该看到已创建了一个StatefulSet而不是一个部署。

再次部署的下一个pod将是一个StatefulSet而不是一个部署。在部署pod之前,我们需要对kubernetes/invoker/invoker.yml文件进行轻微更改。这是因为,默认情况下,OpenWhisk假定您正在运行Ubuntu作为基本操作系统,而GoogleCloud不是。

要做到这一点,请在您选择的文本编辑器中打开kubernetes/invoker/invoker.yml并删除以下代码块:

-name:apparmorhostPath:path:"/usr/lib/x86_64-linux-gnu/libapparmor.so.1"还有另一个关于apparmor的参考资料需要删除。这次是在文件底部:

-name:apparmormountPath:"/usr/lib/x86_64-linux-gnu/libapparmor.so.1"一旦删除了引用apparmor的两个代码块,您可以通过运行以下命令部署invoker:

部署的最后一部分是NGINX容器。对于这个容器,我们需要做更多的工作,因为我们需要为我们的集群生成证书。为了生成证书,我们需要使用OpenSSL。这在Windows机器上默认情况下不安装,因此您可以使用以下命令使用Chocolatey安装OpenSSL:

$chocoinstallopenssl.light一旦安装了OpenSSL,您可以通过运行以下命令生成证书:

$mkdir-pcerts$opensslreq-x509-newkeyrsa:2048-keyoutcerts/key.pem-outcerts/cert.pem-nodes-subj"/CN=localhost"-days365一旦我们有了证书,我们需要使用kubernetes/nginx中的nginx.conf文件创建一个configmap。为此,请运行以下命令:

$kubectl-nopenwhiskcreateconfigmapnginx--from-file=kubernetes/nginx/nginx.conf现在我们需要上传生成的证书和密钥作为secret:

$kubectl-nopenwhiskcreatesecrettlsnginx--cert=certs/cert.pem--key=certs/key.pem一旦它们被上传,我们可以通过运行以下命令启动NGINXpod:

现在我们已经部署了所有的pod,您应该使用以下命令再次检查它们是否都在运行:

正如您所看到的,一切都在运行。只要数量不增加,您可以忽略任何重启。

现在我们已经部署了所有的pod,我们可以开始与我们的部署进行交互。首先,我们需要找出NGINXpod的外部IP地址。您可以通过运行以下命令找到有关pod的信息:

$kubectl-nopenwhiskdescribeservicenginx这是输出:

正如您所看到的,虽然端口是暴露的,但它们只在节点本身上暴露。由于节点位于私有地址上,我们将无法从本地客户端访问它们。要在外部暴露端口,我们需要创建一个负载均衡服务,运行以下命令来执行此操作:

$kubectl-nopenwhiskexposeservicenginx--type=LoadBalancer--name=front-end这将启动一个负载均衡器并暴露三个端口:80、443和8443。您可以通过运行以下命令找到外部IP地址的详细信息:

$kubectl-nopenwhiskdescribeservicefront-end在输出中,您会找到一行,上面写着LoadBalancerIngress,后面跟着一个IP地址:

正如您从先前显示的示例输出中看到的,我有一个IP地址35.188.204.73。这将被用作我与之交互的API端点。

现在我们已经获得了安装的IP地址,我们可以继续通过运行以下命令来配置认证令牌,确保您使用自己安装的IP地址进行更新:

这与前一节中的helloworld完全相同,所以我不会详细介绍。只需切换到您拥有hello.js文件的文件夹,并运行以下命令:

$wsk-ipackagecreate/guest/demo$wsk-iactioncreate/guest/demo/hellohello.js--webtrue一旦您运行了创建包和操作的命令,您将能够访问URL。对我来说,它是以下内容:

这显示了我们期望看到的页面:

再次,我们可以通过运行HTTPie来看到更多:

正如您所看到的,一旦您使用提供的文件部署了ApacheOpenWhisk,使用它是一个非常一致的体验。

在完成本章之前,我们应该删除我们的Kubernetes集群。要做到这一点,请运行以下命令:

在本章中,我们稍微偏离了目标,看了一下ApacheOpenWhisk。我们使用标准虚拟机部署了一个本地副本,然后我们转向部署到在GoogleCloud上运行的Kubernetes集群。

正如您所看到的,一旦部署完成,与ApacheOpenWhisk的交互是一致的体验,我们能够在两个安装中部署我们简单的hello-world应用程序,而无需进行任何修改。

虽然Kubernetes对ApacheOpenWhisk的支持仍处于起步阶段,但我们的偏离表明,不仅是为Kubernetes设计的框架,就像我们在前几章中看到的工具一样,它们将在Kubernetes之上运行,并提供一致的体验,而无需将您锁定在单一供应商或技术中。

在下一章中,我们将看到可能是最成熟的Kubernetes函数作为服务提供:Fission。

接下来我们将看一下Fission。Fission是一个快速增长的,基于Kubernetes的无服务器框架,而且在我们之前章节中看到的技术中,可能是最多才多艺的。在本章中,我们将涵盖:

谁构建了Fission?

安装先决条件

在本地安装、配置和运行Fission

命令概述

在云中安装、配置和运行Fission

部署一些示例Fission应用程序

到本章结束时,我们将在两个不同的目标环境中安装Fission,并且还将启动多个应用程序。

Fission是由Platform9开发的开源无服务器应用程序。它旨在在Kubernetes之上运行,并利用一些核心的Kubernetes功能。Platform9是一家托管服务提供商,其核心业务是部署、管理和支持专门从事OpenStack和Kubernetes的开源云。

OpenStack是一组开源组件,构成了一个完全功能的基础设施即服务产品。它提供计算、网络、块存储、对象存储、编排,甚至容器服务等功能。

该项目的目标是为多个不同的硬件供应商提供支持,从普通的x86硬件到专门的存储解决方案,使最终用户能够构建自己的AWS和MicrosoftAzure风格的产品。

随着AWSLambda和AzureFunctions等服务成熟到现在几乎在大多数企业中都很普遍,Platform9看到了提供自己的函数即服务的机会。

作为一家专门从事复杂开源解决方案的公司,他们为他们向社区贡献自己的工作是有意义的,因此他们以Apache许可证发布了Fission。

这可能看起来像一个奇怪的决定。然而,就像我们在上一章中介绍的OpenWhisk一样,Platform9为他们的客户以及任何想要开始部署函数即服务(FaaS)的人提供了一个坚实的基础来构建他们的应用程序。他们不仅给了人们在任何地方部署他们的工作负载的自由,还能够为安装和Fission平台提供支持服务。

Helm是Kubernetes的一个包管理器,是CloudNativeComputingFoundation的一部分,Bitnami、Google、Microsoft和Helm社区都为其开发做出了贡献。

要在macOSHighSierra上安装Helm,我们可以使用Homebrew;只需运行:

$brewinstallkubernetes-helm如果您正在运行UbuntuLinux,则可以使用安装脚本下载并安装Helm:

安装Helm的下一步需要您拥有一个运行中的Kubernetes集群,因为这是它的启动位置。我将在本章后面包括安装Helm的服务器组件Tiller的说明。

我们需要安装的最后一个命令行工具是Fission本身的工具。您可以通过在macOSHighSierra上运行以下命令来安装它:

运行以下命令应该显示当前安装的版本:

如前所述,我们还没有安装Tiller,因此我们可以安全地忽略关于无法连接到它的错误。

现在我们已经安装了先决条件,我们可以开始创建我们的第一个函数。为此,我们将使用Minikube。要启动单节点集群,我们只需要运行以下命令:

$minikubestart$kubectlgetnodes这应该启动您的Minikube集群,并确认您的本地版本已重新配置以与其通信:

一旦我们的集群运行并且可访问,我们需要通过安装Tiller来完成Helm安装。要做到这一点,我们需要运行以下命令:

$helminit您应该会看到类似以下消息:

Helm现在已配置好,我们可以使用它来部署Fission的远程组件。可以通过运行以下命令来完成:

Helm的输出非常详细。它将为您提供它创建的所有内容的概述,以及开发人员包含的任何附加说明。

输出的这部分包含了部署的基本细节:

NAME:lopsided-foxLASTDEPLOYED:SatDec910:52:192017NAMESPACE:fissionSTATUS:DEPLOYED接下来,我们会得到有关在Kubernetes中部署了什么的信息,从服务账户开始。这些提供运行pod的身份服务。这些允许Fission的各个组件与Kubernetes进行接口交互:

==>v1/ServiceAccountNAMESECRETSAGEfission-builder11mfission-fetcher11mfission-svc11m然后是绑定。这些为集群提供基于角色的身份验证(RBAC):

==>v1beta1/ClusterRoleBindingNAMEAGEfission-builder-crd1mfission-crd1mfission-fetcher-crd1m接下来是服务本身:

==>v1/ServiceNAMETYPECLUSTER-IPEXTERNAL-IPPORT(S)AGEpoolmgrClusterIP10.0.0.13480/TCP1mbuildermgrClusterIP10.0.0.21280/TCP1minfluxdbClusterIP10.0.0.248086/TCP1mnats-streamingNodePort10.0.0.1614222:31316/TCP1mstoragesvcClusterIP10.0.0.15780/TCP1mcontrollerNodePort10.0.0.5580:31313/TCP1mrouterNodePort10.0.0.10680:31314/TCP1m现在我们有了部署详情。您可能会注意到,如下所示,一些pod仍在启动,这就是为什么它们显示为零可用的原因:

==>v1beta1/DeploymentNAME.DESIREDCURRENTUP-TO-DATEAVAILABLEAGEtimer11111mpoolmgr11111minfluxdb11111mnats-streaming11111mcontroller11111mmqtrigger11111mrouter11101mstoragesvc11101mkubewatcher11111mbuildermgr11101m接下来,我们有了部署和服务的pod:

==>v1/Pod(related)NAMEREADYSTATUSRESTARTSAGElogger-zp65r1/1Running01mtimer-57f75c486f-9ktbk1/1Running21mpoolmgr-69fcff7d7-hbq461/1Running11minfluxdb-c5c6cfd86-wkwrs1/1Running01mnats-streaming-85b9898784-h6j2v1/1Running01mcontroller-5f964bc987-mmfrx1/1Running01mmqtrigger-c85dd79f7-vj5p71/1Running01mrouter-7cfff6794b-gn5pw0/1ContainerCreating01mstoragesvc-58d5c8f6-bnqc70/1ContainerCreating01mkubewatcher-6d784b9987-5wwhv1/1Running01mbuildermgr-7ff69c8bb-pvtbx0/1ContainerCreating01m然后我们有了命名空间:

==>v1/NamespaceNAME.STATUSAGEfission-builderActive1mfission-functionActive1m现在我们有了秘密。这些只是用于正在使用的数据库:

==>v1/SecretNAMETYPEDATAAGEinfluxdbOpaque21m我们接近尾声了:持久存储索赔。您可以看到,由于我们在本地启动,它只是使用VM上的一个文件夹,而不是创建外部存储:

==>v1/PersistentVolumeClaimNAME.STATUSVOLUMECAPACITYACCESSMODESSTORAGECLASSAGEfission-storage-pvcBoundpvc-082cf8d5-dccf-11e7-bfe6-080027e101f58GiRWOstandard1m现在我们有了角色绑定:

==>v1beta1/RoleBindingNAMEAGEfission-function-admin1mfission-admin1m最后,我们有了守护进程集:

==>v1beta1/DaemonSetNAMEDESIREDCURRENTREADYUP-TO-DATEAVAILABLENODESELECTORAGElogger111111m现在我们已经看到了我们的Fission安装的所有Kubernetes元素的概述,我们得到了如何与安装进行交互的说明。

笔记分为三个部分;第一部分提供了如何安装Fission命令行客户端的说明。由于我们已经在本章的前一部分中涵盖了这一点,我们可以忽略这一步。

接下来,在第二部分中,我们得到了关于需要设置的环境变量的说明,以便我们的本地Fission客户端可以与我们的Fission安装进行交互。要设置这些变量,请运行以下命令:

第三部分包含了一步一步的说明,说明如何运行一个helloworld函数;让我们现在来运行这些步骤。

首先,我们需要创建一个环境。为此,我们使用以下命令:

现在我们已经创建了环境,我们需要一个要部署的函数。运行以下命令(仅适用于macOS和Linux)来下载helloworld示例:

module.exports=asyncfunction(context){return{status:200,body:"Hello,world!\n"};}如您所见,这与我们在早期章节中运行的示例并没有太大不同。现在我们已经下载了一个函数,我们可以使用以下命令部署它:

$fissionfunctioncreate--namehello--envnodejs--code/tmp/hello.js我们快要完成了;最后一步是创建一个到我们函数的路由。要做到这一点,使用以下命令:

$fissionroutecreate--methodGET--url/hello--functionhello现在我们应该能够通过发出HTTP请求来调用我们的函数。您可以使用以下命令中的任一个来触发我们的函数:

现在我们已经有了一个基本的应用程序在运行,让我们来创建一些更复杂的东西。Fission附带了一个演示应用程序,充当留言板。您可以在伴随本书的GitHub存储库中的/Chapter08/guestbook/文件夹中找到我们将要部署的文件。

$kubectlcreate-fredis.yaml您可以从以下截图中看到,这创建了一个namespace、deployment和service。

现在我们需要创建一个环境来启动我们的函数。由于应用程序是用Python编写的,让我们运行以下命令:

$fissionenvcreate--namepython--imagefission/python-env前面命令的输出显示在以下截图中:

$fissionfunctioncreate--nameguestbook-get--envpython--codeget.py--url/guestbook--methodGET$fissionfunctioncreate--nameguestbook-add--envpython--codeadd.py--url/guestbook--methodPOST前面命令的输出可以在以下截图中看到:

您会注意到,用于添加函数的命令与我们在上一节中用于启动helloworld示例的命令有些不同。在之前的示例中,我们既添加了函数,又创建了路由。您可能还注意到,虽然我们创建了两个函数,但它们都绑定到了相同的路由/guestbook。现在不讨论这个问题,让我们启动应用程序并与之交互。

要打开留言板,请运行以下命令:

如果收到内部服务器错误,请不要担心,只需刷新页面并重新提交。查看页面的HTML源代码,您可能会注意到表单操作配置为将POST提交到/guestbook:

Add如果您查看我们用于创建两个函数的命令,您会注意到两者都附有一个方法。guestbook-add,运行add.py,使用了POST方法,如下面的代码所示:

每当您的浏览器请求页面时,它都会发送一个GET请求。在我们的情况下,所有对/guestbook的GET请求都被路由到guestbook-get函数,这是get.py代码:

##HandlesGET/guestbook--returnsalistofitemsintheguestbook#withaformtoaddmore.#fromflaskimportcurrent_app,escapeimportredis#Connecttoredis.Thisisrunonlywhenthisfileisloaded;as#longasthepodisalive,theconnectionisreused.redisConnection=redis.StrictRedis(host='redis.guestbook',port=6379,db=0)defmain():messages=redisConnection.lrange('guestbook',0,-1)items=[("

  • %s
  • "%escape(m.decode('utf-8')))forminmessages]ul="
      %s
    "%"\n".join(items)return"""

    Guestbook

    Add
    %s"""%ul从上面的代码中可以看出,这会连接到Redis数据库,读取每个条目,将结果格式化为无序的HTML列表,然后将列表插入到水平线下方(
    )。

    在我们将Fission安装移到公共云之前,我们应该更多地了解一下命令客户端。有几个顶级命令可用于管理我们的函数和路由。

    我们已经使用过这个命令,所以不需要详细介绍。fissionfunctioncreate命令有几个选项;最常见的是:

    --name:这表示我们想要给我们的函数取什么名字。

    --env:这表示我们想要在哪个环境中部署我们的函数。更多关于环境的内容请参见下一节。

    --code:我们希望部署的代码的路径或URL。

    --url:我们希望我们的函数在哪个URL上可用。

    --method:我们在前面URL上访问我们的函数的方式;这里的选项有GET、POST、PUT、DELETE、HEAD—如果您不使用--method但使用--url,它将始终默认为GET。

    正如我们在留言板示例中已经看到的,fissionfunctioncreate命令看起来会像下面这样:

    $fissionfunctioncreate\--nameguestbook-get\--envpython\--codeget.py\--url/guestbook\--methodGET获取选项这个选项相当简单;运行fissionfunctionget将显示您选择的函数的源代码。它接受一个输入:--name。这是您希望显示源代码的函数的名称。

    运行以下命令将显示helloworld函数的源代码:

    以下两个命令有点类似:

    $fissionfunctionlist这个命令将列出当前安装的函数。列表中包括函数的名称、唯一ID以及函数部署的环境:

    如果我们已经知道函数的名称,并且想要提醒自己它正在运行的环境,或者需要它的UID,那么我们可以使用fissionfunctiongetmeta命令,并传递函数的名称:

    虽然目前没有任何视图,但您可以使用fissionfunctionlogs命令查看函数的日志。您可以传递一些不同的选项:

    --name:这是您希望查看日志的函数的名称,这总是必需的

    --follow:保持流打开,日志实时显示

    --detail:添加更多详细输出

    使用上述选项,命令将看起来像下面这样:

    $fissionfunctionlogs--detail--follow--namehello然而,正如前面提到的,目前没有太多可看的。

    fissionfunctionupdate命令部署函数的更新版本。它使用与fissionfunctioncreate命令相同的选项。例如,如果我们想要更新我们的helloworld函数以使用不同的源,我们将运行以下命令:

    $fissionfunctionupdate\--namehello\--envnodejs\--codehello-update.js\删除命令我们要看的最后一个命令是fissionfunctiondelete。这个命令相当不言自明。它删除函数,只接受一个参数,那就是--name。

    在使用fissionfunctiondelete时请小心;它不会以任何方式提示您,当您按下Enter时,您的函数将被删除。

    要删除helloworld函数,例如,我们只需运行以下命令:

    下一个顶级命令是environment。正如我们已经看到的,环境是我们的函数运行的地方,它们还定义了我们的函数在哪种语言中执行。在撰写本文时,Fission支持Node.js、Go、Python、PHP、Ruby、Perl和.NETC#。

    fissionenvironmentcreate命令是我们已经使用过的一个命令。例如,当我们创建guestbook应用程序时,我们需要一个Python环境来运行我们的应用程序,所以我们运行了以下命令:

    $fissionenvironmentcreate\--namepython\--imagefission/python-env图像的完整列表、要使用的URL和用于创建图像的Dockerfile如下:

    与函数命令一样,环境也有list和get命令,它们的工作方式也相同。

    $fissionenvironmentlist运行上一个命令将列出所有配置的环境。

    $fissionenvironmentget--namenodejs运行上一个命令将获取命名环境的详细信息。

    delete命令再次按预期工作(请记住它会在没有警告的情况下删除):

    $fissionenvironmentdelete--namenodejs此外,如果您的环境中有函数,它也将在没有警告的情况下被删除。但是,您的函数将保留,直到您手动删除它们。任何尝试调用没有环境的函数都将导致内部服务器错误。

    现在我们知道了在本地运行Fission时启动和交互所涉及的内容,让我们看看在云中启动Kubernetes,然后配置Fission在那里运行。

    在本节的其余部分,我将仅提供macOSHighSierra和Ubuntu17.04主机的说明,因为它们与我们将要运行的命令具有更高的兼容性。

    我将使用以下命令在GoogleCloud中启动我的Kubernetes:

    $gcloudcontainerclusterscreatekube-cluster前述命令的输出可以在以下截图中看到:

    一旦启动,最多需要大约5分钟,您可以使用以下方法检查您的集群是否按预期运行:

    $kubectlgetnodes前述命令的输出可以在以下截图中看到:

    现在我们的三节点集群已经运行起来了,并且我们的本地Kubernetes客户端正在与之交互,我们可以再次运行以下命令来部署Helm的Kubernetes端:

    $helminit这将返回以下消息:

    现在我们已经准备好了Helm,我们可以继续启动Fission。

    与之前一样,我们将使用Helm来安装Fission。在本地安装Fission和在GoogleCloud、MicrosoftAzure或AWS等公共云上安装Fission之间唯一的区别是,我们不会使用--setserviceType=NodePort选项,而是直接运行以下命令:

    您可能会注意到,这次您的安装有一个不同的名称:

    NAME:orange-sharkLASTDEPLOYED:SunDec1013:46:022017NAMESPACE:fissionSTATUS:DEPLOYED此名称用于在整个过程中引用安装,如您从GoogleCloudWeb控制台的工作负载页面中看到的屏幕截图所示:

    在控制台中,点击“发现和负载均衡”将显示分配给您的安装的所有外部IP地址。由于我们传递了NodePort选项,因此已创建了外部负载均衡器:

    在控制台中查看的最后一件事是存储页面。如您所见,外部块存储已创建并附加到您的安装中。这与我们在本地启动时不同,因为存储实际上是我们单台机器的存储:

    回到命令行,你会注意到,Helm再次给了我们关于如何完成本地Fission客户端配置的指令。然而,由于我们没有使用Minikube,这次的指令略有不同。

    这次设置FISSION_URL和FISSION_ROUTER变量的命令使用kubectl来查询我们的安装,以找出负载均衡器的外部IP地址:

    $echo$FISSION_URL$echo$FISSION_ROUTER这应该会给你类似以下的输出:

    现在我们已经安装了Fission,并且我们的本地命令行客户端已配置为与我们的基于云的安装进行交互,我们可以通过运行以下命令快速重新运行helloworld示例:

    一旦启动,你可以使用以下命令之一来调用该函数:

    正如你已经看到的,就像我们所看到的所有技术一样,一旦安装,与公共云中的Fission交互和使用与在本地运行时并无不同。你真的不需要太在意外部访问等等,因为Fission和Kubernetes都已经为你解决了这个问题。

    在我们继续更高级的示例之前,让我们快速再次启动我们的guestbook应用程序。要做到这一点,切换到存储库中的/Chapter08/guestbook/文件夹,然后运行以下命令:

    在我们结束本章之前,让我们看一些在Fission中运行的示例代码,首先是一个天气检查器。

    在存储库的/Chapter08/weather/文件夹中,你会找到weather.js。这是一个简单的Node.js函数,用于查询Yahoo天气API以返回给定位置的当前天气:

    $fissionenvcreate--namenodejs--imagefission/node-env$fissionfunctioncreate--nameweather--envnodejs--codeweather.js--url/weather--methodPOST$fissionroutecreate--methodGET--url/weather--functionweather如果你已经在终端输出中看到了我们最初为helloworld示例创建并运行的环境,那么第一个命令可能会导致错误:

    现在我们已经部署了我们的函数,可以通过运行以下两个命令之一来快速测试它:

    这正是代码的预期行为。正如你所看到的,它返回了一个400错误和我们预期的消息。通过运行以下命令之一提供位置(我使用了英格兰诺丁汉)应该会告诉你天气情况:

    在这个例子中,我们将在当前Kubernetes安装的默认命名空间中每次创建或删除服务时发布一条消息。这些消息将通过名为Slack的Webhook发布到一个名为Slack的群组消息服务中。

    Slack是一个在线协作工具,允许团队在其中与聊天机器人和其他人进行交互。它提供免费和付费的服务,以及一个详尽的API供你的应用程序连接到你的聊天室。

    一旦你进入了你的工作空间,点击屏幕左上角的工作空间名称,然后从下拉列表中选择“管理应用程序”。这将带你进入Slack的应用程序目录。在这里,在页面顶部的搜索框中输入IncomingWebHooks,选择结果,然后点击“添加配置”按钮。

    记下这一点,因为我们需要用它来更新代码。正如你在下面的代码中所看到的,你也可以在/Chapter08/slack/仓库中找到,第三行需要用你的Webhook详细信息进行更新:

    该行应该类似于以下内容:

    constslackWebhookPath="/services/T8F3CR4GG/B8FNRR3PC/wmLSDgS0fl5SGOcAgNjwr6pC";//Somethinglike"/services/XXX/YYY/zZz123"确保文件名为kubeEventsSlack.js,一旦你的Webhook详细信息在代码中,我们可以使用以下命令创建和启动函数:

    $fissionfunctioncreate--namekubeslack--envnodejs--codekubeEventsSlack.js函数创建后,我们需要创建一些东西来触发它。以前,我们一直在使用HTTP调用来调用函数。不过这一次,我们希望在我们的Kubernetes集群中发生某些事情时触发函数。为此,我们需要创建一个观察。

    为了做到这一点,运行以下命令:

    作为我们Fission部署的一部分,有一个名为kubewatcher的服务。默认情况下,Fission使用这个服务来通过观察KubernetesAPI来帮助管理自身,但也向最终用户公开。用于创建之前观察的命令创建了一个观察者,它每次在默认命名空间中对服务进行更改时调用我们的函数(--functionkubeslack)。我们还可以设置一个观察,以查找对pods、deployments等的更改,通过更改类型:

    现在我们需要在默认命名空间中启动一个服务。为此,切换到/Chapter03/文件夹并运行以下命令:

    $kubectlapply-fcli-hello-world.yml然后,通过运行以下命令删除服务:

    如果你检查Slack,你应该会看到两条消息,确认一个名为cli-hello-world的服务已被添加和删除:

    你应该几乎实时地看到这种情况发生,你可能还会看到有关在默认命名空间内启动其他服务的消息。

    接下来,也是最后一个例子,我们要看的是一个二进制环境。这个环境与我们一直在看的环境不同,因为它不包含编程语言。相反,我们将部署一个安装和配置名为cowsay的Unix工具的bash脚本。代码如下,并且位于/Chapter08/whale/文件夹中:

    也许你会想,APK是什么,cowsay又是什么?由于部署到Fission环境中的容器运行的是AlpineLinux,我们需要使用Alpine软件包管理器(APK)来安装我们代码运行所需的必要软件包。

    cowsay是一个Unix命令,它会在一个来自牛的对话气泡中重复你给它的任何输入,因此得名cowsay。我们将安装Docker自己的版本cowsay,它使用的是鲸鱼而不是牛。要部署二进制函数,我们首先需要创建环境:

    $fissionenvcreate--namebinary--imagefission/binary-env现在我们可以部署函数并创建POST和GET路由,以便我们可以访问它:

    $fissionfunctioncreate--namewhalesay--envbinary--deploywhalesay.sh--url/whale--methodPOST$fissionroutecreate--methodGET--url/whale--functionwhalesay上述命令的输出如下截图所示:

    现在我们已经部署了我们的函数,我们可以使用以下之一来访问它:

    你可能会注意到对话框中没有任何内容;那是因为我们需要POST一些东西。与之前的示例不同,我们启动的函数将简单地重复我们发布的任何内容。因此,如果我们POST一个JSON对象,它将返回JSON对象。因此,我们将只发布纯文本:

    现在,你可能会认为这似乎是一个相当愚蠢的例子。然而,我们在这里所做的是获取HTTP请求的内容,并将其发布到Linux二进制文件中,然后使用我们发布的内容执行它。然后,我们通过HTTP请求返回运行命令的输出。

    此时,您可能希望终止/关闭您已经启动以测试Fission的任何Kubernetes集群。

    在本章中,我们已经研究了Fission。我们使用Helm进行了安装,并在本地和GoogleCloud上部署了它。我们还启动了几个测试应用程序,一些基本的,一些调用第三方服务来发布和返回信息。在安装和配置示例应用程序的过程中,我希望您开始看到Fission的用处以及它和其他无服务器技术如何集成到您自己的应用程序中。

    当我开始写这一章时,我希望包括一些关于Fission工作流和FissionUI的部分。然而,在写作时,这两个附加组件都无法正常工作。现在,不要误会,Fission是一种强大且易于使用的技术;然而,它非常新,并且仍在开发中,就像Kubernetes一样——这意味着在代码基础变得更加稳定之前,新版本中会有破坏性的更新。

    例如,我们安装的Fission版本0.4.0是因为在写作时,最新版本的Kubernetes1.8删除了ThirdPartyResources功能,并用CustomResourceDefinitions替换,这意味着旧版本的Fission将无法在当前版本的Kubernetes上运行。

    我们将在剩下的章节中研究Kubernetes的发布周期以及这可能对您产生的影响。

    在本章中,我们将看到:

    什么是OpenFaaS,由谁制作?

    使用Minikube在本地安装OpenFaaS

    Dockerswarm是Docker自己的集群技术;它允许您将运行DockerEngine的一些主机连接在一起。从表面上看,Dockerswarm与Kubernetes非常相似。然而,当你深入研究这两种技术的工作原理时,你会发现它们不仅工作方式不同,而且设计目的也不同。

    OpenFaaS可能是功能最丰富的函数即服务提供商,它支持Dockerswarm,因此很合理地,软件的Kubernetes版本最终会发布——这个Kubernetes版本被称为faas-netes,它在2017年7月进行了第一次提交。

    与其查看Dockerswarm上的OpenFaaS并对比在Kubernetes和Dockerswarm上运行服务,我们将直接深入并在Kubernetes上安装OpenFaaS。就像我们涵盖的所有工具一样,我们需要一个命令行客户端,所以我们将从安装它开始。

    OpenFaaS命令行客户端适用于我们的三个操作系统。让我们逐个安装它,从macOSHighSierra开始。

    正如你可能已经猜到的那样,我们将使用Homebrew来完成这个任务。要安装客户端,只需运行以下命令:

    $brewinstallfaas-cli对于Ubuntu17.04,可以使用OpenFaaSCLI安装脚本来安装CLI,您可以通过运行以下命令直接从GitHub运行:

    $curl-sLcli.openfaas.com|sudosh如果您运行的是旧版本,此脚本还将更新已安装的faas-cli版本。

    要在Windows10专业版上安装CLI,首先以管理员用户身份打开PowerShell窗口;您可以通过从任务栏中的PowerShell菜单中选择以管理员身份运行来执行此操作。一旦打开,您应该看到您在C:\WINDOWS\system32文件夹中,如果没有,那么运行以下命令:

    $cdC:\WINDOWS\system32一旦您在C:\WINDOWS\system32文件夹中,您可以通过运行以下命令下载OpenFaaSCLI:

    安装完成后,您应该能够运行以下命令来确认已安装的CLI的版本号:

    接下来,我们需要在本地安装Docker。虽然我在本节开头说我们不会在Dockerswarm上安装,但OpenFaaS仍然使用DockerEngine,所以我们需要在本地安装它。

    如果您正在运行Ubuntu17.04,可以通过运行以下命令使用Docker的安装脚本来安装Docker:

    $curl-fsSLget.docker.com-oget-docker.sh$sudoshget-docker.sh要在macOSHighSierra上安装Docker,可以使用Homebrew和Cask进行安装,运行:

    $brewcaskinstalldocker对于Windows10专业版用户,您可以使用Chocolatey并运行:

    $chocoinstalldocker-for-windows安装了DockerformacOS和DockerforWindows之后,您需要打开Docker应用程序来完成安装。如果不这样做,Docker将无法启动,我们稍后在本章中将使用Docker的示例也将无法工作。首次启动需要几分钟,因为它需要下载和配置一个小型虚拟机。

    现在我们已经安装了OpenFaaSCLI,我们可以继续使用Minikube启动单节点Kubernetes集群。要做到这一点,请运行以下命令:

    $minikubestart这将启动集群并配置我们的本地KubernetesCLI与之通信,除非您安装了Windows10专业版,然后您可能会看到以下消息:

    DockerforWindows安装的一部分启用了Hyper-V,正如我们在第三章中发现的,本地安装Kubernetes,当我们最初安装Minikube时,您不能同时运行VirtualBox和Hyper-V。为了解决这个问题,我们需要配置Minikube使用Hyper-V来支持虚拟化,而不是VirtualBox。

    为此,打开Hyper-VManager,选择VirtualSwitchManager,然后创建一个新的外部虚拟交换机。如下截图中所示,将其命名为minikube,并确保选中“允许管理操作系统共享此网络适配器”复选框:

    创建了虚拟交换机后,重新启动您的机器。一旦您的机器恢复在线,以管理员权限打开一个PowerShell窗口,并运行以下命令启动单节点Kubernetes集群:

    $minikubestart--vm-driver=hyperv--hyperv-virtual-switch=minikube在Hyper-VManager中,您应该能够看到您的minikube虚拟机的状态为Running,以及列为MobyLinuxVM的Docker虚拟机:

    现在您应该可以继续进行其余的指令了。

    现在我们已经启动了集群,我们需要安装OpenFaaS组件。我们将使用Helm来进行安装。如果您在上一章没有安装Helm,请参考那里的安装说明。与Helm安装一样,我们需要初始化它,这将安装服务器端组件Tiller。要做到这一点,请运行以下命令:

    $helminit现在我们在本地单节点Kubernetes集群上配置了Helm,我们需要从GitHub下载faas-netes代码库的副本。为此,请运行以下命令之一:

    下载后,我们可以使用以下命令使用Helm安装OpenFaaS:

    一两分钟后,您可以通过运行输出末尾的命令来检查安装的状态:

    $kubectl--namespace=defaultgetdeployments-l"release=openfaas,app=openfaas"您应该看到类似以下终端输出的内容:

    现在我们已经安装并可用OpenFaaS,我们可以尝试启动一个helloworld示例。

    与我们涵盖的其他服务一样,我们将运行一个快速的helloworld示例。这将让您了解OpenFaaS和其他工具之间的区别。我们还将找出为什么需要安装Docker。首先,运行以下命令:

    $mkdirhello$cdhello$faas-clinew--langpythonhello这将创建一个名为hello的文件夹,然后在其中创建一个名为hello.yml的文件和一些文件夹:

    在文本编辑器中打开hello.yml将显示以下内容:

    编辑后,运行以下命令:

    $faas-clibuild-fhello.yml这将在本地构建一个包含/hello文件夹中代码的容器,使用您本地的DockerEngine安装:

    现在我们已经构建了容器镜像,您可以通过运行以下命令来查看:

    现在我们可以通过运行以下命令将图像推送到我们的DockerHub帐户:

    我们可以启动我们的函数,但是首先我们需要将MinikubeVM的IP地址放入一个变量中,这样当我们运行OpenFaaSCLI时,它就知道要连接到哪里:

    我们可以通过运行以下命令来调用该函数:

    $echotest|faas-cliinvokehello--gateway$gw这应该返回单词test:

    我们还可以通过运行以下命令来检查函数的状态:

    如您所见,我们有一个正在运行的函数副本,并且已被调用一次。在我们进入下一节之前,再运行几次该函数。

    OpenFaaS带有基于Web的用户界面,可以通过在macOS和Ubuntu上运行以下命令来访问:

    $minikubeservicegateway-external这将打开OpenFaaSWebUI,在那里您应该看到我们在上一节中创建的hello函数。选择该函数,在请求正文表单字段中输入一些文本,然后点击调用将调用该函数,如下截图所示:

    OpenFaaSUI还包括一个商店,您可以直接将社区策划的函数部署到您的OpenFaaS安装中。要访问商店,请单击“部署新函数”按钮,然后您将看到可以部署的函数列表:

    选择mememachine函数,然后点击DEPLOY按钮。部署后,您应该在hello函数下看到一个名为mememachine的函数,选择它,在请求正文表单字段中输入以下内容:

    一两秒后,将下载一个文件,打开它后,您应该看到类似以下截图的内容:

    当我们第一次推出OpenFaaS时,您可能已经注意到其中一个部署被称为Prometheus。

    这是记录我们在整个章节中一直在调用的OpenFaaS网关的一些基本统计信息;您可以通过运行以下两个命令之一来打开Prometheus(请记住,open在Windows上不起作用):

    gateway_function_invocation_total单击“执行”按钮后,您将看到一个图表,其中详细说明了每个函数被调用的次数,以及每个函数调用的HTTP状态:

    从上面的图表中可以看出,当我运行mememachine函数时出现了一些错误,因为镜像大小太大,导致函数崩溃。还有很多其他指标被捕获。我建议您点击一下,看看一些图表。

    完成OpenFaaS安装后,可以通过运行以下命令来删除安装:

    $minikubestop$minikubedelete摘要OpenFaaS是一个快速增长的函数即服务平台,正如前面提到的,它得到了很多社区支持。它的独特之处在于它与Docker本地交互,用于构建和推送镜像到DockerHub,而我们之前使用的其他工具是使用Kubernetes将我们的函数注入到容器和运行时中。

    这就是能够轻松分发容器镜像供OpenFaaS使用的优势,正如我们通过mememachine示例和OpenFaaS商店中的其他函数所演示的。

    在本章中我们没有做的一件事是在公共云中启动Kubernetes集群并部署OpenFaaS。其中一个原因是,为了能够访问它,我们必须通过公共IP地址使其对我们的主机机器可用,这将使我们的安装暴露给世界。在下一章中,我们将讨论在公共云中运行我们的Kubernetes集群时的安全考虑,以及其他事项。

    在上一章的最后,我们提到了保护我们的无服务器安装的问题,以及开箱即用的安全性可能存在的缺陷。在本章中,我们将直面这个问题,讨论在部署Kubernetes上的无服务器函数服务时应该注意的事项,以及如何最好地监视您的集群。

    我们将研究:

    安全最佳实践

    您如何监视您的Kubernetes集群?

    让我们从讨论安全性开始。

    例如,我希望最终用户能够运行一个脚本,通过直接的HTTP请求,由网页或移动应用程序调用我的无服务器函数之一。但是,我不希望同一用户能够访问我的Kubernetes仪表板,例如。

    现在,这可能看起来是一个非常明显的例子,但是,正如我们在过去几年中所看到的,开箱即用的配置并不总是考虑到这个最基本的安全要求。MongoDB就是一个很好的例子。

    在2017年1月、6月和9月,有几家主要新闻媒体报道,大约有99,000个MongoDB安装暴露在互联网上;这些安装要么没有打补丁,要么配置不当。这导致第三方访问、复制和删除了其中的数据。

    之前发推文的研究人员NiallMerrigan在另一条推文中指出,在一个早晨,受损的MongoDB安装数量从12,000增加到了大约27,000。

    那么,这与保护我们的无服务器函数有什么关系呢?嗯,要回答这个问题,我们必须首先看一下MongoDB问题的根本原因。

    许多受攻击的MongoDB版本最初被配置为绑定到0.0.0.0,这意味着服务附加到服务器上的所有IP地址。如果您的MongoDB安装是在仅在私有网络上运行的服务器上启动,这就不是问题,但是被攻击的安装并非如此,它们是在公共云中托管的,其中一些只提供外部IP地址。

    现在,你可能会想,访问数据库肯定需要某种身份验证吧?嗯,你错了;在MongoDB仍然在所有网络接口(0.0.0.0)上监听的时候,身份验证是一个额外的配置步骤。这意味着,根据网站Shodan在2015年7月的数据,公共互联网上共有595.2TB的MongoDB数据暴露在外,并且没有进行身份验证。

    此外,你读对了日期,这是2015年的一个问题,很多安装仍然没有修补和配置正确。

    那么,我们如何避免在我们的Kubernetes和服务器功能服务安装中出现这些基本配置问题呢?让我们先看看Kubernetes本身。

    Kubernetes默认情况下是相当安全的。提供Kubernetes的两家云服务提供商,GoogleCloud和MicrosoftAzure,工作方式类似。

    一个管理节点部署在您的节点旁边;这个管理节点控制整个集群,并且默认情况下暴露给公共互联网和云服务提供商。我们可以通过使用以下命令启动一个集群来测试未经身份验证的用户看到的内容:

    $gcloudcontainerclusterscreatekube现在,默认情况下,此命令将启动集群,包括管理节点。用于验证您的本地kubectl副本与集群的所有证书都是在云上生成的,一旦集群启动,它将配置kubectl以获取连接所需的所有信息。如果您查看配置文件,可以在~/.kube/config中找到,您应该会看到类似以下内容:

    $kubectlgetnodes节点将显示如下:

    现在,打开您的~/.kube/config文件,并从certificate-authority-data部分中删除证书。这基本上会创建一个无效的证书,这意味着当您运行以下命令时,您将收到一个错误:

    $kubectlgetnodes错误将显示如下:

    因此,除非您有正确证书的副本,否则无法连接到集群。不用担心,您仍然可以通过运行以下命令访问您的证书:

    $gcloudcontainerclustersget-credentialskube您将看到以下内容:

    这个命令将连接到您的GoogleCloud帐户,下载详细信息,并使用证书更新您的~/.kube/config文件。您可以通过运行以下命令测试新下载的凭据:

    $kubectlcluster-info这将返回有关所有终端的详细信息:

    您可能会注意到列表中的最后一个URL是用于Kubernetes仪表板的。那么它是如何保护的呢?

    User"system:anonymous"cannotgetservices/proxyinthenamespace"kube-system".:"Nopolicymatched.\nUnknownuser\"system:anonymous\""这很好,因为这正是我们想要看到的——我们不希望未经身份验证的用户能够直接访问我们的仪表板。但是,我们如何访问它呢?我们没有用户名和密码,只有一个证书——即使我们有用户名和密码,我们会在哪里输入它们,考虑到我们从未被提示进行任何身份验证?

    Kubernetes有一个内置的代理服务器。启动时,代理服务器使用证书连接到您的Kubernetes集群。一旦连接,通过代理传递的所有流量都经过身份验证,您将能够使用服务。要启动代理,我们只需要运行以下命令:

    $kubectlproxy您将看到代理启动如下:

    这将在前台启动代理进程。从前面的终端输出中可以看到,代理正在本地机器的8001端口上监听。我们只需要替换URL的公共部分并将其放入浏览器中。所以在我的情况下,我更新如下:

    我改为如下所示:

    这将直接带您进入仪表板:

    到目前为止,我们已经证明了GoogleCloud上的Kubernetes配置是安全的。MicrosoftAzure集群以类似的方式工作,例如,我们运行以下命令来更新一旦集群部署完成后的本地凭据:

    $azaksget-credentials--resource-groupKubeResourceGroup--nameAzureKubeCluster在使用kubeadm和kube-aws部署时,证书会生成并复制到我们的配置文件中。

    因此,到目前为止,我们已经学到了,默认情况下Kubernetes强制执行基于证书的身份验证来保护您的安装,这意味着您必须付出相当大的努力来错误配置您的安装,以至于您的安装暴露给世界。然而,这有一个例外。这与您的安装无关;它更多地涉及您如何管理kubectl配置文件。

    永远不要在任何地方发布它(例如,将其提交到GitHub,或与同事共享)。如果它落入错误的手中,那么不仅有人拥有您的证书副本,他们还拥有您的集群其他信息,这意味着他们只需将其放置在本地机器上,就可以自由地开始启动应用程序。此外,由于大多数基于云的Kubernetes安装可以访问您的云提供商来启动支持服务,如负载均衡器、存储,以及可能的额外节点,您可能会发现自己面临相当大的账单,以及一个受损的集群。

    所以,现在我们知道我们的Kubernetes集群应该是安全的,那么我们所看到的无服务器函数服务呢?

    我们已经在我们的本地Kubernetes集群和云上安装并连接了我们的每个服务。到目前为止,我们还没有真正考虑过如何保护它们——这是我们在上一章末提出的问题。

    以下部分将讨论每个工具在其默认配置中的安全性以及此配置可能给您带来的潜在风险。我不会详细讨论如何保护每个工具,但在适当的情况下,我会提供链接到文档。

    让我们从OpenFaaS开始。我仍然在运行我的GoogleCloud集群,所以我将使用前一章中克隆的faas-netes文件夹中的以下命令在那里部署OpenFaaS:

    $kubectlapply-f./faas.yml,monitoring.yml如您所见,这次我只使用了kubectl而不是helm。我们可以通过运行以下命令来检查部署的服务:

    $kubectlgetservices这将返回以下内容:

    需要注意的一件事是,默认情况下OpenFaaS使用NodePort而不是负载均衡器来公开网关服务。没问题,你可能会想;我们可以使用以下命令来找到部署的名称并公开它:

    $kubectlgetdeployments现在我们知道部署被称为网关,我们可以运行:

    $kubectlexposedeploymentgateway--type=LoadBalancer--name=gateway-lb一两分钟后,运行以下命令应该给我们提供外部IP地址和端口:

    $kubectlgetservices结果将如下所示:

    在OpenFaaSGitHub存储库上有关使用代理服务(如Traefik和Kong)的说明。

    使用OpenFaaS还存在另一个潜在的安全问题,如果您已经是Docker用户,这应该是您熟悉的问题。由于OpenFaaS使用Docker镜像和DockerHub作为其主要交付方法,因此在推送镜像时需要小心,因为镜像可能潜在地包含密码详细信息、API凭据、自定义代码和其他您可能不希望通过公共容器镜像存储库访问的信息。解决此问题的方法是使用私有存储库或私有Docker注册表。

    接下来,让我们来看看Kubeless。为了在我的GoogleCloudKubernetes集群中部署最新版本,我运行了以下命令:

    $kubectlgetservices-nkubeless如您从以下终端输出中所见,没有服务被公开暴露:

    到目前为止,一切都很顺利。让我们快速启动一个测试函数并将其暴露出来。在/Chapter04/hello-world/文件夹中,我运行了以下命令:

    $kubectlgetfunction$kubelessfunctionls$kubelessfunctioncallhello运行以下命令将该函数暴露给世界:

    $kubectlgetservices到目前为止,我们实际上并没有做任何事情来锁定我们的安装,那么它有多安全呢?对于这个问题的简短答案是非常安全,但是默认安装的Kubeless比默认安装的OpenFaaS更安全的原因是什么?

    从表面上看,这两种技术在架构上是相似的;它们的服务器组件都部署在我们的Kubernetes集群上,并且我们使用本地机器上的命令行界面与这些组件进行交互。例如,我们为Kubeless使用了以下命令:

    Kubeless确切知道我们的集群在哪里,更重要的是,它在需要访问时进行身份验证。由于Kubeless是一个本地的Kubernetes框架,而不是安装在Kubernetes之上,它正在集成到我们的集群中,并添加额外的功能——在这种情况下是函数——并且正在使用其他Kubernetes技术,比如kubectl和自定义资源定义,来根据需要将我们函数的代码注入到运行时中,这意味着一切都包含在我们的Kubernetes集群中,与之的所有交互都是安全的。

    这可以通过从~/.kube/config文件中删除证书,然后尝试列出函数来进行演示。您应该会看到以下错误:

    所有这些都意味着您的Kubeless安装默认情况下是安全的。

    Funktion,像Kubeless一样,默认情况下是安全的,因为它与您的Kubernetes集群紧密集成,并添加了额外的功能,其命令行界面在kubectl的基础上进行调用。

    ApacheOpenWhisk,像OpenFaaS一样,安装在您的Kubernetes集群之上,而不是完全集成自己。然而,正如我们在第七章中所介绍的那样,ApacheOpenWhisk和Kubernetes,一旦服务暴露到公共互联网,CLI需要配置以对安装进行身份验证。在那一章中,我们运行了以下命令来暴露服务并对客户端进行身份验证:

    在Fission安装期间,我们必须设置两个环境变量:

    正如您所看到的,我们得到了一个标识FissionAPI和版本号的响应。从~/.kube/config文件中删除证书,并运行以下命令:

    $fissionfunctionlist我们仍然可以与我们的Fission安装进行交互;这意味着默认情况下Fission没有身份验证,并且当我们使用推荐的安装程序时,API默认暴露在互联网上:

    在那之前,建议您更新Helm图表,将控制器服务的serviceType设置为ClusterIP。从下面的输出中可以看到,它目前设置为LoadBalancer:

    一旦您配置服务使用ClusterIP,您可以使用kubectl内置的代理配置从本地主机到控制器的端口转发。执行此操作的命令看起来类似于以下内容:

    正如您所看到的,当涉及到保护我们的无服务器安装时,我们有一个相当混杂的情况——我们涵盖的一些解决方案是默认安全的,而另一些解决方案,比如旧的默认MongoDB配置,需要更多的工作来保护它们并使其达到生产就绪状态。在永久部署本书中涵盖的任何工具之前,请确保您已经审查了每个工具暴露的内容以及如何最好地将其锁定。

    在我们开始研究各种监控Kubernetes集群的方法之前,我们应该快速谈谈当涉及到一个可能有很多移动部分的工具时,我们所说的监控是什么意思。

    正如您所能想象的,监控Kubernetes集群与此有很大不同。按设计,集群中运行的应用程序应具有容错性和高可用性——事实上,我们在之前章节中运行的函数有时只有执行函数所需的寿命。

    考虑到这一点,我们不需要深入了解监视Kubernetes集群的细节——这可能需要一本完全不同的书。相反,我们将快速查看一下使用仪表板、GoogleCloud和MicrosoftAzure来审查我们Kubernetes集群的服务指标的一些选项,因为这两者都原生支持Kubernetes集群。

    Kubernetes仪表板不仅是管理集群的重要资源;它还为您提供了一个很好的视觉概述,显示您正在运行的内容以及当前的性能。

    例如,在命名空间下拉菜单中选择所有命名空间,然后在左侧菜单的工作负载部分点击Pods,将为您提供所有正在运行的Pod的列表,以及每个Pod当前使用CPU和RAM的详细情况:

    点击一个Pod——在这种情况下是heapster——将为您提供该Pod中组成容器正在使用的资源的更详细的分解:

    向下滚动将显示容器。在heapster的情况下,Pod中有三个容器。从这里,您可以实时查看每个容器的日志:

    可以想象,这是一个非常有用的功能,当您需要调试正在运行的容器时。

    然而,您可能已经注意到在查看仪表板时,显示的CPU和RAM利用率仅为过去15分钟的数据——您无法深入挖掘或查看更早的数据。因此,有关当前运行服务的信息可以通过仪表板获得。

    接下来是GoogleCloud。从外表看,GoogleCloud控制台的Kubernetes部分看起来几乎与Kubernetes仪表板相似:

    然而,正如您从前面的截图中所看到的,除了显示OK状态之外,它实际上并没有告诉您有关集群内部发生了什么。相反,您需要使用Stackdriver,它可以从GoogleCloud控制台的左侧菜单中访问。

    当您首次进入Stackdriver时,将会被问到几个问题。通过这个过程,在结束时,您应该可以免费试用并收集来自您的Kubernetes集群的日志。几分钟后,您应该开始看到来自您的集群的信息显示在指标资源管理器中。从这里,您可以开始构建诸如以下仪表板之类的仪表板:

    正如您从上述屏幕截图中所看到的,我们有选项查看超过15分钟的数据-实际上,仪表板显示了超过一个小时的数据,这就是集群的年龄。

    Stackdriver不仅可以让您访问有关您的集群的指标,还可以访问来自您的Kubernetes集群和容器本身的日志:

    由于日志和指标被存储在集群之外,您还可以访问有关容器的历史信息。如果您在一个只活动几秒钟的容器中运行一个函数,您不仅可以看到该容器的RAM和CPU利用率,还可以访问整个容器的生命周期。

    Stackdriver的其他功能包括关于您整体使用情况的每日、每周和每月电子邮件报告,以及配置触发器的选项,用于当指标阈值被触发或日志文件中出现事件时通知您-您可以通过短信、电子邮件甚至聊天产品(如Slack或Campfire)收到这些通知。

    与GoogleCloud相比,MicrosoftAzure对您的Kubernetes集群的开箱即用的洞察力并不是很好。您无法看到集群内部的运行情况,虽然有可用的指标,但它们只适用于主机机器-例如,您可以在以下屏幕截图中看到CPU利用率:

    同样,您可以使用以下命令启动Kubernetes仪表板(确保用您自己的资源组和名称替换):

    $azaksbrowse--resource-groupKubeResourceGroup--nameAzureKubeCluster不过不用担心,还有容器监控解决方案;这是一个基于代理的系统,您可以部署在您的Kubernetes集群上,然后将信息反馈给Azure门户。

    要部署它,您需要在Azure门户内搜索Microsoft的容器监控解决方案。单击“创建”按钮将要求您创建一个工作空间;我选择在与我的Kubernetes集群相同的资源组和区域中创建我的工作空间。确保选中“固定到仪表板”,然后单击“部署”。

    这就有点复杂了,因为您需要获取工作空间ID和主密钥。这些信息深藏在一系列链接中。要获取它们,转到您的仪表板并选择您的工作空间—我的标记为Containers(russ-monitor)。然后,单击“OMS工作区”,然后单击“高级设置”。您应该看到类似以下屏幕截图的内容:

    记下工作空间ID和主密钥(在上述屏幕截图中我的已模糊处理)。在本书附带的存储库的Chapter10文件夹中有一个名为oms-daemonset.yaml的文件;复制该文件并更新其中的env部分的值,以便使用您实际的工作空间ID和主密钥进行更新:

    env:-name:WSIDvalue:-name:KEYvalue:更新文件后,从保存了更新后的oms-daemonset.yaml文件的同一文件夹中运行以下命令,将daemonset部署到您的集群中:

    $kubectlcreate-foms-daemonset.yaml部署后,您应该能够运行以下命令来确认一切是否按预期工作:

    $kubectlgetdaemonset您应该在集群中的每个节点上看到一个daemonset。由于我的集群有三个节点,结果看起来像下面这样:

    部署后,大约15分钟后,您应该能够重新访问您的工作空间并开始记录统计信息。以下屏幕截图给出了您对记录的信息的一个概念。

    第一个屏幕显示了有关在您的Kubernetes集群中运行的容器数量的一些基本信息,以及Kubernetes记录的任何错误和事件:

    向右滚动将向您显示有关集群的更多详细信息:

    正如您所看到的,我们有信息在我集群中运行的两个命名空间中的pod,然后我们有集群中的节点。在此之后,我们有所有已下载的映像,以及所有正在运行的容器的详细信息。

    再次向右滚动将显示更多信息:

    PowerBI是由Microsoft提供的业务分析服务。它允许您创建仪表板并对数据集进行一些相当复杂的计算,其中之一是将度量数据从Kubernetes集群导出到MicrosoftAzure工作区。

    在本章中,我们讨论了我们的Kubernetes集群如何受到保护,以及如何保护我们在前几章中看到的每个无服务器工具的默认配置。我们已经看过三种方法,可以使用Kubernetes仪表板从我们的Kubernetes集群获取实时统计信息,并且还查看了GoogleCloud和MicrosoftAzure提供的监控工具,用于存储和查询来自您的集群的指标。

    在下一章中,也是最后一章,我们将看看如何基于我们在前几章中学到的知识最好地在Kubernetes上运行无服务器工作负载。

    在我们的最后一章中,我们将讨论一些不同的情景,您会希望在其中托管自己的无服务器工作负载,并在选择工具时要考虑什么。我们将从讨论使用一种仍处于萌芽阶段并且仍在积极开发中的技术的优缺点开始。

    我们在本书中看到的几乎所有技术目前都在开发中。正如我们已经讨论过的,一些项目正处于开发的早期阶段,而另一些则更加成熟。让我们先讨论Kubernetes本身。

    Kubernetes目前正在积极开发,尽管它已经相当成熟。我在2017年9月初开始写这本书,现在,当我写下最后一章时,已经是2017年12月底了。

    这些更新涵盖了从维护版本v1.5、v1.6和v1.7到实际版本v.1.8和v1.9,以及随后的维护版本,一直到v1.10的第一个alpha版本。在如此活跃的发布周期中,保持对发布的掌握有多容易呢?

    嗯,考虑到发布的频率,情况并不像你想象的那么糟糕,尽管可能会变得复杂。正如您从表中看到的,每个Kubernetes发布都有一个主要版本、一个次要版本和一个补丁版本。例如,我写作时的当前版本是:

    v1.6.13(较旧版本)

    v1.7.11(较旧版本)

    v1.8.6(当前版本)

    v1.9.0(开发版本)

    截至2017年12月12日,同一主要版本有四个次要版本正在积极开发和修补。Kubernetes本身支持同时三个次要版本;即当前版本(v1.8)和两个较旧的版本(v1.6和v1.7)。这意味着:

    预计运行当前版本的主节点将与运行两个先前版本的节点一起工作。也就是说,您可以在集群中拥有一个v1.8主节点和混合的v1.7和v1.6节点。

    运行当前版本的主节点预计可以与一个版本落后和一个版本领先于当前版本的客户端(如kubectl)一起工作;这意味着我们可以将我们的v1.8主节点与v1.9和v1.10客户端进行交互。

    建议无论您运行哪个版本,都始终运行最新的补丁版本,因为补丁通常包含关键的错误和安全修复程序。

    您可以通过运行以下命令列出可以使用Minikube部署的Kubernetes版本:

    首先,让我们看看工具的类型。在上一章中,当我们研究安全性时,我们发现基本上有两种类型的工具。第一种是在Kubernetes内添加和扩展功能的工具,例如Kubeless和Funktion。第二种类型的工具通过基本上位于Kubernetes之上并进行API调用来消耗Kubernetes服务,例如ApacheOpenWhisk,Fission和OpenFaaS。

    例如,2017年9月,Kubeless发布了一个更新,从使用ThirdPartyResources(TPR)更改为CustomResourceDefinitions(CRD),因为TPR在Kubernetesv.1.7中已被弃用,并在v1.8中删除。

    这意味着您选择的工具将需要一些研究。您应该问自己的问题是:

    我正在评估的工具是否与我将在集群中部署的Kubernetes版本兼容?如果有疑问,您可以通过在Minikube上进行一些测试安装来进行检查。

    是否有任何可能影响我的部署的未解决问题?在承诺使用该工具之前,我建议查看工具GitHub项目页面上的任何未解决问题;其中有没有问题听起来很熟悉,并且可能适用于您的安装?

    我正在考虑部署的工具是否在积极开发中,新版本发布频率如何?是否有社区支持该工具?查看GitHub上的发布页面;发布频率如何,是否有任何破坏性的发布?

    该工具有多安全?根据前一章,默认配置有多安全,使其安全会如何影响您使用该工具?

    以下是一些有用的链接,应该可以帮助您回答之前的问题。

    Kubeless的有用链接如下:

    OpenWhisk的有用链接如下:

    Fission的有用链接如下:

    OpenFaaS的有用链接如下:

    Funktion的有用链接如下:

    自从这本书开始编写以来,Funktion已经被沙箱化。源代码仍然可供任何人使用,或者分叉他们自己的版本以继续开发。作者建议两种替代方案:Kubeless或ApacheOpenWhisk。

    在前几章中,我们谈到了无服务器函数和Kubernetes以及使用它们的优势:

    Kubernetes:使用Kubernetes部署应用程序的最大用例是,它允许您开发一次,然后以一致的方式在多个平台上部署,无论是自托管的裸机服务器,还是在VMWare、OpenStack、KVM、Hyper-V等上运行虚拟机的私有云。对于谷歌云、微软Azure和现在的AWS等公共云提供商也是一样,它们都提供自己的本地托管Kubernetes服务,包括Minikube或即将发布的DockerformacOS或DockerforWindows版本。

    无服务器:将应用程序的全部或部分部署为无服务器函数可以帮助它轻松扩展。突然间,你不需要担心你的虚拟机或容器是否有足够的资源来处理大量的传入连接,或者这些连接如何路由到你的应用程序。每个请求将被发送到一个个体或一组容器中,在那里你的请求将被处理——一旦完成,该容器将被终止或回收用于下一个请求。

    Kubernetes加无服务器:正如前面提到的,应用程序的无服务器部分可以轻松扩展——这可以与Kubernetes结合,其中可以快速地手动或通过脚本添加额外的节点到你的集群中。一旦额外的资源成为集群的一部分,你的无服务器函数将自动安排在新资源上,而无需对应用程序路由或代码进行进一步的更改。

    再加上你几乎可以在所有主要的公共云提供商中部署你的应用程序的知识,你将获得一致的体验,而不必调整你的代码以适应提供商自己的函数即服务提供,比如我们在第一章中讨论的那些。无服务器景观。

    你选择无服务器工具很可能取决于两个因素,第一个是你的应用程序是用什么语言编写的,例如,你的应用程序是用Python、Node.js、PHP、Java、.NET还是Go编写的?

    第二个因素将是个人偏好。在阅读本书的章节时,你可能已经对哪种工具最适合你以及哪种工具适合你的开发工作流程和自己的工作方式形成了看法。安全等问题总是一个影响因素,但正如在上一章中讨论的那样,有办法克服这些问题。

    到目前为止,我们一直在讨论许多可能是小的移动部分。那么大的固定点,比如数据库和文件存储,该如何与Kubernetes上的FaaS服务结合呢?

    每当我开始一个项目,我倾向于查看数据库的使用情况以及对应用程序整体性能的影响,然后从那里开始工作。

    Kubernetes允许您运行PetSet;回想一下本书开头的宠物与牛的比喻。在Kubernetesv1.5中,随着该功能退出alpha版,它被称为StatefulSet。该功能在Kubernetesv1.9中退出beta版。

    StatefulSet允许您运行传统上在Kubernetes等集群服务中运行起来相当困难的东西。通过使用pod和持久存储的组合,它基本上在Kubernetes集群中创建了一个固定点,其中:

    具有稳定的唯一网络标识符,如果StatefulSet需要在主机之间移动或者由于错误需要重新启动pod,它将持续存在

    具有稳定的专用于StatefulSet的持久存储,用于存储数据库、配置等

    具有有序和优雅的部署和扩展、删除和终止,以及自动滚动更新,所有这些意味着您可以控制需要在启动、移动或关闭时进行控制的软件。

    所有这些意味着在Kubernetes集群中托管数据库是完全可能的。这样做意味着您将能够在相同的命名空间内连接到您的数据库,但这种解决方案可能并非适用于所有情况。

    例如,如果您有一个大型数据集,或者您的数据库需要被Kubernetes集群外的其他应用程序访问,那么您最好使用公共云提供商提供的本地数据库服务。这些服务包括:

    尽管使用这些服务会使您暴露于一定程度的供应商锁定,因为您的大部分数据将位于Kubernetes集群之外,但这三个服务都提供开源数据库引擎,从应用程序的角度来看,这意味着它们仍然在使用相同的数据库服务,无论是在您的集群内托管还是作为您的公共云提供商服务之一。

    有关StatefulSets的更多信息,我建议阅读Kubernetes网站上的以下两个示例:

    请记住,直到Kubernetesv1.9版本之前,此功能都处于测试阶段,因此如果您的集群运行的是旧版本,可能需要查看文档。

    大多数现代应用程序应该不再存储在本地驱动器上生成的文件,而是应该使用对象存储。通常,对象提供了一个API,允许应用程序将文件写入服务,并查询服务以查找文件的元数据,包括检索文件可以通过HTTP访问的URL。

    三大公共云提供商都提供对象存储:

    如果您希望将应用程序保留在Kubernetes中,包括对象存储,不用担心,可以运行自己的对象存储;事实上,您可以运行一个与AmazonS3具有高度兼容性的对象存储,这意味着您的应用程序应该可以继续工作,几乎不需要修改。

    Minio是一个多云对象存储,可以部署到Kubernetes以及其他云和服务提供商;甚至可以使用Minikube在本地运行它。

    所以,我们到了书的结尾。我们已经解释了什么是无服务器,并解决了在服务器上运行无服务器函数的混乱。

    我们已经了解了Kubernetes是如何起步以及一些核心概念,以及如何使用Kubernetes提供的工具在本地和公共云中部署集群,还有云服务提供商的原生解决方案。

    使用这些集群,我们通过了几个工具,它们都提供了函数即服务功能,要么通过扩展Kubernetes的新功能,要么通过利用Kubernetes的平台即服务功能并在其上安装自己。

    然后我们讨论了这些部署可能存在的安全问题以及如何监视它们,然后讨论了我们如何努力保持领先的不断发展的技术,并且在开始在Kubernetes上部署无服务器函数时需要考虑的事项。

    THE END
    1.宠物店名字时尚洋气依恋熊宠物店 好日子宠物乐园 阿喵阿汪宠物会所 妖灵灵宠物生活馆 尚宠宠物生活馆 北大营宠物店 萌宠一族宠物店 渔众不同奇宠世界 蜜宠宠物SPA会馆 小邪宠物工作室 豆花宠物 贵宾之家宠物生活馆 萨宝宠物狗粮猫粮店 全明星宠物俱乐部 美墩儿宠物生活馆 ...http://mingzi.jb51.net/qiming/dianpu/28969.html
    2.2024年公司起名好听的农牧公司名字有哪些2024年公司起名好听的农牧公司名字有哪些 凤事、蓝坚、太宝、纽长、百旋、春苏、驰盛、览至、福梦、尚高、实邦、苏梦、发全、特思、相览、帝春、妙诺、旋龙、泰翔、月界、力升、全识、雅艾、海斯、盛览、相洲、磊鑫、美凡、易宇、达易、益斯、佳西、源具、真英、迪永、旭德、同诚、生拓、盈汇、永用、...http://rilisu.com/jieri_51319/
    3.“宠物侦探”找的是宠物,更是人类的爱专业的宠物学校、宠物医院、宠物民宿,宠物巴士司机、宠物托管师、宠物美容师、宠物殡葬师,以及有点“玄学”色彩的宠物沟通师,据说能帮你听懂那一声声“汪”和“喵”里表达了什么意思。代遛狗、上门铲屎已经是常规需求,还出现了更“垂直”的职业——扮演带宠物绝育的“坏人”。 https://m.gmw.cn/2024-06/04/content_1303754672.htm
    4.美漫丧钟最新章节列表混沌文工团(求收藏,求推荐) 第35章 丧钟的战斗 第36章 好运 第37章 研究所 第38章 人性底限 第39章 地下 第40章 黑灯电池(求收藏) 关于DC宇宙发展 DC世界大事件年表 第41章 植物 关于大事件《金属》以及团子的一些想法 关于书中的漫威宇宙 第42章 南达尔巴特 第43章 塔莉娅的秘密 第44章 蝙蝠 第45章 对战 第...https://www.shuq.net/xs1589/
    5.美漫丧钟最新章节列表美漫丧钟最新章节目录第3369章 起名大豆 第3370章 是陷阱吗? 第3371章 避难所英雄 第3372章 放长钓线 第3373章 小子暴富 第3374章 顺便交易 第3375章 三家混乱 第3376章 援军抵达 第3377章 追杀到家 第3378章 爱攀比的好友 第3379章 美食通讯器 第3380章 声东击西 第3381章 所谓战术 第3382章 不愉快的试探 第3383章...http://www.siluwx.org/book/78814/index.html
    1.宠物食品公司起名(精选267个)宠物食品公司起名 1、萌宠盛宴食品公司 这个名字传达出公司提供的宠物食品如同一场盛宴,丰富多样且美味可口。让宠物们享受美食的同时,也为宠物主人带来满足感。 2、爱宠优味食品公司 强调对宠物的关爱,同时突出食品的优质味道。让宠物主人放心选择,为宠物提供美味又健康的食品。 https://www.szmxcs.com/gsqm/836.html
    2.兽医门诊服务起名(兽医公司好听的名字)兽医门诊服务可以针对不同的宠物提供不同的保健和治疗服务,可以根据不同的服务特点来为公司起名。专门为猫提供服务的兽医门诊可以命名为"猫之家",专为狗提供服务的兽医门诊可以命名为"犬乐园",以此突出公司的特色和定位。 七、利用形容词和副词 在给兽医门诊服务起名时,可以使用一些形容词和副词来增加名字的表现力。http://www.qlmzp.com/wenzhang/32044.html
    3.物业公司名字免费起名大全四个字:物业守护者–金牛财税物业公司是维护房屋及公共设施的专业公司,为居民提供最基本的居住服务。一个好的物业公司名字可以让人们更加信任和满意。在这里,我们为大家提供一些物业公司名字免费起名的大全,希望能帮助您找到一个合适的物业公司名字。 第一段:简洁明了的物业公司名字 物业公司名字要简洁明了,容易理解,这样才能够让人们快速地记住。https://www.jinniucaishui.com/14043.html
    4.有奖征集小动物们全网征名啦1.名字需朗朗上口,富有创意,能体现动物的特性。 2.符合光明红木文化古镇的文化氛围和动物乐园的定位。 3.避免使用低俗、不雅的名字。 03 活动时间 留言阶段:11月9日—11月21日 公布结果:11月21日评论区回复 ...https://www.zhengjimt.com/zjxx/xuanchuanyuzhengji/237142.html
    5.生肖狗公司取什么名字好令人称赞的名字合集公司起名要怎么取合适 1. 公司名字要简洁明快,便于记忆。要方便和消费者进行信息交流,同时还能引起大众的想象力,寓意更加丰富的好名字。 2. 公司名字要符合公司文化理念和公司企业宗旨。公司名字可以有效引导顾客想象力并有助于公司品牌形象。 3. 具备独特个性的名称。个性不是胡乱的起一个公司名字,而是需要结合公司...https://www.kswqd.com/gongsiqiming/15804.html
    6.配送服务部名字与众不同起名大全配送服务部名字与众不同起名大全 2024-11-11 23:15:00 编辑:yumi 配送服务部取名字精选推荐: 1、红霞 红字指红色,取名寓意事业的兴盛、成功。霞字指红色的云,引申形容像彩霞般绚丽。字型简单易记。 2、王海侠 王字指皇帝、首领、王国。(wàng)古代指统治者谓以仁义取得天下。海字指大海,取名表示胸怀宽广、知...https://www.xhtw.com/1606950.html
    7.宠物用品店名字怎么起宠物用品店名字大全→MAIGOO知识摘要:开一家宠物店,有必要起一个好听的名字,这样才能吸引顾客。在给宠物用品店起名时,应名实相符,富有文化内涵,朗朗上口,要适应当地风土人情,通俗易懂,具有一定的消费特征,还要注意避免雷同,这样才不会引起误会。接下来就和小编一起来看看宠物用品店名字大全吧。 https://www.maigoo.com/goomai/215629.html
    8....2023使用生成式AI,用您最喜欢的歌曲为宠物命名据他们介绍,在2023年,各大企业正迫切寻求利用生成性人工智能(AI)的力量来解决各自独特的挑战。开发者们都收到了许多关于非传统使用AI的需求,例如创建一个根据用户喜欢的歌曲为宠物起名的系统。尽管这个例子看起来可能有些荒谬,但它展示了底层技术如何适应解决现实世界的商业问题。https://blog.csdn.net/weixin_46812959/article/details/134789088
    9.适合女人9个小生意(适合做生意女人)–触手文案网这9个小生意分别是美容行业、网络营销、烘焙业、儿童托管服务、宠物美容、实体店铺、搭配顾问、预防医学和社交媒体。无论你是想寻求自我发展的机会还是为了增加家庭收入而创业,这些小生意都可以帮助女性实现自己的梦想。这9个适合女人从事的小生意,都是具有未来性和实践性的,只需要在自己擅长的领域中努力探索适合女人9...https://www.cswenan.com/27659.html
    10.动物萌宠乐园软文(萌宠乐园文案)本篇文章给大家谈谈动物萌宠乐园软文,以及萌宠乐园文案对应的知识点,希望对各位有所帮助,不要忘了收藏本站喔。 本文目录一览: 1、描写萌宠的短句子 2、萌宠动物乐园策划书 3、享受五一小长假,和轩逸一起打卡萌宠乐园 4、昆明融创海世界游玩感想几句话 ...https://www.beitazoo.com/news/80571.html
    11.区域公用品牌运营必看文章:区域公用品牌运营的十大趋势2023年,作为现象级区域公用品牌——淄博烧烤的设计者、亲历者,天锐灵动在复盘、总结淄博烧烤的时候发现,淄博烧烤之所以快速火爆出圈,其本质就是跳出了品牌“自嗨”的状态,沉下心来,认真并竭尽所能的“倾听大众、服务大众、善待大众”, 所以,我们看到,很多游客来淄博,不用担心任何问题,因为总有人会帮你解决——出租...http://www.360doc.com/content/24/0320/09/58338705_1117756364.shtml
    12.《黎漾严峥凛》严峥凛黎漾小说完整在线阅读出了门,她便直奔几公里外的宠物托管机构。 当年她和严峥凛一起领养了一只金毛,起名叫飞飞。 因为严侑辰对狗毛过敏,黎漾只能将它寄养在这里,只要一有空就过去看它。 现在她决定脱离世界,最放心不下的就是这只大狗。 她必须在自己离开前,给飞飞找到一个可以托付的领养人。 一过去,飞飞就兴奋地摇着尾巴过来蹭她。https://m.jingpinhu.com/book/lyylovq549.html
    13.美漫丧钟女主最新章节列表,小说美漫丧钟女主无弹窗(混沌文工团...第5867章 宠物托管 第5868章 搭人(鼠)梯 第5869章 奇怪空间 第5870章 神行界 第5871章 随地大小变 第5872章 陌生的仓库 第5873章 箱子仓库 第5874章 淘汰画作 第5875章 这里有活人? 第5876章 海边小镇 第5877章 线条构成 第5878章 一点迹象 第5879章 变化之塔 第5880章 他画谁猜 第5881章 第四关...https://www.xs74w.com/19/19186/