本篇内容是根据2016年8月份#20 Kubernetes, Containers, Go音频录制内容的整理与翻译

Kelsey Hightower (译者注: kubernetes-the-hard-way的作者) 参加了节目,讨论他在 Google Cloud Platform 的工作,包括 Kubernetes、在 Google Cloud 上实现 Pokémon GO、Kubernetes 集群联合、容器,以及当然还有 Go 语言。




Erik St. Martin: 好的,我们又回来了,迎来新一期的 GoTime 播客。这是第 20 期。今天的节目中有我,Erik St. Martin,还有 Brian Ketelsen ---跟大家打个招呼吧,Brian。

Brian Ketelsen: 大家好!

Erik St. Martin: 还有 Carlisia Thompson...

Carlisia Thompson: 大家好!

Erik St. Martin: 今天的特别嘉宾对大家来说应该不陌生。他在 Go 和 Kubernetes 社区非常知名。让我们欢迎 Kelsey Hightower!

Kelsey Hightower: 大家好,我很高兴来到这里。

Erik St. Martin: 对于可能还不太了解你的人,能否简单介绍一下你自己以及你正在从事的工作?

Kelsey Hightower: 好的!我目前在 Google 工作,主要负责 Google Cloud 技术,尤其是一些我长期以来非常喜欢的开源项目,主要是 Golang 和 Kubernetes。Kubernetes 是一个分布式系统框架,用于实现类似 Google 风格的部署---这算是简洁的概括。我之前还在 CoreOS 和 Puppet Labs 工作过。

我把自己看作是一个会写代码的系统管理员(system admin)。

Erik St. Martin: [不清楚的音频 00:01:32.18] 系统管理员的部分;你更像是一个系统管理员,而不是程序员。

Kelsey Hightower: 其实,过去五年我主要是全职做开发,也参与了一些其他的开发工作,但我的职业生涯是从系统管理员开始的。所以我在工作中始终会带入这种思维方式。如果我写的代码需要连接数据库,我会实现重试逻辑;我不会随意把代码甩给别人,因为我知道墙的另一边坐着的是谁。

如今,我在写代码时,不仅仅关注如何构建应用,还会想到谁来管理这个应用,以及管理起来会是什么样子。我永远不会忘记自己在技术领域的起点。

Brian Ketelsen: 这不就是现在的无服务器(serverless)理念吗?大家都在谈论无服务器计算,这让我有点抓狂;我们之前似乎也讨论过几次。现在难道不是“无运维”(opsless)了吗?你只需把东西扔到 Kubernetes 上,就不必担心了?

Kelsey Hightower: 是的,我认为 Kubernetes 是运维人员将他们的专业知识代码化后的产物。说实话,需要运维人员或某种运维角色来部署并维护 Kubernetes,以及对其进行升级。今天的新闻中提到了 Pokémon GO 的技术栈。Google 的 SRE(站点可靠性工程师)团队在幕后做了大量工作,为他们完成了升级。

所以,运维始终存在。不过,即使在像 Kubernetes 这样的系统中,你不一定需要直接与运维人员交互来完成部署,因为你可以通过 API 来实现,但仍有一些运维方面的工作可以通过 Kubernetes 来处理。日志记录方式、连接重试方式、如何在集群环境中进行操作,这些都是运维相关的问题。我认为我过去做系统管理员的经历让我更容易接受这些平台。

Erik St. Martin: 学会创建抽象是 Kubernetes 的优势之一。我们已经习惯了虚拟机的世界,它让人们逐渐摆脱对物理硬件的依赖。现在,我们开始能够更多地从集群运维的角度抽象出来,人们不再需要过多担心故障转移等问题。

不过就像你说的,你仍然需要专注于如何处理重试逻辑,确保代码是幂等的(item-potent),但你不需要过多考虑故障转移策略和扩展问题,因为这些大部分已经被系统处理了。

Kelsey Hightower: 是的,我认为 Kubernetes 对人们来说真的就像 Go 的运行时一样。大多数人甚至不知道 Go 的运行时存在。他们只是有一个静态链接的二进制文件,很多人会忘记运行时其实嵌入在其中,并负责垃圾回收、跨多核的扩展等工作。Kubernetes 也很像这样。你将 Kubernetes 部署在一组服务器上,而不是一组核心上。Kubernetes 的工作就是以一种你不需要考虑垃圾回收的方式运行你的应用程序。当你从 Kubernetes 中删除一个应用时,底层会清理镜像和进程,确保资源没有被浪费。

正如我们在编程世界中所做的事情一样,我认为 Kubernetes 代表了把一个运行时放在基础设施之上。

Erik St. Martin: 这是一个非常有趣的视角。

Brian Ketelsen: 我在 Twitter 上看到有些人说 Kubernetes 就像是云计算的 Linux 内核。你觉得这个观点怎么样?

Kelsey Hightower: 是的,这是我经常重复的一种说法。我认为是 Mesosphere(译者注: Mesos 项目背后的公司) 让这个术语流行起来的。我几年前在 Google 的 Urs 写的一篇关于“数据中心即计算机”的白皮书中读到过。如果我们接受“数据中心即计算机”这一概念,那么它就需要一个内核和一个操作系统。我将在即将到来的 KubeCon 大会上谈到这个想法。如果 Kubernetes 是一个内核,那么系统调用接口(system call interface)会是什么样子?对我来说,这正是我们开始讨论能够自我部署的应用的地方。

在 UNIX 系统中,你启动一个应用程序,它会绑定到一个 socket。在 Kubernetes 中,部署的应用程序可以创建一个具有公共 IP 地址的负载均衡器,客户端可以绑定到它上面。如果我们想要扩展,在一台机器上你可以创建多个进程;在 Kubernetes 这样的系统中,我们有 API 来实现。在 UNIX 系统中,我们有系统调用接口(syscall interface);可能通过某种 libc 或类似的东西来交互。而在 Kubernetes 中,它只是一个 REST API,它让我们可以在集群层面上做出与你在传统操作系统上类似的语义操作。

我觉得 Kubernetes 在硬件(这里是多台计算机)和软件(运行在集群中的应用程序)之间做得非常好,完美地完成了契约的角色。

Brian Ketelsen: 那你觉得 Go 语言对 Kubernetes 有什么特别之处?Kubernetes 是非常棒的软件,它是用 Go 写的,这两者之间有关系吗?

Kelsey Hightower: 是的,我认为很多人... 编程语言,甚至是自然语言---比如我的妻子是语言学家,她在波特兰教授 ESOL(英语作为第二语言)。我觉得语言以及围绕这些语言的社区会影响你的思维方式和构建方式。在 Go 社区中,构建跨平台、静态链接的可执行文件非常容易。如果你想想 Kubernetes 的部署方式,我们有一组独立的可执行文件,它们可以以不同的版本运行,或者可以根据需要升级,这完全基于 Go 的工作方式。我们有这些小型的二进制文件,只需要放置或替换它们来完成升级。我们不害怕使用并行或并发的方式来做事... Kubernetes 中的大多数组件都能够扩展,因为 Go 让这一切变得非常简单。我们不需要对 API 服务器或代理做太多复杂的技巧。

