Kubernetes设计和开发四大基本原则

简介: 作者介绍:Saad Ali 是来自Google的高级软件工程师,致力于开源Kubernetes项目。他于2014年12加入该项目并负责Kubernetes存储和volume子系统的开发。他还担任Kubernetes存储兴趣小组的负责人,同时也是CSI(容器存储接口)的协同开发者和maintainer。

作者介绍:Saad Ali 是来自Google的高级软件工程师,致力于开源Kubernetes项目。他于2014年12加入该项目并负责Kubernetes存储和volume子系统的开发。他还担任Kubernetes存储兴趣小组的负责人,同时也是CSI(容器存储接口)的协同开发者和maintainer。在加入Google之前,Saad Ali于微软负责IMAP原型开发项目。

Kubernetes正在迅速成为在分布式系统上部署工作负载的事实标准。在这篇文章中,笔者将通过揭示其设计的一些原则,帮助你更深入地了解Kubernetes。

1、要声明式而不要命令式

一旦你学会在Kubernetes开源编排引擎上部署第一个工作负载(pod),就会遇到Kubernetes的第一个原则:Kubernetes API是声明性的而不是命令式的。

在命令式API中,你可以直接发出服务器要执行的命令,例如: “运行容器”、“停止容器”等。在声明性API中,你声明系统要执行的操作,系统将不断向该状态驱动。   

可以想象成手动驾驶和自动驾驶系统。

因此,在Kubernetes中,你创建一个API对象(使用CLI或REST API)来表示你希望系统执行的操作。系统中的所有组件都会向该状态发展,直到删除该对象。

例如,如果要调度容器化工作负载,不是发出“运行容器”命令,而是创建描述所需状态的API对象、pod:

创建后,此对象在API服务器上保留:

如果容器由于某种原因崩溃,系统将重新启动容器。

要终止容器,请删除pod对象:

为什么要声明式而不要命令式?

声明式API使系统更加健壮。

在分布式系统中,任何组件都可能随时出现故障。当组件恢复时,需要弄清楚要做什么。

使用命令式API时,崩溃的组件可能在它关闭时错过了一个调用,并且需要一些外部组件在它恢复时“赶上”。但是使用声明式API,组件只需查看API服务器的当前状态,即可确定它需要执行的操作(“啊,我需要确保此容器正在运行”)。

这也被描述为“水平触发”而不是“边缘触发”。在边缘触发系统中,如果系统错过“事件”(“边缘”),则必须重放事件以便系统恢复。在水平触发系统中,即使系统错过了“事件”(可能是因为它已经关闭),当它恢复时,它可以查看信号的当前状态并相应地做出响应。

因此,声明式API使Kubernetes系统对组件故障更加健壮。

  • 2、
没有隐藏的内部API

如果你了解各种Kubernetes组件的工作原理,你会遇到Kubernetes的下一个原则:控制平面是透明的,因为没有隐藏的内部API。

这意味着Kubernetes组件用来交互的API和你用来与Kubernetes交互的API相同。结合第一个原则(Kubernetes API是声明式的),这意味着Kubernetes组件只能通过监控和修改Kubernetes API来交互。

让我们通过一个简单的例子来说明这一点。为了启动容器化工作负载,你可以在Kubernetes API服务器上创建一个pod对象,如上所示。

Kubernetes调度程序根据可用资源确定运行pod的最佳节点。调度程序通过为新pod对象监控Kubernetes API服务器来完成此操作。当新的未调度的pod被创建时,调度程序将运行其算法为这个pod查找最佳节点。在调度pod之后(已为pod选择了最佳节点),调度程序不会去告诉所选节点要启动pod。请记住,Kubernetes API是声明式的,内部组件使用相同的API。因此,调度程序更新pod对象中的NodeName字段以指示已经调度该pod。

kubelet(在节点上运行的Kubernetes代理)监控Kubernetes API(就像其他Kubernetes组件一样)。当kubelet看到具有与自身对应的NodeName字段的pod时,它知道改pod已经被调度且必须启动它。一旦kubelet启动了pod,它就会继续为pod监控容器状态,并且只要相应的pod对象继续存在于API服务器中,就会一直让容器保持运行。

