Skip to main content

不止于Kubernetes,开发人员应着眼于更多适合云原生应用的范式

本文由本人整理,发表在CSDN平台并署名【小雨青年】。

发布地址 : https://blog.csdn.net/m0_46700908/article/details/124809054

整理 | 小雨青年 校对 | 西狩

出品 | CSDN云原生

声明:本文出自CNCF网站,最初由Michael Vittrup Larsen在Eficode博客上发表。CSDN将文章翻译成中文,分享给大家。

Kubernetes在容器编排中无处不在,其受欢迎程度尚未减弱。然而,这并不意味着容器编排领域的发展处于停滞状态。本文将说明为什么Kubernetes用户,尤其是开发人员,应该超越我们在过去几年学到的传统Kubernetes,而转向可能更适合云原生应用的范式。

一、Kubernetes的崛起

通过构建容器镜像来冻结依赖关系并得到一个“随处运行”的体验,再结合Kubernetes Development资源规范来管理容器副本的编排,这是非常强大的。然而,这与我们在没有 Docker和Kubernetes之前操作虚拟机的方式并没有本质上的不同。这个小小的思维飞跃使我们很容易采用Kubernetes,但这也是我们应该超越“传统”的Kubernetes的原因。

本文将从开发者的角度审视Kubernetes的未来。一般来说,当今的Kubernetes将会消失,开发者也不会在意。这并不是说我们的技术栈中不会有Kubernetes,而是我们将使用新的抽象来改进构建和操作应用程序的方式,而这些抽象本身是建立在Kubernetes之上的。

应用程序将使用建立在Kubernetes平台上的平台来行构建。

Kubernetes是一个构建平台的平台。这是一个很好的起点,但不是结局。

—— Kelsey Hightower,2017 年 11 月 27 日

有趣的是,Linux是我们十多年前构建一切的基础平台。如今Linux仍然无处不在,并且是我们技术栈的一部分,但很少有开发人员关心它,因为我们已经在其上层添加了一些抽象。这和传统的Kubernetes所要发生的事情是一样的。

二、新范式一扫而光

安全性:OIDC优于Secret

Kubernetes提供Secret资源来指定静态机密信息,例如API密钥、密码等。开发人员不应使用Kubernetes Secret资源。

在Secret资源中,编码的显式机密信息可能会被泄露,并且难以轮换和撤销。对于GitOps工作流程,还需要特别注意机密信息避免以明文形式存储。应用程序应采用基于角色的方法来进行身份验证和授权。这意味着应用程序身份验证和授权应该基于“我们是谁”,而不是“你知道的东西”(密码、API密钥)。

强大的身份认证是所有安全的基础。如果你不确定与你通信的服务器的身份,那么对网络流量进行加密是没有意义的。这就是证书和证书授权机构对HTTPS流量的作用,这通常能保证互联网的安全。

Kubernetes有一个强大的工作负载识别系统。所有工作负载都与服务账户相关联,并且它们具有由Kubernetes发布的短期OpenID-Connect(OIDC)身份令牌。Kubernetes API服务器签署这些OIDC令牌,其他工作负载可以通过Kubernetes API服务器验证令牌。这为在Kubernetes上运行的工作负载提供了强大的身份,可以作为基于角色的身份验证和授权的基础。

开发人员不应使用Kubernetes Secrets,而应基于OIDC令牌进行身份验证和授权。这意味着,我们应该确保我们的数据库仅在提供有效的、未过期的令牌时才接受请求,而不是将数据库密码存储在Secret资源中。

使用OIDC令牌与外部系统集成的示例有服务账户的AWS IAM角色和Hashicorp Vault Kubernetes身份验证。

网络:Ingress不如所期待的那么好

Kubernetes提供了一个Ingress资源来指定如何将HTTP流量路由到工作负载中。正如Tim Hockin(Kubernetes联合创始人)承认的那样,Ingrees资源存在很多问题,主要问题是它只能让我们管理HTTP流量路由最基本的东西。允许开发人员使用入口资源将是基础设施和站点可靠性工程(SRE)团队的一个头疼问题,他们需要互连广泛的基础设施并使其可靠运行。Ingress资源过于简单,开发者不应该用它来配置网络。