另一个好处是 Kubernetes 依赖的大多数工具---比如 Etcd、Docker,以及一些其他插件---恰好也是用 Go 写的。所以我们有一个强大的生态系统,这让 Kubernetes 更加特别。主要是社区的力量,其中大多数人具备 Docker 或 Etcd 的 Go 开发技能,而这些技能可以很轻松地转移到 Kubernetes 上,这对于我们的推广至关重要。

Erik St. Martin: 我记得 Flannel 也是用 Go 写的,对吧?

Brian Ketelsen: 是的。

Kelsey Hightower: 是的,Flannel... 基本上整个技术栈中的工具,比如 Weave、Prometheus、InfluxDB... 你能想到的几乎所有被使用的工具,包括 Fluentd,我记得也是。几乎全都如此。还有 Hashicorp 的 Vault... 例子不胜枚举。

Carlisia Thompson: 那么,Kubernetes 是使用插件架构的吗?

Kelsey Hightower: 在 Kubernetes 中,我们拥抱了分布式系统的模型。Kubernetes 的某些部分确实有插件模型。如果你考虑运行在机器上的代理程序(agent),它有某种插件模型。我们可以与不同的容器运行时(如 Rocket 或 Docker)交互。在 API 服务器上,插件架构更像是通过 API 的契约。如果你想构建一个自定义的调度器,你不需要重新编译 Kubernetes。这里没有单一的二进制文件。你只需构建另一个调度器,只要符合 API 规范并遵循相关规则,你就可以成为 Kubernetes 中的一等公民。

我们将插件模型分为两种类型。对于特定组件或服务而言,某些功能是局部的,你会看到更多的内部(in-process)或内置代码库的插件模型来扩展系统。但我们越来越倾向于一种模型,在这种模型中,所有功能扩展都可以通过与定义良好的 API 契约交互的外部二进制文件来完成。

Carlisia Thompson: 明白了。

Erik St. Martin: 是的,从一个通用的视角看 Kubernetes,有一些资源是被管理的,然后通常会有某种服务或组件负责监视 Etcd 中这些资源的变化,并根据观察到的变化调整集群,比如更新 pod 或类似的操作。

正如 Kelsey 所提到的,你可能会提交一个 pod 到 API,但实际上并没有 pod 在运行。系统会注意到这个 pod 被添加到了 Etcd 中,然后调度器(scheduler)会找到一个理想的节点来放置它,并将 Etcd 中的资源分配到该节点上,这样系统就知道它已经被分配了。然后我们会重新回到调度过程。你可以替换这些任何一个环节。

另一个概念是副本控制器(replication controller)。它位于 pod 之上的一层,定义了需要运行的副本数量。它本质上是一个循环,监控集群的变化,根据标签查询当前运行的副本数量,再启动另一个 pod。所以你可以在这些点上的任何地方插入你的逻辑,创建自己的系统,或者调整行为以更符合你的使用案例。这也是我会在 KubeCon 上讨论的内容之一,不仅仅是部署应用程序,而是基于 Kubernetes 构建应用程序。因为你可以复用这些相同的概念。你有一个资源定义,描述了你希望集群满足的某种状态,然后有某种控制器或调度器通过调整集群来实现这个期望状态。

Kelsey Hightower: 是的,如果我们把这个与 Go 社区联系起来,这就像某个函数返回一个 channel。通过管道传递的内容是实现细节,观察者可以根据需要处理这些内容。在 Kubernetes 中也是类似的模型---多个进程在观察类似 channel 的对象,并根据这些对象采取行动,同时响应以改变整个系统的行为。

Brian Ketelsen: Kubernetes 是我第一次看到一个系统能够描述资源的期望状态,并在后台完成调整过程。这让我觉得非常有趣。在 Kubernetes 之前,你有见过类似的模式吗?即你告诉系统“这是我想要的状态,去实现它”,而不是传统模型中的“我发出一个请求,完成一个操作”。我从没见过带有调整模型的期望状态概念。

Kelsey Hightower: 我认为我们在某些声明式系统中见过类似的模式,比如带有 DSL(领域特定语言)的 Puppet、CFEngine 和 Chef。它们通常有一个中间状态,用户可以在 DSL 中编写代码(通常是基础设施即代码的形式),然后编译器将其编译为服务目录。我认为 Kubernetes 与它们的不同之处在于,Kubernetes 更像是一个在线系统(online system)。你将状态更改发送到一个具有共识的中央权威组件,所有其他组件都会同时收到状态变化的通知。所以它是一个非常反应式的系统。

在其他系统中,虽然也有期望状态的概念(你可以用一种语言编写代码,编译成其他形式供代理程序使用),但这些系统通常在某种循环中运行,比如“每隔 30 分钟检查一次用户的期望状态”。Kubernetes 是声明式的。在 Kubernetes 中,当你创建一个应用程序(比如用 pod manifest),如果你删除了 pod manifest,对应的进程或容器也会从系统中移除。我认为这种声明式系统与期望状态驱动的组合让 Kubernetes 显得与众不同。尽管它与其他系统有一些功能上的重叠,但用户体验是由这两者的结合驱动的。

Erik St. Martin: 是的,我弟弟刚刚给我发消息---一个很好的例子是 Ansible,对吧?你定义文件的期望状态,或者需要安装的包,以及其他内容,它会尝试调整状态。但它不是实时的,也不会对更改做实时响应。

Kelsey Hightower: 在许多方面,Ansible 并不是声明式的。举个例子,如果你在 Ansible 的 playbook 中声明了一个资源,比如说在系统上添加一个文件,第一次运行 Ansible 时,这个文件会在目标系统上被创建。但如果你从 playbook 中移除了这个资源,再次运行 Ansible,这个文件并不会被删除。

我认为 Kubernetes 的不同之处在于,我们会管理和存储整个集群的状态信息。因此,当某些东西被移除时,我们清楚地知道如何清理它。整个集群的状态集中存储在一个地方,这让我们拥有了全局视图。

Erik St. Martin: 我发现用这些概念来构建应用程序真的很有趣,比如标签(label)的概念。通过标签,你可以让容器和 pods 吸引某些节点,同时排斥其他节点。现在 Kubernetes 1.4 版本中,我可以删除之前自己写的调度逻辑,因为现在 Kubernetes 引入了软(soft)和硬(hard)标签需求的概念,这基本上解决了我遇到的问题。 (译者注: 即污点与容忍)

举个例子---这有点像流媒体视频传输的逻辑。软标签的意思是,任何这些节点都可以运行特定的视频流,但优先选择某些节点。你可以对某些区域或一组机器设置一个硬标签要求,同时设置另一个优先节点的标签,因为这些节点可能有额外的带宽。因此,调度器会尽量将任务安排在优先节点上。如果这些节点空间不足,任务才会回退到其他节点,但可能会因此付出带宽的代价。

通过给机器添加标签来实现这一切真的很有意思。这种方式也适用于公有云和私有云的场景,比如你可以优先运行在私有云中,但当资源不足时转移到公有云。

