Please enable Javascript to view the contents

K8s设计理念

 ·  ☕ 7 分钟 · 👀... 阅读

设计理念与分布式系统

分析和理解Kubernetes的设计理念可以使我们更深入地了解Kubernetes系统,更好地利用它管理分布式部署的云原生应用,另一方面也可以让我们借鉴其在分布式系统设计方面的经验。

架构设计原则

只有apiserver可以直接访问etcd存储,其他服务必须通过Kubernetes API来访问集群状态
单节点故障不应该影响集群的状态
在没有新请求的情况下,所有组件应该在故障恢复后继续执行上次最后收到的请求(比如网络分区或服务重启等)
所有组件都应该在内存中保持所需要的状态,apiserver将状态写入etcd存储,而其他组件则通过apiserver更新并监听所有的变化
优先使用事件监听而不是轮询

核心技术概念和API对象

API对象是K8s集群中的管理操作单元。K8s集群系统每支持一项新功能,引入一项新技术,一定会新引入对应的API对象,支持对该功能的管理操作。例如副本集Replica Set对应的API对象是RS。
每个API对象都有3大类属性:
元数据metadata、
规范spec
状态status。
元数据是用来标识API对象的,每个对象都至少有3个元数据:namespace,name和uid;
除此以外还有各种各样的标签labels用来标识和匹配不同的对象,例如用户可以用标签env来标识区分不同的服务部署环境,分别用env=dev、env=testing、env=production来标识开发、测试、生产的不同服务。规范描述了用户期望K8s集群中的分布式系统达到的理想状态(Desired State),例如用户可以通过复制控制器Replication Controller设置期望的Pod副本数为3;status描述了系统实际当前达到的状态(Status),例如系统当前实际的Pod副本数为2;那么复本控制器当前的程序逻辑就是自动启动新的Pod,争取达到副本数为3。
K8s中所有的配置都是通过API对象的spec去设置的,也就是用户通过配置系统的理想状态来改变系统,这是k8s重要设计理念之一,即所有的操作都是声明式(Declarative)的而不是命令式(Imperative)的。声明式操作在分布式系统中的好处是稳定,不怕丢操作或运行多次,例如设置副本数为3的操作运行多次也还是一个结果,而给副本数加1的操作就不是声明式的,运行多次结果就错了。

节点(Node)

Kubernetes 运行在节点 (node) 上,节点是集群中的单个机器。如果你有自己的硬件,节点可能对应于物理机器,但更可能对应于在云中运行的虚拟机。节点是部署你的应用或服务的地方,是 Kubernetes 工作的地方。有 2 种类型的节点 ——master 节点和 worker 节点,所以说 Kubernetes 是主从结构的。
节点是 “物理” 结构 —— 我们把 “物理” 放在引号里,因为要记住,很多时候,它们实际上是虚拟机。

pod

Kubernetes 中的逻辑而非物理的工作单位称为 pod。一个 pod 类似于 Docker 中的容器。
一个 Kubernetes pod 通常包含一个或多个 Docker 容器,所有的容器都作为一个微服务单元来管理。

复制控制器(Replication Controller,RC)

RC是k8s集群中早期保证pod高可用api对象,适用于长期服务业务型,如web服务

副本集(Replica Set,RS)

RS是新一代RC,同样保证高可用,区别在于提供更多匹配模式,一般不单独使用,配合Deployment理想状态参数使用

部署(Deployment)

用于创建更新服务,比RS应用模式更广的API对象

服务(Service)

提供服务发现,负载均衡能力(kube-proxy)

任务(Job)

用来控制批处理型任务的API对象,与长期服务业务型不同的是运行有头有尾

后台支撑服务集(DaemonSet)

后台支撑服务集,关注节点,保证每个节点都有一个此类Pod运行,比如储存,日志和监控

有状态服务集(StatefulSet)