服务网格的兴起可以看出Kubernetes网络对更多控制和可编程性的需求。它们将Ingress资源划分为多个资源,以便更好地分离职责,并在路由、可观察性、安全性和容错方面提供额外的功能。

越来越多建立在Kubernetes之上的抽象假设了一个可编程的网络,超过了Ingress的可能性(Knative、Kubeflow、连续部署工具如Argo Rollouts等)。这强调了在Kubernetes中,一个更健壮的网络模型已经是事实上的标准。

Kubernetes社区已经发展出了一个“Ingress v2”——网关API。虽然这解决了Ingress的一些问题,但它只涵盖了大多数服务网格支持的一小部分功能。

Kubernetes支持ACL来限制哪些工作负载可以通过NetworkPolicy资源进行通信。该资源在Kubernetes网络插件中实现,并且通常转化为Linux Iptables过滤规则,即类似于防火墙的基于IP地址的解决方案——又一个旧范式。一些服务网格扩展了强大的基于Kubernetes OIDC的工作负载身份,以实现工作负载之间的相互TLS。这基于比IP地址更强大的原则,为Kubernetes网络通信带来了机密性和真实性。

在Kubernetes应用程序打包中,就如何包含网络配置方面存在一些分歧。许多Helm图表都带有Ingress资源模板。然而,随着我们转向更高级的网络模型,这些定义将无法使用。展望未来,像Helm图表这样的应用程序部署应该将网络配置视为一个正交问题,应该将其排除在应用程序部署工件之外。关于应用程序网络配置,可能没有万能的解决方案,用户很可能希望开发自己的“应用程序路由”部署工件。

Kubernetes通过在集群中的所有节点上创建一个同构网络来简化网络。如果您的应用程序是多集群或多云,它可能同样受益于跨集群或云的同构网络。Kubernetes网络模型无法这样做,所以你需要更强大的东西,比如服务网格。

因此,从组织和架构的角度来看,有几个原因可以说明开发人员不应使用Ingress资源对网络进行编程,而必须从整体组织角度考虑选择,以确保网络配置和管理的可管理性与长期可行的方法。

工作负载定义:切中要害

实际上,几乎所有Kubernetes应用程序的核心都是Deployment资源。Deployment是一种资源,它以Pod内的容器形式定义了我们的工作负载应该如何执行。可以使用HorizontalPodAutoscaler(HPA)资源来控制部署扩展,以适应不同的容量需求。HPA通常使用容器CPU负载作为添加或删除Pod的衡量标准,并且由于HPA算法的目标利用率通常在70%左右,这意味着我们的设计浪费了30%。使用保守目标利用率的另一个原因是HPA通常需要一分钟或更长的响应时间。为了处理不同的容量需求,我们需要一些备用容量,而HPA会添加更多Pod。

如果我们的应用程序能看到缓慢变化的容量需求,则使用Deployment和HPA管理工作负载的效果会很好。然而,随着向微服务、事件驱动架构和功能(处理一个或几个事件/请求然后终止)的转变,这种形式的工作负载管理远非理想。

Kubernetes Event-Driven Autocaler(KEDA)可以改善微服务的扩展行为和快速变化的工作负载(如函数)。KEDA定义了自己的一组Kubernetes资源来定义扩展行为,并且可以被视为“HPA v3”(因为 HPA 资源已经处于“v2”)。

Knative是一个结合了Kubernetes部署模型、扩展以及事件和网络路由的框架。Knative平台建立在Kubernetes之上,并通过Knatice-Service资源对工作负载管理采取了有见地的观点,其核心是CloudEvents。Knative 服务基本上是由CloudEvents或普通HTTP请求等事件触发和扩展的功能,Knative使用Pod Sidecar来监控事件率,因此可以根据事件率的变化快速扩展。Knative还支持缩放到零,因此允许更细粒度的工作负载缩放,更适合微服务和函数。