Kelsey Hightower: 是的,没错。Kubernetes 的目标就是在一组机器上提供一个运行时环境。不管这些机器是你桌下的 Raspberry Pi 集群,还是某个云服务提供商的机器,亦或是你自己的裸机服务器,Kubernetes 都能确保按照既定规则运行。我们运行在硬件之上,你可以自由定制底层硬件,也可以在 Kubernetes 之上做任何事情,最终你实际上是在构建自己的平台。

我常常把 Kubernetes 称为构建分布式系统的框架,而大多数人用这个框架的一个流行方式就是通过容器部署应用程序。但实际上没有什么能阻止你用它来想象和构建其他类型的系统。

Erik St. Martin: 这是我特别感兴趣的一点,我很想看看 Kubernetes 的扩展会带来什么新的东西。就像你说的,现在大多数人的共识是,你只需要在机器上设置 Kubernetes,然后把你的容器扔进去就好了。但我很高兴看到越来越多的用例出现,人们开始更深入地与它交互,编写自己的工具来观察集群状态,并根据状态对集群进行修改。

我认为未来几年会有很多有趣的东西出现。甚至 Kubernetes 本身也在发生变化,比如 PetSet(译者注: 现在已经被StatefulSet替代,用来部署有状态的应用,如MySQL,MongoDB,Redis等)这样的功能正在被引入……

Kelsey Hightower: 我想谈谈这个话题……在我看来,Kubernetes 的核心其实非常小。就像 Golang 有一个标准库,但核心语言本身非常小。如果我们把 Kubernetes 的核心想象成一个小型系统,它也非常精简。我们可能有四到五个核心对象类型---具体取决于你怎么看。

首先是节点(node)对象,通常是由实际的机器支持的(无论是裸机、虚拟机还是其他形式)。节点是 Kubernetes 中的一个对象,其他对象会绑定到节点上。然后是 pod 对象,你可以在其中定义“这是我的应用程序,这是它的卷(volumes)”,pod 是运行在节点上的。所以节点和 pod 是 Kubernetes 的两个核心对象。

接下来还有另一个对象类型,比如说“保持一个 pod 始终运行”或者“我要运行五个这样的 pod”。这会是另一个对象类型。

其他对象是否是核心概念,这点还存在争议。因为 Kubernetes 中也有扩展(extensions)。比如 Deployment 是一种扩展,而 Service 更像是核心对象,用来表示“这一组应用程序属于同一个服务”。一旦有了服务(service)、pod、控制器(controller)和节点(node),其他东西,比如 DNS,也只是由服务对象驱动的。

Deployment 或 PetSet 更像是基于这些核心对象之上的工作流。它们变成了标准库的一部分,允许人们以新的方式利用底层对象。这样一来,每个人都不需要从头学习如何绑定原始的 TCP 套接字,或者解析 HTTP 请求的字节流。你只需要导入 net/http 模块,就可以直接使用。所以我喜欢把 Kubernetes 中的其他对象看作是标准库的一部分。它们是大多数人希望在集群中看到的功能。

随着 Kubernetes 的发展,我更倾向于把这种增长看作是标准库的扩展,而不是核心对象的增加。这种扩展使我们能够实现许多新功能,比如定时任务(scheduled jobs)、部署(deployments),以及任何其他人想要实现的功能。

Erik St. Martin: 我也同意这个观点。这些大多是基于底层对象的抽象层,用来简化任务。当你看到 Kubernetes 支持的所有功能列表时,可能会感到很复杂,但实际上,它们只是工作流场景的实现。比如“如何确保这五个相同的 pod 始终处于运行状态,无论发生什么情况,总有五个在运行”,这实际上就是复制控制器(replication controller)。

你们现在正在逐步淘汰复制控制器,转而使用副本集(replica set),对吧?

Kelsey Hightower: 对,本质上就是命名约定。既然我们在谈 Kubernetes 的对象,这其实跟 Golang 很像。在 Go 的标准语言规范里有核心类型,但你也可以自己定义类型,对吧?你可以定义一个类型,这个类型可以是其他类型的集合。在 Kubernetes 中也基本是一样的逻辑。例如,我曾构建了一个工具,帮助人们集成 Let's Encrypt。为了做到这一点,我本可以简单地写点脚本,自动化一些任务,但在 Kubernetes 中,我们还支持运行时的用户自定义类型---我们称之为第三方资源(third party resources)。

作为用户或者供应商,你可以创建一个新的 Kubernetes 对象类型,并通过第三方扩展或第三方资源将其发送到 Kubernetes 中。Kubernetes 会自动接收你的类型定义,并自动生成 API 端点、Etcd 中的存储以及与 kubectl(Kubernetes 命令行工具)的集成。所以,现在你可以开始定义这些证书对象。

这个对象的结构(schema)由你或观察这些对象的工具开发者决定。这种方式让你能够以我们未曾想象的方式扩展系统,但仍然感觉像是 Kubernetes 核心类型的一部分,用户体验依然是原生的。

Brian Ketelsen: 如果你想自己启动一个 Kubernetes 集群,可以打开浏览器,直接访问 Linode.com/gotime,使用代码 GoTime20 就能免费获得两个月的使用时间。你可以使用 Linode 强大的云服务器开始探索 Kubernetes。他们在全球有八个数据中心,套餐起价仅为每月 10 美元。你还能获得完整的 root 权限,这意味着你可以部署 Kubernetes。他们提供原生 SSD 存储、40GB 的网络带宽以及快速的 Intel Xeon E5 处理器。这是用几个 Linode 节点来玩 Kubernetes 的完美方式。

你还可以访问 Kelsey 的 "Learn Kubernetes The Hard Way" 仓库……Kelsey,它的 GitHub 仓库地址是什么?

Kelsey Hightower:kelseyhightower/KubernetesTheHardWay,在 GitHub 上。

Brian Ketelsen: 对,这将是开始学习 Kubernetes 的理想起点---Linode 和 Kelsey Hightower 一起助力你的 Kubernetes 之旅。

Carlisia Thompson: Kelsey,你刚才提到了一些开发者可以做的事情,其中很多内容我有点听不太懂,因为过去四年我都在中型公司工作,这些公司都有非常优秀的 DevOps 团队。作为开发者,我一直与 DevOps 团队紧密合作,但我不会直接使用这些工具,除非我在业余时间自己去学。我并没有去学,所以我也没有太多的经验可以分享。举个例子,昨天是我第一次使用 Docker,而我有一个强烈的动机去学,因为我机器上的某些东西无法正常工作,而我也不想花时间去解决。我就想,“好吧,我来搞懂 Docker。它可以是我的解决方案,也可以是我们团队其他开发者的解决方案。如果他们想用它,这问题就不仅是我一个人在解决,一旦我解决了,大家都能用,因为它是可复制的。”这就是使用容器的一个优势。

当然,一旦你有了容器,你还需要管理它们。从开发者的角度来看,我们应该关注什么呢?因为我在想,“如果我的 DevOps 团队没有使用 Kubernetes,或者我无法使用 Kubernetes,那我应该如何探索它?有没有一种方式可以让我将它集成到我的应用中并从中获益?”我们应该怎么做?或者说,作为不负责 DevOps 的开发者,我们是不是就完全不需要关注它?还是说,这其中有一些对我们有用的东西?