删除pod对象后,Kubelet会明白不再需要容器,并终止它。

为什么没有隐藏的内部API?

让Kubernetes组件使用相同的外部API使得Kubernetes可组合和可扩展。

如果由于某种原因,Kubernetes的默认组件(例如,调度程序)不足以满足你的需求,你可以将其关闭并将其替换为自己的使用相同API的组件。

此外,如果你需要的功能尚不可用,则可以使用公共API轻松编写组件以扩展Kubernetes功能。

  • 3、
在用户所在的位置满足他们

Kubernetes API允许存储工作负载可能感兴趣的信息。例如,Kubernetes API可用于存储秘密或配置映射。秘密可以是你在容器镜像中不想要的任何敏感数据,包括密码、证书等。配置映射可以包含应独立于容器镜像的配置信息,例如应用程序启动和其他类似参数。

由于上面定义的没有隐藏的内部API的第二个原则,可以修改在Kubernetes上运行的应用程序以直接从Kubernetes API服务器获取秘密或配置映射信息。但这意味着你需要修改应用程序以意识到它是在Kubernetes中运行。

这就是Kubernetes的第三个原则:在用户所在的位置满足他们。也就是说,Kubernetes不应要求重写要在Kubernetes上运行的应用程序。

例如,许多应用程序接受秘密和配置信息作为文件或环境变量。因此,Kubernetes支持将秘密和配置映射作为文件或环境变量注入pod。

为什么要这么做?
通过进行设计选择,最大限度地减少在Kubernetes上部署工作负载的障碍,Kubernetes可以轻松地运行现有工作负载,而无需重写或大幅改变它们。

  • 4、
工作负载可移植性

一旦在Kubernetes上运行无状态工作负载,下一步自然就是尝试在Kubernetes上运行有状态工作负载。Kubernetes提供了一个功能强大的卷插件系统,可以将许多不同类型的持久存储系统与Kubernetes工作负载一起使用。

例如,用户可以轻松地请求将Google Cloud Persistent Disk安装到特定路径的pod中:

创建此pod时,Kubernetes将自动负责将指定的GCE PD挂载到pod被调度到的节点,并将其挂载到指定的容器中。然后,容器可以在容器或pod的生命周期之外写入GCE PD被挂载到持久数据的路径。

此方法的问题在于pod定义(pod YAML)直接引用Google Cloud Persistent Disk。如果此pod已部署在非Google Cloud Kubernetes集群上,则无法启动(因为GCE PD无法使用)。

这是另一个Kubernetes原则的用武之地:工作负载定义应该可以跨集群移植。用户应该能够使用相同的工作负载定义文件(例如相同的pod yaml)来跨不同的集群可以部署工作负载。

理想情况下,上面指定的pod甚至应该可以在没有GCE PD的集群上运行。为了实现这一目标,Kubernetes引入了PersistentVolumeClaim(PVC)和PersistentVolume(PV)API对象。这些对象将存储实现与存储使用分离。

PersistentVolumeClaim对象用作用户以与实现无关的方式请求存储的方法。例如,用户可以创建PVC对象来请求100 GB的ReadWrite存储,而不是请求特定的GCE PD:

Kubernetes系统将此请求与来自包含PersistentVolume对象的可用磁盘池中的卷匹配,或自动配置新卷以满足请求。无论哪种方式,用于Kubernetes集群部署工作负载的对象都可以跨集群实现移植。

为什么要有工作负载可移植性?

这种工作负载可移植性原则突出了Kubernetes的核心优势:与操作系统使应用程序开发人员不必担心底层硬件的细节一样,Kubernetes将分布式系统应用程序开发人员从底层集群的细节中解放出来。使用Kubernetes,分布式系统应用程序开发人员不必被锁定到特定的集群环境。针对Kubernetes部署的应用程序可以轻松地部署到本地和云环境中的各种集群,而无需对应用程序或部署脚本进行特定于环境的更改(Kubernetes端点除外)。

  • 5、
结论

由于这些原则,Kubernetes更强大,可扩展,可移植且易于迁移。这就是Kubernetes迅速成为在分布式系统上部署工作负载的行业标准的原因。