RC和RS主要是控制提供无状态服务的,其所控制的Pod的名字是随机设置的,一个Pod出故障了就被丢弃掉,在另一个地方重启一个新的Pod,名字变了、名字和启动在哪儿都不重要,重要的只是Pod总数;有状态服务集,用来控制有状态服务,每个Pod的名字事先确定不能更改。
对于RC和RS中的Pod,一般不挂载存储或者挂载共享存储,保存的是所有Pod共享的状态,Pod像牲畜一样没有分别(这似乎也确实意味着失去了人性特征);对于StatefulSet中的Pod,每个Pod挂载自己独立的存储,如果一个Pod出现故障,从其他节点启动一个同样名字的Pod,要挂载上原来Pod的存储继续以它的状态提供服务。
适合于StatefulSet的业务包括数据库服务MySQL和PostgreSQL,集群化管理服务Zookeeper、etcd等有状态服务。

集群联邦(Federation)

服务的作用距离范围从近到远一般可以有:同主机(Host,Node)、跨主机同可用区(Available Zone)、跨可用区同地区(Region)、跨地区同服务商(Cloud Service Provider)、跨云平台。K8s的设计定位是单一集群在同一个地域内,因为同一个地区的网络性能才能满足K8s的调度和计算存储连接要求。而联合集群服务就是为提供跨Region跨服务商K8s集群服务而设计的。

存储卷(Volume)

K8s的存储卷的生命周期和作用范围是一个Pod

持久存储卷(Persistent Volume,PV)和持久存储卷声明(Persistent Volume Claim,PVC)

PV和PVC使得K8s集群具备了存储的逻辑抽象能力,使得在配置Pod的逻辑里可以忽略对实际后台存储技术的配置,而把这项配置的工作交给PV的配置者,即集群的管理者。存储的PV和PVC的这种关系,跟计算的Node和Pod的关系是非常类似的;PV和Node是资源的提供者,根据集群的基础设施变化而变化,由K8s集群管理员配置;而PVC和Pod是资源的使用者,根据业务服务的需求变化而变化,由K8s集群的使用者即服务的管理员来配置。

密钥对象(Secret)

Secret是用来保存和传递密码、密钥、认证凭证这些敏感信息的对象。使用Secret的好处是可以避免把敏感信息明文写在配置文件里。在K8s集群中配置和使用服务不可避免的要用到各种敏感信息实现登录、认证等功能,例如访问AWS存储的用户名密码。为了避免将类似的敏感信息明文写在所有需要使用的配置文件中,可以将这些信息存入一个Secret对象,而在配置文件中通过Secret对象引用这些敏感信息。这种方式的好处包括:意图明确,避免重复,减少暴露机会。

用户帐户(User Account)和服务帐户(Service Account)

用户帐户为人提供账户标识,而服务账户为计算机进程和K8s集群中运行的Pod提供账户标识。用户帐户和服务帐户的一个区别是作用范围;用户帐户对应的是人的身份,人的身份与服务的namespace无关,所以用户账户是跨namespace的;而服务帐户对应的是一个运行中程序的身份,与特定namespace是相关的。

名字空间(Namespace)

名字空间为K8s集群提供虚拟的隔离作用,K8s集群初始有两个名字空间,分别是默认名字空间default和系统名字空间kube-system,除此以外,管理员可以创建新的名字空间满足需要。

RBAC访问授权

K8s在1.3版本中发布了alpha版的基于角色的访问控制(Role-based Access Control,RBAC)的授权模式。相对于基于属性的访问控制(Attribute-based Access Control,ABAC),RBAC主要是引入了角色(Role)和角色绑定(RoleBinding)的抽象概念。在ABAC中,K8s集群中的访问策略只能跟用户直接关联;而在RBAC中,访问策略可以跟某个角色关联,具体的用户在跟一个或多个角色相关联。显然,RBAC像其他新功能一样,每次引入新功能,都会引入新的API对象,从而引入新的概念抽象,而这一新的概念抽象一定会使集群服务管理和使用更容易扩展和重用。

总结

从K8s的系统架构、技术概念和设计理念,我们可以看到K8s系统最核心的两个设计理念:一个是容错性,一个是易扩展性。容错性实际是保证K8s系统稳定性和安全性的基础,易扩展性是保证K8s对变更友好,可以快速迭代增加新功能的基础。

参考

https://kubernetes.feisky.xyz/concepts/concepts#he-xin-ji-shu-gai-nian-he-api-dui-xiang
https://github.com/rootsongjc/kubernetes-handbook/blob/master/cloud-native/quick-start.md

分享
您的鼓励是我最大的动力

Jason Tan
作者
Jason Tan
Developer