Kelsey Hightower: 这是一个很好的问题。如果你仔细想想,构建这些系统的人现在主要是开发者。我希望能看到更多运维人员加入,实际上我们也确实看到他们在围绕这些系统构建功能。但你提到的这个世界,就是开发者现在需要花更多时间处理运维工作,比如构建一些特定于运维的工具。如果退后一步看,这一切其实都只是软件。这些软件恰好是用来部署其他软件的。这有点像编写单元测试,你编写的软件是用来测试你的应用程序,而在这种情况下,软件是用来管理应用程序的,但归根结底,它们都是软件。

作为开发者,你可能对部署和管理一个 Kubernetes 集群没那么感兴趣。团队里有不同的角色负责这些工作。如果你所在的团队有专门的一组人使用托管系统,那很好。作为开发者,你真正关心的是:“我有一个应用程序,它运行在我的本地机器上。” Docker 是一款非常棒的软件,它允许你在 Linux 机器上运行并抽象掉对 SSH、systemd 单元文件和日志的需求---所有这些都被隐藏在底层。Docker 运行在单台机器上,为你提供了一个非常友好的 API,让你可以打包应用程序、推送到仓库,并在任何找到 Docker 的地方运行。这简直完美。

但到了生产环境,你需要考虑的事情要多得多,而不仅仅是启动和停止一个应用程序。比如,谁来收集日志并将它们推送到一个中央位置?你如何表达需求,比如“我希望这个应用程序能运行在多台机器、多数据中心上”?这一特定需求需要一个更高级的工具或语言来表达和执行。很多这样的考量会让你开始接触到集群的概念。我有多台机器,而我们现在用的这些机器,实际上像是大型主机,并不是设计来永久运行的。因此,我们需要面对这些机器可能会出故障的事实。如果你在使用云服务提供商的虚拟机,这些虚拟机是临时的,所以你必须计划好,运行它们的机器随时可能被销毁。它们可能会因为迁移而终止,所以你可能需要一个系统来应对这种情况。

从历史来看,即使你没在用 Kubernetes,你的团队也需要构建一些类似的东西。比如,如何决定应用程序运行在哪台机器上?如果你有一个 DevOps 团队,根据他们的工作方式,可能会把这些决定记录在电子表格里,或者像 Ansible 这样的工具中,比如说“这个应用程序运行数据库,那个服务器运行我的 Web 应用程序。”这就是手动调度,对吧?而在 Kubernetes 中,这种调度是一个自动化的过程。作为开发者,你可以编写一个类似部署声明的 manifest 文件。在这个文件中,你可以描述“我的应用程序需要 1 个 CPU 和 16MB 的 RAM,这足够处理每秒这么多请求。如果需要扩展,就给我更多这样的实例运行,我们可以水平扩展。”所以,作为开发者,在开发和测试阶段,一台机器就足够了。但到了生产环境,开发者需要一套新的概念来表达:“我需要这款应用程序运行 5 个副本,需要这些资源,并且我希望通过这个特定端口(而不是另一个端口)向客户暴露服务。”

所以,如果你仔细想想,Kubernetes 就是将一个 DevOps 团队的功能整合到一个系统中,然后提供给开发者一个 API,让你可以用它来表达你的应用程序在生产环境中的运行需求。

Carlisia Thompson: 非常酷。我现在就想深入探讨这个问题。[笑]

Brian Ketelsen: 我认为 Docker 和 Kubernetes 背后的概念,即便你不使用它们,也对 DevOps 世界和 Twelve-Factor 应用程序理念非常重要。即使你没使用容器,这些理念对你依然有帮助。如果你通过环境变量注入配置,那么在 Kubernetes 和 Docker 中,你的工作会变得简单得多。如果你把所有日志写到 STDOUT(标准输出),在 Kubernetes 和 Docker 中,你的工作也会变得更简单。这些做法无论你是否使用容器管理器或调度器,都应该坚持,因为它们会让你的工作变得更轻松,而在使用容器和编排工具时,它们的好处会更明显。

这些是容器和编排世界中那些互补的实践,无论如何我们都应该这样做。

Carlisia Thompson: Brian,如何通过 Kubernetes 来实现 Twelve-Factor 应用的这些理念?

Erik St. Martin: 举个例子,如果你有一个令牌需要在两个服务之间交换,或者你想验证一个 TLS 证书,如果这些配置通过环境变量传递到你的应用程序中,那么当你创建一个 Pod 规范(manifest)并交给 Kubernetes 时,你可以将存储在集群中的 secret 映射为环境变量,注入到你的 Pod 中。

Kelsey Hightower: 我想打断一下…… Kubernetes 其实并不关心 Twelve-Factor 的理念。如果你有一组数据想要消费,在 Kubernetes 中可以通过同步对象存储为一个文件,你可以指定文件名,它会在运行时被注入到你的容器中,或者你也可以选择将它们放入环境变量。这是你的选择。

正如 Brian 所说,像 Kubernetes 这样的分布式系统有能力在故障发生时自动重新调度你的应用程序。如果一个节点宕机,或者你有三个节点,你的应用程序在运行,你说“我想要我的应用程序有三个副本运行在 Kubernetes 中。”默认情况下,我们可能会在每个服务器上放一个副本,但这是实现细节的问题。

如果其中一台服务器宕机,你不需要做任何更改。Kubernetes 会自动将第三个副本移动到另一个有空间运行你的应用程序的节点上。正是因为这种自动化的过程,遵循 Twelve-Factor 的理念对你来说是最有利的。简单来说,Twelve-Factor 的核心理念就是让你的应用程序与机器解耦。

如果你的应用程序依赖某个服务器上的特定文件,你会遇到问题,也无法享受到 Kubernetes 将你迁移到另一台机器的能力。

这就是为什么在 Kubernetes 中,当你有一个令牌或者数据库用户名和密码时,你可以选择将这些 secret 定义为 Kubernetes 中的键/值对。作为开发者,你可以通过 API(或者把它看作一个大 YAML 文件)定义这些需求。你可以在文件中说:“我的应用程序需要这个容器版本,五个 secret。但我不通过环境变量获取配置,我通过磁盘上的文件获取配置。”开发者可以指定“我想引用这个 secret,这个用户名或密码,并将这些 secret 写入这个文件。”

Kubernetes 会自动完成这些工作。它会在运行时调用 API 服务器,拉取 secret,写入一个临时文件,并注入到你的进程中。当你的进程启动时,它就像往常一样看到这个文件,但我们依然遵循 Twelve-Factor 的方法。我们不会将这个文件写入底层服务器。如果我们将你的进程迁移到新服务器,我们会重复刚才提到的步骤,让这个配置可用。

所以,从某种角度看,Twelve-Factor 讨论的是一个能力有限的系统。它起源于 Heroku,而 Heroku 是一个很棒的系统,它推动了约束和契约的概念。在 Kubernetes 中,我们为你提供了一些额外的契约,让你在构建进程时有更多的灵活性。或许我们多出了第 13 或第 14 个因素,但核心理念仍然是让应用程序与机器解耦。如果你能做到这一点,就能享受 Docker 和 Kubernetes 带来的好处……因为在 Docker 的世界里,我们不会讨论 RedHat 或 Debian,而是讨论应用镜像和容器镜像。在 Kubernetes 里,我们不会讨论将应用安装到服务器,而是讨论将应用安装到集群。机器不再重要。

