Kubernetes很快成为跨云和本地环境在分布式系统上管理和部署工作负载不可或缺的工具。虽然现在大多数人都熟悉如何使用Kubernetes,但很少有人知道它背后的“为什么”?为什么KubernetesAPI看起来像它的样子?为什么Kubernetes组件之间只能通过KubernetesAPI进行交互?为什么在引用卷时会有PersistentVolumeClaim对象?为了回答这些问题并帮助您更深入地了解Kubernetes,本次演讲将揭示支撑其设计的原则。原则1.KubernetesAPI是声明式而非命令式的我们从一个非常简单的示例开始,说明如何启动需要在节点上运行的任务。一种非常简单的方法是发送命令来启动容器。但这样一来,如果容器或节点崩溃,或者节点暂时无法访问,用户必须监控和存储每个节点和容器的状态,捕获所有异常,并进行异常处理。也就是说,所有复杂的异常处理逻辑都交给了客户端。这就引入了Kubernetes的第一个设计原则:KubernetesAPIsaredeclarativeratherthanimperative(KubernetesAPIsaredeclarativeratherthanimperative)imperative:用户:提供一系列指令驱动系统达到指定状态。系统:执行指令用户:监控系统并根据系统状态提供进一步的指令声明式:用户:定义期望的状态系统:朝着指定的状态努力下图是声明式API的示例:1.用户创建一个API对象2.使用的组件并行工作以达到状态。声明式API支持自动恢复。例如:1.节点B宕机。2.系统自主将Pod移动到一个健康的节点A上。需要注意的是,主节点只存储Pod的定义语句,不会向节点B发送命令。如果这样做,主节点将会变得和我们之前提到的客户端一样,复杂脆弱,难以扩展。这就介绍了K8s的第二个设计原则:Kubernetescontrolplaneistransparent,therenohiddeninternalAPIs(TheKubernetescontrolplaneistransparent.TherearenohiddeninternalAPIs.)原则2.Kubernetescontrolplaneistransparent,Beforethereisno隐藏的内部API:主节点:提供一系列指令驱动节点到指定状态。节点:执行主节点发送的指令主节点:监控每个节点并根据节点状态提供进一步的指令现在:主节点:定义你想要达到的状态节点:独立工作以达到主节点定义的状态让我们看一个创建Pod的例子:如下图所示,所有组件都监控KubernetesAPI,然后决定它们应该做什么。用户调用API声明要创建的Pod。主节点创建Pod的定义。Scheduler通过API观察PodA的定义。通过调度操作,决定在NodeB上创建PodA,并通过API更新Master节点上PodA的定义。.NodeB观察到PodA被定义为在自己的管辖范围内,启动PodA用户通过API删除PodANodeB发现PodA被删除NodeB删除PodA这样做可以导致更简单和更健壮的系统设计,并且很容易从故障状态中恢复。系统不存在单点故障,主节点的职责非常简单。这样做的另一个好处是系统更容易扩展和组合。由于没有内部隐藏的API,用户可以很容易地用自定义组件替换现有组件,或者添加自定义功能。K8s还有很多对业务很重要的对象,比如存储密码的keyfilesecret,配置configmaps,或者通过下游API提供pod的基本信息。那么是不是一定要修改应用程序调用KubeAPI来获取这些信息呢?这就引入了Kubernetes的第三条设计原则:满足用户的需求(Meettheuserwheretheyare)Principle3.在满足用户需求之前:应用必须修改为知道K8s的存在,现在调用KubeAPI:Appscanloadconfigurationfiles或环境变量中的关键文件,因此无需修改。我们可以举个例子,就是关于远程存储的。如上图所示,Pod可以直接引用一个远程存储卷(GCEPD、AWSEBS、NFS等),kubernetes会自动为Pod提供该卷。但是这样做,有一个问题,如果你是迁移到一个新的基础设施上,那么它就不行了。所以这就引出了kubernetes设计的第四个原则:可移植工作负载(Workloadportability)原则4.可移植工作负载持久卷(PersistentVolumn,PV)和持久卷声明(PersistenVolumnClaim,PVC)就是这样的一个例子。如上图所示,通过PVC的抽象,用户Pod不直接引用GCEPD或EBS,这样Pod可以在不同的基础设施中相互迁移,实现可移植性。就像操作系统一样,该设计实现了系统应用程序与底层硬件或架构的分离和解耦。总结本文总结了谷歌高级软件工程师和kubernete开发者SaadAli在Kubecon2018分享的一个《Kubernetes设计原则》。四大设计原则是:需要Portableworkload通过这次分享,我们可以发现K8s设计原则背后的原因是软件设计的一些通用原则是一致的。虽然面向对象不再是一个流行的名词,但本文的设计原则与面向对象的设计原则高度一致。受试者对自己负责。在设计对象时,对象要尽可能封装内部状态,自己负责。我们设计了一辆可驾驶的汽车。一种设计是两个对象,driver和car,然后是diver.run(car)。而更好的设计是不需要驱动程序,或者说将驱动程序看作是Car的一个属性,即Car.run()。第二种设计更符合面向对象的设计原则。这是声明式API背后的原则。组件负责它们自己的类似于KubeAPI的接口。对象在修改时关闭,在扩展时打开。通过开放的API,用户可以轻松实现功能扩展,但不能修改已有的组件,可以开发自定义组件来替换已有的组件。可移植性设计采用了类似面向对象的多态性,同样定义了抽象接口PVC,隐藏了具体的实现细节。希望本文的分享能够帮助大家理解K8s背后的设计原则。
