从容器革命一开始就有两件事情很清楚:首先,技术堆栈中各层的去耦产生了一个清晰、原则性的概念分层(明确的合同、所有权和责任)。其次,引入这些层使开发人员能够专注于对他们来说最重要的事——应用程序。
公平地说,这种情况之前发生过,第一代平台即服务(PaaS)就是旨在使开发人员能够采用“无服务器”架构 。麻烦的是,就像许多第一波产品一样,太多重叠的概念被混合到一个单一的单体产品中。就大多数第一代PaaS而言,开发者体验、无服务器和定价模式(基于请求的)是以不可分割的单体形式混合在一起的。因此,可能想要采用无服务器但不要开发者体验(如特定编程语言)的用户,或者追求大型应用程序的更具成本效益的定价模型的用户,不得不放弃无服务器计算。
容器的发展改变了这一切,从无服务器运行时中解耦开发人员的体验。因此,过去一年无服务器容器基础设施的发展并不令人意外。去年七月,Azure发布了Azure Container Instances——这是第一个大型公有云中的无服务器容器产品(但公平地说,hyper.sh的人更先进入市场)。看到重要用户对无服务器基础设施的兴趣,其他公有云纷纷跟随Azure的步伐,如Fargate六个月后在RE:Invent 2017上被宣布。笔者认为,在所有公有云中都会有无服务器容器基础设施可用,只是一个时间问题。
一个越来越清楚的趋势是,未来是容器化的,而这些容器将在无服务器基础设施上运行。
那么一个显而易见的问题就是:在这个无服务器的未来里,编排会变成什么样?
Kubernetes是一种用于提供运行容器的无服务器体验的技术。但事实是,在低层次上,Kubernetes架构本身是有深度意识的单个机器,并且从调度器到控制器管理器的组件假定Kubernetes中的容器存在于Kubernetes可见的机器上。
像Azure Container Instances这样的无服务器容器基础设施是原始基础设施。虽然它是轻松运行一些容器的好方法,但构建复杂的系统需要开发一个编排器来引入更高层次的概念,如Services、Deployment、Secrets等。
对于这些无服务器平台,开发一个全新的编排器可能充满诱惑,但事实是,全球正在围绕Kubernetes编排API进行整合,并且与现有Kubernetes工具的无缝集成非常有吸引力。此外,在可预见的将来,笔者预计大多数人的Kubernetes集群将是专用机器和无服务器容器基础设施的混合体——专用机器将用于相对静态使用的稳态服务或专用硬件(如FPGA或GPU),而无服务器容器将用于突发或瞬态工作负载。
虚拟Kubelet与Kubernetes和无服务器容器相结合
Kubernetes社区面临的一个有趣的问题是,如何将无服务器容器基础设施与更高层次的Kubernetes概念相结合。最近,开源虚拟kubelet项目的开发在Kubernetes节点和调度SIG的讨论里备受关注。
虚拟kubelet项目本质上旨在桥接无服务器容器和Kubernetes API。正如你从名字中可以看出的那样,虚拟kubelet是Kubernetes kubelet守护进程的替代实现,它将虚拟节点投影到Kubernetes集群中。这个虚拟节点代表无服务器容器基础设施,使Kubernetes调度器意识到它可以将容器调度到无服务器容器API上。
当虚拟kubelet启动时,它将自己注册到Kubernetes API服务器,并立即启动与Kubernetes API服务器的心跳协议,以便它添加到Kubernetes的虚拟节点看起来健康。你可以在下面的屏幕截图中看到这个过程。最初有一个标准的Kubernetes集群,其中有三个实际节点存在于该集群中。然后,我们开始在此集群中运行虚拟kubelet即容器,并将第四个节点添加到集群中。第四个节点是虚拟节点,代表无服务器容器基础设施。当然,这个节点是一个相当特殊的节点,因为它代表了在Azure Container Instances等无服务器基础设施上运行容器的无限容量。
在无服务器基础设施上运行的容器和在Kubernetes中的机器上运行的容器有着定价和特性上的差异。鉴于这种差异,虚拟kubelet要求用户必须明确选择在新的虚拟节点上运行容器。为了实现这一点,虚拟kubelet使用Kubernetes关于taint和toleration的概念。添加后,虚拟节点标记为Kubernetes taint,防止将任意pod调度到该虚拟节点。只有当一个pod表明它愿意容忍这个无服务器taint时,才会考虑将该pod调度到该虚拟节点上。
一旦将该pod调度到无服务器虚拟节点上,虚拟kubelet会注意到这一点,并着手在无服务器基础设施中实际创建容器。在无服务器基础设施中成功创建pod之后,虚拟kubelet还负责将健康和状态信息报告给Kubernetes API服务器,以使所有API和工具按预期工作。
Kubernetes和无服务器容器基础设施的这种结合在批处理或突发工作负载方面有各种实际用例。例如,正在进行图像处理的用户可以快速启动大量容器,以处理最近一次的将图像上传到共享存储,在几秒钟内就可以从无基础设施变成数百个处理图像的容器,并且在此处理完成后,用户立即回去而不用为容量付钱。这与在虚拟机之上运行的Kubernetes集群形成了鲜明的对比——无论这些机器是否在使用,运行机器的成本都是不变的。同时,这种图像处理的实际编排可以使用标准的Kubernetes概念来实现,例如可以调度所有这些图像处理容器的Job对象。
让Kubernetes与无服务器容器兼容
看到虚拟kubelet项目在云计算行业的发展和增长势头真是令人兴奋,从创业公司到公有云的众多合作伙伴加入,并为将无服务器容器与Kubernetes结合在一起努力。
当然,这并非一帆风顺。正如我们已经探索过的关于这种整合,很明显,将Kubernetes与无服务器容器基础设施联系起来意味着重大挑战和开放性问题。虽然Kubernetes为用户提供了一个面向容器的API,但当你查看这个API的实现细节时,会发现它显然是建立在“这些容器之下有机器”的概念之上。当然,使用无服务器容器基础设施(如Azure Container Instances)时,这些机器不再存在,而这会与现有的Kubernetes基础设施产生冲突。
举一个非常简单的例子,我们在部署虚拟kubelet时最早注意到的一件事是,在部署虚拟kubelet的集群中,有外部负载均衡器的Kubernetes Services会停止正常工作。当我们检查这种情况时,发现原因很明显。负责创建和维护云负载均衡器的Kubernetes控制器管理器试图向云负载均衡器注册虚拟节点。但是,此节点并不真正存在,因此无法添加到负载均衡器,从而导致无法创建负载均衡器的错误。使用Kubernetes 1.9,我们添加了flag,以便可以明确地在负载均衡器中阻止由Kubernetes创建的节点,因此解决了这个问题。
当考虑Kubernetes调度器时,会出现更重要的问题。Kubernetes调度器的构建是为了确信每个单独节点都是一个故障域,因此将容器分散到多个不同的节点是一件好事。当每个节点是一个物理机或虚拟机时,这确实是件好事,因为每个节点都可能发生故障或恐慌,从而摧毁该节点上的所有容器。但是,对于虚拟kubelet而言,情况变了。无服务器容器基础设施本身具有容错能力,并且构建在许多不同的机器之上。因此,虽然将多个容器从同一个应用程序调度到一个物理机或虚拟机上可能不安全,但将多个容器从同一个应用程序调度到单个无服务器的虚拟节点上是非常安全的。使用无服务器容器和虚拟kubelet时,节点不再是故障单元。这种不协调和许多类似的调度问题仍然是需要解决的开放性问题。
Kubernetes和无服务器的未来
Kubernetes的构建是为了给开发人员一个干净的、面向应用的API,使他们忘记了机器和机器管理的细节。但事实是,在这个API表面下,机器还在那里。无服务器容器基础设施的发展使人们可以开始完全忘记这些机器,但是为大规模应用程序成功使用无服务器容器需要开发一个编排器。因此,Kubernetes编排层和无服务器容器基础设施的集成对Kubernetes和无服务器基础架构的未来成功都是至关重要的。
笔者完全相信未来的Kubernetes集群将包含运行在专用机器上的容器和突发到无服务器基础设施中的容器的组合。但是,尽管目的地明确,到达那里的路径和细节仍有待确定。笔者非常高兴能与Kubernetes社区进行公开讨论。如果你有兴趣参与,请加入我们的虚拟kubelet github项目,或者参加SIG-Node和SIG-Scheduling的邮件列表或会议。笔者非常高兴能够和你共同构建新一代的容器编排,共同迈向容器化和无服务器的未来!
K8S技术社区评论
Separate of concern(关注分离)在过去的几十年中一直是IT行业发展的最重要原则,我们关注应用而不是硬件基础架构催生了云计算,我们关注分布式系统而不是容器催生了Kubernetes,Serverless技术的出现并和Kubernetes结合是SOC原则的进一步体现,使Developer可以把目光聚焦在Code(业务平面)上而不会被其它平面牵扯精力,毫无疑问Serverless为Kubernetes注入了新的活力,为传统应用更好的Cloud Native化铺平了道路。
——K8S技术社区特约评论员、EasyStack联合创始人兼CTO 刘国辉
本文转移K8S技术社区-Kubernetes核心设计者认为Serverless是Kubernetes的未来