Erik St. Martin: 把配置(ConfigMap 或 secret)作为文件注入到 Pod 中有趣的一点是,这个文件本身并不会真的改变。但你仍然可以监听文件系统的变化,从而意识到你的配置已经被修改了。

Kelsey Hightower: 没错。

Erik St. Martin: 这正是 Kelsey 想表达的……你可以按照通常的方式构建应用程序,只要不过度耦合。我觉得很多人会有种“害怕错过”的心理。Kubernetes 确实非常酷,它能为你做很多事情,但并不是每个人都需要它,而且它是有成本的。你需要管理很多东西,比如分布式数据存储 Etcd,需要维护、备份,还有维护整个集群本身的工作。如果过早引入 Kubernetes,也可能适得其反。但如果你构建了一个设计良好的应用程序,你可以轻松地将它容器化,然后部署到 Kubernetes 上。

Kelsey Hightower: 说到这一点,这就像 goroutines 一样---在 Golang 中,你可以在完全不接触 goroutines 的情况下走得很远。如果你在构建一个 Web 应用程序,net/http 中使用的 goroutines 通常是对你隐藏的。但你可以用得很好。有些人滥用它们,毫无理由地使用,结果导致开销增加,还需要担心锁定等问题……这是过早选择这种方式所带来的问题。另一方面,如果正确使用 goroutines,比如 net/http 那样处理多个请求,你甚至不需要担心底层的实现。如果你有多核 CPU,它会并行处理,但这些细节是对你隐藏的。这些只是 Go 运行时为你做的额外好处。

随着时间的推移,即使许多人认为 Kubernetes 有点“杀鸡用牛刀”,开销很大,但我认为整个行业最终会重新校准基线,期待“我的应用程序应该能够运行在多个数据中心,并具备保持可用的工具”。因为现在所有的客户都假定,任何网站都应该可以快速地从世界各地访问,并且全天候运行。如果达不到这个标准,不论公司有多大,都会引发投诉。

Erik St. Martin: 是的,我觉得这很公平。人们已经习惯了所谓的 “五个九”的高可用性,他们会期待每个网站都能达到这种水平。如果他们的移动应用程序不能立刻连接,他们就会崩溃。

但 Kubernetes 的维护确实有成本。不过很多人其实并没有维护自己的 Kubernetes 集群;他们使用的是提供 Kubernetes 服务的公共平台,比如 GKE、CoreOS 的服务,还有其他一些公司的 Kubernetes 服务。

Brian Ketelsen: 说到 GKE,你看过关于 Pokémon GO 的那篇博客文章了吗?Kelsey?

Kelsey Hightower: 哦,你知道我看过了![笑] 我可是亲身参与的!Google 的 SRE 团队真的很棒,他们证明了……其实并不存在真正意义上的“无运维”。即使是 Pokémon GO 背后的团队……他们也有运维人员与我们的运维团队合作,但因为能与 Google 的运维团队合作,他们不需要投入太多资源来组建一个庞大的运维团队。对于听众来说,GKE 是 Kubernetes 的商业化版本,我们将它深度整合到了 Google Cloud 中。但它和开源的 Kubernetes 项目使用的是完全相同的代码库,任何人都可以使用,甚至可以在自己的环境中部署。

这对整个 Kubernetes 社区来说是一个巨大的胜利,因为 Google 并不是唯一在构建 Kubernetes 的公司,就像 Golang 一样,有成千上万的贡献者。对于任何新系统,尤其是基础设施工具来说,只有当它真正投入生产并承载实际的生产流量时,才算是真正的成功。表面上看,你可能会说,“这只是 Pokémon GO”,但相信我,这款游戏赚了很多钱。而一旦涉及到金钱,情况就都一样---没有人愿意损失收入。

像 Pokémon GO 这样全球范围内广泛使用的游戏,对许多玩家来说是一种现象级的体验,同时它也有收入关联,所以它的运行表现就成了一个非常关键的业务问题。看到 Kubernetes 在真实的工作负载中大放异彩,真的令人欣喜。

Brian Ketelsen: 是的,有一些关于这个的文章。我们会把它们放在节目笔记中,读起来真的很令人印象深刻。我很好奇……当我们谈到邀请你上节目时,你提到如果有一个自由的周末,你会想要研究“自部署的 Go 应用”。跟我们聊聊你会怎么做?你会在那个周末做些什么?

Kelsey Hightower: 其实两周前我在纽约的一个周末就做了这个。我当时在思考 Kubernetes 和各种平台即服务工具。让我觉得 Go 非常棒的地方,不是它的语法、功能或标准库,而是你可以在 Mac 上编译出一个自包含的 Linux 二进制文件,然后通过 SCP 传到服务器上---这是我在第一次 GopherCon 演讲中做的事情之一。对我来说,这种简单的方式让编程重新变得有趣,也让消费用 Go 编写的其他软件变得容易。

现在我们转向 Kubernetes,却发现又回到了“好吧,现在你想要部署应用,就必须完成所有这些步骤”的世界,比如创建所有这些 YAML 文件,学习如何填充它们。我构建了一个小应用程序,你会在 KubeCon 的我的主题演讲中看到它。这个应用程序本身可以说:“哦,我知道如何生成自己的部署文件。我可以在二进制文件中暴露一些标志,比如‘我想运行五个副本’,用户可以决定应该向 Kubernetes 请求多少内存。”

我的原型(其实在 GitHub 上)叫“Hello, Universe”。“Hello, world”已经过时了,“Hello, Universe”才是未来。所以当“Hello, Universe”将这些东西部署到 Kubernetes 上时,它会通过 API 查找所有运行的 Pod 实例,并将它们的 STDOUT 连接到我的 STDOUT。这样即使这个二进制文件运行在我的笔记本电脑上,你仍然可以看到所有 STDOUT 输出到你的笔记本电脑上。当你按下 Ctrl+C 终止进程时,我会清理 Kubernetes 中的所有资源,关闭服务、部署,甚至删除 secret。在命令行上,你只需提供几个标志,比如“这是我的 TLS 证书、私钥和公钥”,然后我的库会将这些内容上传到 Kubernetes,作为 secret 存储起来。这样在底层,你可以透明地将应用程序扩展到一个或多个集群,但它的感觉就像是一个简单的应用程序在你的笔记本电脑上运行。对我来说,这种体验是革命性的。

想象一下,如果有人告诉你:“下载我的项目,在你的笔记本电脑上运行它试用一下。当你准备好了,只需提供一个 Kubernetes 标志和一个 Kubernetes 集群的 URL(或者一个联邦集群的 URL)”。它就会自动部署到所有集群中,并提供一个仪表盘或 UI,让你能够实际与它的运行状态交互。有点像你在真实服务器上使用的 ps 命令,但想象一下你的应用程序成为集群中运行的东西的用户界面。

对我来说,这就是能够推动行业发展的东西,能够真正向人们展示这些技术栈的强大力量,同时只需很少的努力。

Brian Ketelsen: 太不可思议了。我知道今晚我要研究什么了。