本文转移K8S技术社区-Kubernetes设计和开发四大基本原则

相关实践学习
深入解析Docker容器化技术
Docker是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux机器上,也可以实现虚拟化,容器是完全使用沙箱机制,相互之间不会有任何接口。Docker是世界领先的软件容器平台。开发人员利用Docker可以消除协作编码时“在我的机器上可正常工作”的问题。运维人员利用Docker可以在隔离容器中并行运行和管理应用,获得更好的计算密度。企业利用Docker可以构建敏捷的软件交付管道,以更快的速度、更高的安全性和可靠的信誉为Linux和Windows Server应用发布新功能。 在本套课程中,我们将全面的讲解Docker技术栈,从环境安装到容器、镜像操作以及生产环境如何部署开发的微服务应用。本课程由黑马程序员提供。     相关的阿里云产品:容器服务 ACK 容器服务 Kubernetes 版(简称 ACK)提供高性能可伸缩的容器应用管理能力,支持企业级容器化应用的全生命周期管理。整合阿里云虚拟化、存储、网络和安全能力,打造云端最佳容器化应用运行环境。 了解产品详情: https://www.aliyun.com/product/kubernetes
相关文章
|
Kubernetes 开发工具 Docker
微服务实践k8s与dapr开发部署实验(2)状态管理
微服务实践k8s与dapr开发部署实验(2)状态管理
281 3
微服务实践k8s与dapr开发部署实验(2)状态管理
|
Kubernetes Docker 微服务
微服务实践k8s&dapr开发部署实验(1)服务调用(一)
微服务实践k8s&dapr开发部署实验(1)服务调用(一)
200 2
|
Kubernetes JavaScript 前端开发
k8s学习--chart包开发(创建chart包)
k8s学习--chart包开发(创建chart包)
695 1
|
Kubernetes Docker Perl
在K8S中,如果是因为开发写的镜像问题导致pod起不来该怎么排查?
在K8S中,如果是因为开发写的镜像问题导致pod起不来该怎么排查?
|
Kubernetes Docker 微服务
微服务实践k8s&dapr开发部署实验(1)服务调用(二)
微服务实践k8s&dapr开发部署实验(1)服务调用(二)
216 0
|
Kubernetes 网络协议 Python
运维开发.Kubernetes探针与应用
运维开发.Kubernetes探针与应用
714 2
|
Kubernetes Cloud Native 搜索推荐
探索云原生技术:Kubernetes在现代应用部署中的角色打造个性化移动体验:从开发到操作系统定制
【7月更文挑战第31天】本文深入探讨了云原生技术的核心组件之一——Kubernetes,并分析了其在现代云计算环境中的关键作用。通过实际代码示例和案例分析,文章揭示了Kubernetes如何优化资源管理、提高部署灵活性以及增强服务的可靠性。读者将获得对Kubernetes操作实践的直观理解,并认识到采用云原生架构对企业数字化转型的推动力。
192 0
|
Kubernetes Cloud Native Go
Golang深入浅出之-Go语言中的云原生开发:Kubernetes与Docker
【5月更文挑战第5天】本文探讨了Go语言在云原生开发中的应用,特别是在Kubernetes和Docker中的使用。Docker利用Go语言的性能和跨平台能力编写Dockerfile和构建镜像。Kubernetes,主要由Go语言编写,提供了方便的客户端库与集群交互。文章列举了Dockerfile编写、Kubernetes资源定义和服务发现的常见问题及解决方案,并给出了Go语言构建Docker镜像和与Kubernetes交互的代码示例。通过掌握这些技巧,开发者能更高效地进行云原生应用开发。
389 1
|
Kubernetes Dubbo 应用服务中间件
带你读《Apache Dubbo微服务开发从入门到精通》—— 三、 部署到Kubernetes(中)
带你读《Apache Dubbo微服务开发从入门到精通》—— 三、 部署到Kubernetes(中)
212 49
|
Kubernetes Docker 微服务
微服务实践k8s&dapr开发部署实验(3)订阅发布
微服务实践k8s&dapr开发部署实验(3)订阅发布
218 0