Knative服务是使用传统的Kubernetes Deployment/Services实现的,对Knative服务的更新(例如新的容器镜像)会创建并行的Kubernetes部署/服务资源。Knative使用它来实现蓝/绿和金丝雀部署模式,HTTP流量的路由也是Knative服务资源定义的一部分。

因此,Knative服务资源及其用于定义事件路由的关联资源成为开发人员在Kubernetes上定义其应用程序部署时使用的主要资源。就像我们现在经常通过Deployment资源与 Kubernetes交互,让Kubernetes来处理Pod一样,使用Knative意味着开发者将主要关注 Knative服务,而Deployment由Knative平台处理。

虽然我希望Knative模型适用于大多数用例,但实际的应用范围可能会有所不同。如果你正在做机器学习,那么也许Kubeflow很适用;如果您更专注于DevOps和交付管道,那么Kpack、Tekton或Cartographer可能更好的选择。

存储:摆脱持久卷的束缚

Kubernetes提供PersistentVolume和PersistentVolumeClaim资源来管理工作负载的存储。它可能是我最不喜欢的资源,因为它允许开发人员将其用于除临时缓存数据之外的任何内容。

从高层次的角度来看,PersistentVolumes(PV)的一个问题是它将应用程序的主要关注点与存储关注点结合在一起,这不是理想的云原生设计模式。十二要素应用程序方法论指导我们将任何支持服务视为网络附加服务,这是因为我们要在Kubernetes中横向扩展工作负载和数据管理(如CAP定理)。

PV代表文件和目录的文件系统,我们使用POSIX文件系统接口对数据进行操作。访问权限也基于POSIX模型,允许用户和组进行读取或写入访问。这种模型不仅与云原生应用程序设计匹配度差,而且在实践中使用起来也很棘手,这意味着大多数情况下,PV以“容器可以访问所有数据”的模式安装。

开发人员应该构建有状态的应用程序,而这些应用程序是无状态的。 这意味着应该在应用程序外部使用文件系统以外的其他抽象来处理数据,例如在数据库或对象存储中。数据库和对象存储应用程序可能会使用PV来满足其存储需求,但这些系统应由基础设施/SRE团队管理,并由开发人员作为服务使用。

当我们将存储视为网络连接时(例如通过REST API进行对象存储),数据安全性可能会得到显著提高。使用REST API,我们可以通过上述基于Kubernetes工作负载身份的短期访问令牌来实现身份验证和授权。

随着采用无服务器工作负载模式,我们应该期待更多动态和更短寿命的工作负载(例如,无服务器功能处理每个Pod的一个事件)。在这种情况下,工作负载和“老式磁盘”之间的不匹配变得更加明显。

在Kubernetes中,容器存储接口(CSI)一直是通过PV向工作负载添加文件系统和块存储的接口。Kubernetes对象存储特别兴趣小组正在开发一个容器对象存储接口(COSI),它可能会将对象存储变成Kubernetes中的一等公民。

三、勇敢的新世界

在本文中,我认为在定义Kubernetes应用程序时,有充分的理由超越“传统”的Kubernetes 资源。当然,这并不是说我们永远不会使用传统的资源类型。事实上是,我们仍然会遇到无法轻易转换的遗留应用程序,SRE团队可能仍然需要运行有状态的服务,这些服务可以被开发人员构建的应用程序使用。私有云基础设施尤其如此。

Kubernetes的未来在于我们在Kubernetes之上构建并通过自定义资源定义(CRD)向用户提供的CRD和抽象。 Kubernetes成为抽象的控制面板,开发人员应该关注这些抽象的CRD。Kubernetes控制面板可以管理Kubernetes内部甚至Kubernetes外部的资源,例如Crossplane管理员基础设施。

img

综上所述,大部分传统的Kubernetes资源对于开发者来说可能有更好的选择。使用替代方案将改善我们在未来几年开发和操作云原生应用程序的方式。毕竟,Kubernetes是一个搭建平台的平台,并不是最终目标。