Erik St. Martin: 好吧,我已经把 GitHub 的代码库打开了。[笑声] 开始思考这些事情真的很有趣。我正在谈论的是应用部署的方式,主要是使用第三方资源。基本上就是提交一个配置,比如一个频道列表或者有线电视的配置,把它提交到 Kubernetes 的 API。然后会有一个控制器监视这些资源,它会说:“嘿,我需要启动一个用于视频流的 pod。我需要将它的配置映射进去,并确保有一个副本保持运行。”可能会有两个副本,其中一个用于故障转移,但从一个通用的角度来看,这种方式确保了,作为负责频道列表和有线电视流的人,我不需要关心硬件或软件或其他什么。我只需要提交一个期望的状态,比如“我希望这组频道被流式传输到这个区域,执行吧!”

当我不想这么做时,或者我想以某种方式更改它,我只需更新资源,集群就会自适应。这真的改变了你构建应用程序的方式,非常有趣。

Kelsey Hightower: 对于正在收听的 Go 开发者来说,这里有一个类似点。在我开始用 Go 写代码之前,我主要使用 Ruby 和 Python。使用这些语言时,每次你想要实现并发,都需要停下来思考一下,比如“哦,Ruby---我要实现并发。好吧……让我在这个东西前面加上路径和 [听不清 00:44:35.26],让我去获取 NGINX,还有天哪,我还得去拿一个 Redis 队列”,只是为了并发做点什么。而在 Go 中,这些几乎是默认就有的,所以你可以承担更有野心的项目,比如“我要用 Golang 编写一个分布式数据库。”因为你不需要再担心实现这些目标的工具,它们看起来就是现成的。社区也在构建这些工具,你可以从中获得灵感。

所以任何时候,如果能免去实现某些复杂功能的心智负担,并且这些功能已经为你提供好了,这会给你勇气和时间去构建更具挑战性的东西。我认为 Kubernetes 对于这些大型复杂部署也起到了类似的作用。现在,许多基础部分被下移了,你只需要专注于完成你的事情。

Erik St. Martin: 我也很喜欢用 kubectl 命令来处理这些东西。这是使用类似第三方资源最棒的事情之一。现在我不是在问 Kubernetes 关于 pod 和复制控制器之类的东西,而是问它关于我的东西,比如获取证书、获取流、获取其他东西。我只需要查看这些内容;如果有某种控制器在运行,监控集群的状态,你可以更新资源的状态,然后你就能看到,“嘿,这是我的 TLS 或 LetsEncrypt 的状态,或者……”

Brian Ketelsen: ……或者我的有线电视频道。

Erik St. Martin: 或者我的有线电视频道。严格来说,是一组频道。它是介于两到八个、两到十个频道,以及一个复用屏幕之间的。

Brian Ketelsen: 我迫不及待想听这个演讲了。但首先,我们需要聊一聊 Code School 的新课程。

插播:

Erik St. Martin: Kelsey,Kubernetes 接下来会有什么新东西?有什么特别让你兴奋的即将到来的功能吗?

Kelsey Hightower: 是社区……你知道的,我们有集群联邦(Cluster Federation)。今天早上我刚做了一个演讲,讲的是如何更轻松地管理多个集群。目前,Kubernetes 让管理多台机器变得容易;而 Kubernetes 联邦将使管理多个集群变得容易。在 1.4 版本中,我还在 GitHub 上发布了一个名为 Kubernetes Cluster Federation 的教程,教你如何构建多个集群,然后将它们连接在一起,并开始使用新的联邦功能将多个集群作为一个集群进行交互。所以,如果你有兴趣,可以去看看那个教程。

对我来说,这是最有趣的事情之一,因为我们希望人们对拥有多个集群感到放心,这样你就不需要一个大集群跨越多个数据中心---那会是个灾难---但我们让它变得简单,这样大家就能轻松地做正确的事情。Kubernetes 社区必须站出来---我们确实做到了---而集群联邦让你能够正确地完成任务。我认为这是一个游戏规则的改变者。

Erik St. Martin: 是的,我知道对我来说,这个联邦功能出来后,直接让我省去了一个原本需要构建的部分。因为同样的问题是分布在全球的多个数据中心,它们由不同的团队维护。所以我还没开始构建联邦功能,但我对此印象深刻。就像每次新版本发布,我都能删除一些代码,这种感觉很棒。

Brian Ketelsen: 说到改变游戏规则的事情,我们聊聊 Kelsey 和他的现场代码演示吧。如果说有任何一个人在会议历史上改变了规则,那就是 Kelsey 和他即兴的现场演示。我不知道你是否在 2014 年的 GopherCon 之前就做过这样的事,但当时你在幻灯片上启动容器时震惊了整个世界。

Erik St. Martin: 他从容器中 PXE 启动了一个虚拟机……

Kelsey Hightower: 说实话,我想告诉你们……我并没有通过上大学学会这些东西,很多人也一样。对我来说,尤其是在早期,真正学会这些概念的唯一方法就是让它运行起来。当你第一次让它运行成功时---你们应该能体会这种感觉---你会开始跳起那种小舞步;你戴着耳机,家人看着你觉得你疯了。而这种感觉就是技术向你证明它在为你工作,而不是你在为它工作的时候。

所以,当我做演讲或者有机会站上舞台时,我真的希望人们能在尽可能短的时间内感受到这种感觉。我认为现场演示让我作为一个演讲者保持诚实,专注于事实,专注于真正有效的东西。同时,它也让其他人能够感受到甚至重温我第一次让它成功运行时的那一刻,他们亲眼看到它运行起来。我觉得很多人看到这样的演示会受到启发,比如“你知道吗?如果他能在 20 或 30 分钟内做到这一切,还把步骤放在了 GitHub 上,我没有理由不去做完全相同的事情。”我认为这对人们来说很有激励作用,对我自己也是。

对我来说,现场演示是我的必备环节,只是为了确保我作为演讲者完成了我的工作。这也是我的一种依赖方式。虽然现场演示有风险,但回报似乎是巨大的。

Erik St. Martin: 我不会撒谎,昨晚我和 Brian 聊到怎么才能超过 PXE 启动的演示,我想到了通过现场启动一个有线电视流,但后来我担心带宽问题。在会议上带宽从来都不太好。

Kelsey Hightower: 是啊,不过现在既然这个挑战已经提出了,我期待你去实现它。现在如果失败了……[笑声] 你最好准备好应对。

Brian Ketelsen: 通常,演讲者会有专属的有线以太网接入,不仅仅是 Wi-Fi 网络。我觉得你不能用这个借口,Erik。我想看到你在舞台上,从你的笔记本电脑上广播电视……

Erik St. Martin: 如果我把流限制为一个节目,我可能可以通过有线连接实现。但通常来说,这是一个 38/8 的流。

Kelsey Hightower: 听着,各位,如果你要准备一个现场演示,请不要像 Erik 现在这样准备。如果你要做,就去做。你得掌控它。[笑声] 选择一个用例,然后不惜一切代价让它成为可能。因为最终的结果是---去做吧,伙计!别再胡思乱想“如果这样如果那样”了---没人想听这些。你上台,完成你的演示……别告诉我们你的计划,我会在 KubeCon 上看到它,确保你实现了。

Brian Ketelsen: 挑战已经抛下了。

Erik St. Martin: 好吧。我觉得你确实有一种非常有创意的方式向人们解释事情。这不仅仅是现场演示。今年的 GopherCon 上,你做了一个关于编写你自己的调度器并用俄罗斯方块(Tetris)来解释的演讲。那太棒了!你把一件看起来很复杂的事情,比如如何将资源高效地分配到节点上---大多数人会觉得这是一个不想碰的工作。我不会想去写调度器。但你把它拆解成了这些易于理解的概念,用俄罗斯方块的方式来思考。每个人都能理解俄罗斯方块。

我觉得这也是人们喜欢看你演讲的原因---你把那些看起来遥不可及的事情带到了每个人都能联系上的层面上。

Kelsey Hightower: 谢谢,这正是我的目标。我尽量花更多时间去理解某样东西,而不仅仅是学习它。如果我觉得自己已经理解到可以用一个电子游戏来表达它的程度,那我就觉得自己准备充分了。

Carlisia Thompson: Kelsey,我想问你一个问题,稍微换个话题---你希望 Go 作为一种语言,在成熟过程中如何发展,以支持像 Kubernetes 这样显然非常复杂且规模巨大的项目?我很好奇,你认为在哪些方面可以获得更多支持?比如来自社区、语言本身或生态系统的支持。

Kelsey Hightower: 我觉得我们已经得到了不少支持。当我们遇到问题,比如不得不停留在 Go 1.4,或者面对 Go 1.6 的一些问题时,Go 团队介入并使用 Kubernetes 来帮助定位和解决性能问题,对我们来说是非常大的帮助。在 Go 社区里,大家使用这个项目并给我们反馈,甚至直接查看我们的代码并指出:“嘿,其实有更好的方式来实现这些功能。” 这些都对 Kubernetes 帮了不少忙。

对于 Kubernetes 来说,包管理的问题也被提升到了新的高度。对于一些小项目而言,没有一个统一的解决方案来处理包和第三方依赖问题是可以接受的,但在 Kubernetes 这种项目中,依赖链非常庞大,甚至项目自身的内部依赖也很复杂。所以,我觉得 Go 的原生 vendoring(供应目录)功能是一个很大的进步。而在第三方依赖管理方面的所有进展,对 Kubernetes 和我们的社区来说都会是很大的帮助。同时,对于那些编写 Golang 代码并使用 Kubernetes,或者对分布式系统感兴趣的人来说,提供更好的示例代码也会对我们的社区和项目大有裨益。此外,我们也希望更多的 Golang 专家能为 Kubernetes 作出贡献。

在我们项目里,有很多人其实也是 Go 的新手。这并不是坏事,但我们始终可以从那些拥有 Go 专业知识的人那里获益,包括帮助重构、清理代码库,以及向我们的社区传授他们积累的最佳实践。

Erik St. Martin: 是的,而且 Kubernetes 还有很多 Special Interest Groups(特殊兴趣小组),如果你对 Kubernetes 项目的某些特定领域感兴趣,比如调度器、应用部署或者网络部分……其实我甚至都记不清所有的小组了,但你可以参与其中。大多数小组每周都会有会议之类的活动。

这是一个庞大的项目,涉及很多领域,但你可以很容易找到一个自己感兴趣的小范围,然后和其他人一起快速上手 Kubernetes 的某一部分。

Kelsey Hightower: 我也应该提一下,我是个非常务实的人,我不会只是抱怨某种语言缺少某些功能,真的。Go 对于 80%-90% 的使用场景已经处理得很好了。当然,总会有一些差距,这可能来源于某种语言的特性或者个人的偏好。但我觉得,对于我想做的事情,Go 的任何不足都没有阻碍我的执行能力。很多人喜欢抱怨,比如 “如果 Go 有泛型就好了”,或者 “如果 Go 有某某功能就好了”。我理解这些诉求,如果这能帮助大家提高,那我完全理解。但我没有看到 Go 存在任何明显的短板阻碍人们实现自己的想法。而且我认为,这才是衡量 Go 的方式。

人们是否能够实现自己的目标?Go 是如何帮助他们的?当然,我们可以讨论 Go 是如何在某些方面限制了他们,但从人们正在交付的产品来看,Go 确实在这方面表现得非常出色。

Erik St. Martin: 我觉得你说得很好,有一个可行的解决方案总比没有解决方案要好,对吧?

Kelsey Hightower: 没错。

Carlisia Thompson: 回到你刚才提到的内容,Kelsey,我只能想象作为 Kubernetes 的贡献者团队,你们肯定总结了大量的最佳实践和优秀做法。有没有可能将这些最佳实践整理成一个合集?我觉得社区非常需要这样的东西。大家一直在问,但这些内容总是有点神秘。你知道它存在,但如果能有某种形式的清单或指南放在某个地方,那就太好了。

Kelsey Hightower: 我不确定我们是否真的拥有所有的 Go 专家或者所有的最佳实践。我觉得 Kubernetes 团队会亲口告诉你,他们也是在边做边学。如果你想想看,这两个项目都不算很老。所以,许多为 Kubernetes 做贡献的人,其实是在第一次学习 Go 的过程中开始参与的。我觉得我们就像是 Go 社区的一个缩影。我们有一些长期使用 Go 的开发者在为项目贡献代码,也有一些刚刚接触这门语言的新手。但我觉得这恰恰体现了 Go 的一个优势---你可以直接参与到一个非常大的 Go 代码库中,开始贡献。

但另一方面,由于 Go 相对年轻,我们确实有一些最佳实践,但 Kubernetes 甚至挑战了一些这些最佳实践,因为它们可能不适用于我们的需求。所以我认为这是一个很大的权衡,而这些问题在 Code Bubble 的一些讨论中正在逐渐浮现。

Brian Ketelsen: 我在节目笔记中提到了一些有趣的 Go 项目和新闻,这通常是我们下一个环节的主题,但现在提到也很合适。Tim Hawkin 发布了一个 Go Build Template,这是直接从 Kubernetes 中提取出来的。Go Build Template 是一个 makefile 和 Go 项目结构的组合。它允许你构建一个 Go 应用程序,并能在 Docker 支持的所有平台上运行。这个 makefile 非常优雅,所有的代码也都很棒。你只需要克隆这个 Go Build Template,添加你的代码,就可以拥有一些关于构建、测试和组织你应用程序的非常优秀的最佳实践。当我第一次看到它时,我非常喜欢。我记得他是在两三天前发布的,我立刻标记了这个项目。这个模板展示了如何在容器化的背景下,从构建和测试的角度来管理一个 Go 应用程序。整个 makefile 简直像一件艺术品,非常出色。

Kelsey Hightower: 沿着这个思路,我还认为 Kubernetes 的端到端测试非常了不起。我们管理着一个庞大的分布式系统,有很多动态的组件,但我们有非常精细的端到端测试。这些测试直接从代码库中拿出真实版本,测试用户的端到端功能。我们并不完全依赖单元测试和模拟测试,而是直接启动所有的组件,通过 Kubernetes 运行真实的操作,来发现生产环境中用户可能遇到的真正问题。这些测试对于保持 Kubernetes 的相对稳定性来说是一个宝库。我们以稳定性闻名,同时我们在引入新功能方面也很大胆。

所以这里的一个最佳实践是广泛使用 alpha。我认为我们在 API 中非常明确地标注了:“这是一个 alpha 功能,API 和实现可能会发生变化。” 然后它会进入 beta 阶段,这个阶段可能持续几个月甚至一年,如果需要的话,最后才会进入稳定阶段(stable)。我觉得这是任何大规模、高度使用的项目,甚至任何规模的项目都应该考虑的一种非常好的实践---将 API 从 alpha 推进到稳定版本。一旦它们成为 v1 稳定版,你必须承担起维护的责任,不能随意更改或移除,因为这样用户才会信任你的项目和 API。

Carlisia Thompson: 这是一个很棒的概念。我之前稍微看了看你们的 API 测试,我觉得看到了一些你提到的内容。这听起来是一个很好的方式,就像你说的那样,通过类似生产环境的集群来维护集成测试,并将其作为测试阶段的一部分。

Brian Ketelsen: 我下周在波士顿的培训课程中会教授一个关于如何测试真实世界应用程序的模块,也会讲到如何测试真实的 Go 应用程序。其中大概有四次引用了 Kubernetes,因为 Kubernetes 的测试确实是顶尖的。在分布式应用中,他们成功测试了非常难的部分,这真的很令人印象深刻。他们在 Kubernetes 中对这些进行了测试,所以你几乎不会看到有问题的 Kubernetes 版本发布。这就是实实在在的最佳实践。

Erik St. Martin: 我觉得当我们考虑大型项目中语言的惯用用法时,有一点需要注意:我们不能对这些大型项目抱有过高的期望,认为它们一定是完全惯用的 Go 代码。这些项目有来自各地的许多贡献者,每个人的背景都不同。我们可以看看其他地方的例子,比如 Ruby on Rails。如果你看它的代码库,我敢说你也会发现很多非惯用 Ruby 代码的例子。

所以,这只是一个想法。虽然我们希望这些项目能够尽可能地符合最佳实践,但在大型项目中发现一些不符合语言惯用用法的代码并不奇怪。

Kelsey Hightower: 对。

Brian Ketelsen: 我在想这个问题,我们刚才也聊到过。关于树莓派(Raspberry Pi),其中一个问题是它能连接的设备数量有限。但如果我们把它联邦化,做成一个树莓派的集群呢?我手头正好有大概20个树莓派放在抽屉里……为什么不将它们组成一个联邦集群,每个负责收集一部分信息?这样你就可以在烧烤炉里的每个食物上放肉类温度计,然后把所有数据汇总在一起。这种方式,要么做到极致,要么干脆别做。

Erik St. Martin: 它现在占用很多资源吗?

Brian Ketelsen: 你开玩笑吗?我发过一张截图,上面显示的是 top 命令运行结果,当时 Prometheus 和 Qpid 同时运行,负载只有 0.03 之类的……几乎没占用什么资源。树莓派的性能根本没被触碰到。

Erik St. Martin: 你已经在考虑需要联邦化了吗?

Brian Ketelsen: 不,不是担心。我只是觉得,如果能做到,那就应该做啊。[笑声] 做到极致。

Erik St. Martin: 我们可能有点突然插入这个话题了,Kelsey,你有没有想要推荐的项目?

Kelsey Hightower: 我想说,文档这是在毁掉所有人。不管是运维(Ops)还是开发(Dev),大家都因为缺乏文档而崩溃。我们都花了太多时间在反向工程上,去研究我们找到的那些库。所以我特别想向 Ben Johnson 致敬,他花时间为一些非常棒的库和管理工具(比如 BoltDB,我在很多项目中用到它)写了文档。我们应该感谢他的文档。如果 Medium 是一个代码库,那么他往里面写的文档就太疯狂了。

现在人们终于开始真正了解这些东西了。尽管我们喜欢使用各种库,但文档才是真正让人进步的东西,它能让人达到一个可以产出我们今天所讨论这些工具的水平。所以我们往往没有给予文档应有的重视。这些工具需要操作手册,对吧?所以我要为 Ben Johnson 的文档致敬。他过去几个月写的许多文章都非常棒。这就是我的推荐。

Brian Ketelsen: 太棒了,这是个好推荐。

Carlisia Thompson: 完全同意!谁要讨论那个 “idiomatic Go(惯用 Go)” 的话题?

Erik St. Martin: 抱歉,是指……?

Carlisia Thompson: 是在项目和新闻板块里的吗?

Kelsey Hightower: 是的,他对字节(bytes)以及标准库中的一些不同的包进行了深入剖析,并花时间详细说明这些东西是如何工作的。他以一种标准库文档里找不到的方式来写,从人对人的交流角度出发,比如“这是个什么东西,让我们深入探讨,并给你一些具体的思考方向。” 这帮助了很多人,包括像我这样的有经验的 Gopher(Go 开发者)。当你从这个角度去阅读时,会对这些东西有更深的理解。所以,任何时候我们的社区有人能做到这一点,它的影响都会很大---无论是为你的库写文档、项目示例,还是为别人写的库提供文档支持。这些贡献虽然不是直接被大家导入到源码中的东西,但它们非常有价值。

Erik St. Martin: 是的,还有示例代码(example code)。因为有时候你看了文档,还是无法理解,直到你看到有人用某个库或项目写的代码示例,才会真正明白。

我觉得我们已经超时10到12分钟了,可能该结束节目了。

Brian Ketelsen: 哦,天啊……

Erik St. Martin: 除非我们都想在这里待上一整天。

Brian Ketelsen: 哦,天啊……!

Carlisia Thompson: [笑声] 又超时了……

Erik St. Martin: Brian,你说你要出差,对吧?所以你不会去参加 KubeCon。

Brian Ketelsen: 是的,我应该会在阿姆斯特丹。

Erik St. Martin: 那我就能跟 Kelsey 一起玩了,而你却在另一个国家。

Brian Ketelsen: 但我会想念你们的。

Erik St. Martin: 所以现在你可能会有点嫉妒了,因为我们要结束这个节目了,而我会和 Kelsey 一起玩,而你不能……

Brian Ketelsen: 哦,天啊…… [笑声] [叹气] FOMO(害怕错过)。

Erik St. Martin: 我要感谢今天所有参与节目的嘉宾……特别感谢 Kelsey 百忙之中抽空来和我们聊 Kubernetes 的一切内容。感谢所有听众,特别是那些正在 GoTime FM 频道互动的朋友们。还要感谢 Linode 和 Code School 对本期节目的赞助;没有他们,我们就没办法上线。

还要感谢 Carlisia 的雇主 Fastly,为本期节目以及所有 Changelog 节目提供 CDN 服务。记得将节目分享给任何你觉得可能感兴趣的程序员朋友。你可以在 GoTime.fm 订阅我们,我们的 Twitter 是 @GoTimeFM。我应该都提到了吧,那就这样吧,再见啦,大家!

Brian Ketelsen: 谢谢,Kelsey。

Kelsey Hightower: 谢谢你们邀请我!

Carlisia Thompson: 再见!这次节目真棒!





好文收藏
38 声望6 粉丝

好文收集