3.1 资源对象与API群组
Kubernetes系统的API Server基于HTTP/HTTPS协议接收并响应客户端的操作请求,它提供了一种“基于资源”的RESTful风格的编程接口,把集群各种组件都抽象成标准的RESTful资源,并支持通过标准的HTTP方法、以JSON为数据序列化方案进行资源管理操作。
资源可以分为若干个集合,每个集合只包含单一类型的资源,并且各资源间无序。当然,资源也可以不属于任何集合,称为单身资源。事实上,集合本身也是资源,它可以部署于全局级别,位于API的顶层,也可以包含在某个资源中,表现为“子集合”。集合、资源、子集合及子资源间的关系如图3-1所示。
Kubernetes遵循RESTful架构风格组织及管理其API资源对象,支持通过标准的HTTP方法(POST、PUT、PATCH、DELETE和GET)对资源进行增、删、改、查等管理操作。不过,在Kubernetes系统的语境中,“资源”用于表示“对象”的集合或类型,例如Pod资源可用于描述所有Pod类型的对象,但本书将不加区别地使用资源、对象和资源对象,并把它们统统理解为资源类型生成的实例——对象。
3.1.1 Kubernetes的资源对象
以资源的主要功能作为分类标准,Kubernetes的API对象大体可分为工作负载、发现与负载均衡、配置与存储、集群和元数据几个类别。它们基本都是围绕一个核心目的而设计:如何更好地运行和丰富Pod资源,从而为容器化应用提供更灵活和更完善的操作与管理组件,如图3-2所示。
工作负载型资源用于确保Pod资源对象更好地运行容器化应用。具有同一种负载的各Pod对象需要以负载均衡的方式服务于各请求,而各种容器化应用需要彼此发现以完成工作协同。Pod资源具有生命周期,存储型资源能够为重构的Pod对象提供持久化数据存储机制,配置型资源能够让共享同一配置的Pod资源从中统一获取配置改动信息。这些资源作为“配置中心”为管理容器化应用的配置文件提供了极为便捷的管理机制。集群型资源为管理集群本身的工作特性提供了配置接口,而元数据型资源用于配置集群内部其他资源的行为。
1. 工作负载型资源
Pod用于承载容器化应用,代表着Kubernetes之上工作负载的表现形式。它负责运行容器,并为容器解决环境性的依赖,例如向容器注入临时或持久化的存储空间、配置信息或密钥数据等。而诸如滚动更新、扩容和缩容一类的编排任务则由“控制器”对象负责,专用于Pod编排任务的控制器也可统称为Pod控制器。
应用程序分为无状态和有状态两种类型,无状态应用中的每个Pod实例均可被其他同类实例所取代,但有状态应用的每个Pod实例均有其独特性,必须单独标识和管理,因而它们分别由两种不同类型的Pod控制器进行管理。例如,ReplicationController、ReplicaSet和Deployment负责管理无状态应用,StatefulSet则用于管控有状态类应用。还有些应用较为独特,有些需要在集群中的每个节点上运行单个Pod资源,负责收集日志或运行系统服务等任务,该类编排操作由DaemonSet控制器对象进行,而需要在正常完成后退出故无须始终处于运行状态任务的编排工作则隶属Job控制器对象。CronJob控制器对象还能为Job型的任务提供定期执行机制。
▪ReplicationController:用于确保每个Pod副本在任一时刻均能满足目标数量,即它用于保证每个容器或容器组总是运行并可访问;它是上一代的无状态Pod应用控制器,建议读者使用新型控制器Deployment和ReplicaSet来取代它。
▪ReplicaSet:新一代ReplicationController,它与ReplicationController唯一不同之处在于支持的标签选择器不同,ReplicationController只支持“等值选择器”,而ReplicaSet还支持基于集合的选择器。
▪Deployment:用于管理无状态的持久化应用,例如HTTP服务等;它用于为Pod和ReplicaSet提供声明式更新,是构建在ReplicaSet之上的、更为高级的控制器。
▪StatefulSet:用于管理有状态的持久化应用,例如数据库服务程序;与Deployment的不同之处在于,StatefulSet会为每个Pod创建一个独有的持久性标识符,并会确保各Pod间的顺序性。
▪DaemonSet:用于确保每个节点都运行了某Pod的一个副本,包括后来新增的节点;而节点移除将导致Pod回收;DaemonSet常用于运行各类系统级守护进程,例如kube-proxy和Flannel网络插件,以及日志收集和临近系统的Agent应用,例如fluentd、Logstash、Prometheus的Node Exporter等。
▪Job:用于管理运行完成后即可终止的应用,例如批处理作业任务;Job创建一个或多个Pod,并确保其符合目标数量,直到应用完成而终止。
2. 发现与负载均衡
Service是Kubernetes标准的资源类型之一,用于为工作负载实例提供固定的访问入口及负载均衡服务,它把每个可用后端实例定义为Endpoint资源对象,通过IP地址和端口等属性映射至Pod实例或相应的服务端点。Ingress资源则为工作负载提供7层(HTTP/HTTPS)代理及负载均衡功能。
3. 配置与存储
Docker容器分层联合挂载的方式决定了其系统文件无法在容器内部存储持久化数据,因而容器引擎引入外部存储卷的方式来解决此类问题,相应地,Kubernetes支持在Pod级别附加Volume资源对象为容器添加可用的外部存储。Kubernetes支持众多类型的存储设备或存储系统,例如GlusterFS、Ceph RBD和Flocker等,还可通过FlexVolume及CSI(Container Storage Interface)存储接口扩展支持更多类型的存储系统。
另外,基于镜像运行容器应用时,其配置信息在镜像制作时以硬编码的方式置入,所以很难为不同的环境定制所需的配置。Docker使用环境变量等作为解决方案,但需要在容器启动时将配置作为变量值传入,且无法在运行时修改。Kubernetes的ConfigMap资源能够以环境变量或存储卷的方式接入Pod资源的容器中,并可被多个同类的Pod共享引用,从而做到“一次修改,多处生效”。不过,这种方式不适用于存储敏感数据,例如证书、私钥和密码等,那是另一个资源类型Secret的功能。
4. 集群型资源
Kubernetes还存在一些用于定义集群自身配置信息的资源类型,它们不属于任何名称空间且仅应该由集群管理员操作。常用的集群型资源有如下几种。
▪Namespace:名称空间,为资源对象的名称提供了限定条件或作用范围,它为使用同一集群的多个团队或项目提供了逻辑上的隔离机制,降低或消除了资源对象名称冲突的可能性。
▪Node:Kubernetes并不能直接管理其工作节点,但它会把由管理员添加进来的任何形式(物理机或虚拟机等)的工作节点映射为一个Node资源对象,因而节点名称(标识符)在集群中必须唯一。
▪Role:角色,隶属于名称空间,代表名称空间级别由规则组成的权限集合,可被RoleBinding引用。
▪ClusterRole:集群角色,隶属于集群而非名称空间,代表集群级别的、由规则组成的权限集合,可被RoleBinding和ClusterRoleBinding引用。
▪RoleBinding:用于将Role中的许可权限绑定在一个或一组用户之上,从而完成用户授权,它隶属于且仅能作用于名称空间级别。
▪ClusterRoleBinding:将ClusterRole中定义的许可权限绑定在一个或一组用户之上,通过引用全局名称空间中的ClusterRole将集群级别的权限授予指定用户。
5. 元数据型资源
此类资源对象用于为集群内部的其他资源对象配置其行为或特性,例如HPA资源对象可用于控制自动伸缩工作负载类型资源对象的规模,Pod模板提供了创建Pod对象的预制模板,而LimitRange可为名称空间内的Pod应用设置其CPU和内存等系统级资源的数量限制等。
提示
一个应用通常需要多个资源的支撑,例如用Deployment资源编排应用实例(Pod)、用ConfigMap和Secret资源保存应用配置、用Service或Ingress资源暴露服务、用Volume资源提供持久化存储等。
本书后面篇幅的主体部分将展开介绍这些资源类型,它们是将容器化应用托管运行于Kubernetes集群的重要工具组件。
3.1.2 资源及其在API中的组织形式
资源对象代表了系统上的持久类实体,而Kubernetes用这些持久实体来表达集群的状态,包括容器化的应用程序正运行于哪些节点,每个应用程序有哪些资源可用,以及每个应用程序各自的行为策略,例如重启、升级及容错策略等。一个对象可能会由多个资源组合而成,用户可对这些资源执行增、删、改、查等管理操作。Kubernetes通常使用标准的RESTful术语来描述API概念。
1)资源类型是指在URL中使用的名称,例如pods、namespaces和services等,其URL格式为GROUP/VERSION/RESOURCE,例如apps/v1/deployments。
2)每个资源类型都有一个对应的JSON表示格式,称为一个“种类”;客户端创建对象时,一般需要以JSON规范提交对象的配置信息。
3)Kind代表资源对象所属的类型,例如Namespace、Deployment、Service及Pod等,而这些资源类型又大体可以分为3个类别。
▪对象类:对象表示Kubernetes系统上的持久化实体,一个对象可能包含多个资源,客户端可以对其执行多种操作;Namespace、Deployment、Service及Pod等都属于这个类别。
▪列表类:通常是指同一类型资源的集合,例如PodLists和NodeLists等。
▪简单类:常用于在对象上执行某种特殊操作,或管理非持久化的实体,例如/binding或/status等。
Kubernetes绝大多数的API资源都属于“对象”型类别,代表集群中某个抽象组件的实例。有一小部分的API资源类型为“虚拟”类型,用于表达一类“操作”。所有的对象型资源都拥有一个独有的名称标识以完成幂等的创建及获取操作,但虚拟型资源无须获取或不依赖于幂等性时也可以不使用专用标识符。
有些资源类型的作用域为集群级别,操作权限归属于集群管理员,例如Namespace和PersistentVolume等,但绝大多数资源类型都隶属名称空间级别,可由用户使用,例如Pod、Deployment和Service等。名称空间级别资源的URL路径中含有其所属空间的名称,当这些资源对象在名称空间被删除时,其URL路径中的名称也会被一并删除,并且访问这些资源对象也将受控于其所属的名称空间级别的授权审查。
Kubernetes把API分割为多个逻辑组合以便于扩展和管理,每个组合称为一个API群组,支持单独启用或禁用,并能够再次分解。API Server支持为不同群组使用不同的版本,允许各组以不同的速度演进,而且支持同一群组同时存在不同的版本,例如autoscaling/v1、autoscaling/v2beta2和autoscaling/v2beta1等,因此能够在不同的群组中定义同名的资源类型,从而能在稳定版本的群组及新的实验群组中同时存在不同特性的同一个资源类型。在当前集群中,API Server所支持的API群组及相关版本信息可通过kubectl api-versions命令获取,如下命令结果中显示的多数API群组会在后续章节配置资源清单时反复用到。
~$ kubectl api-versions admissionregistration.k8s.io/v1 admissionregistration.k8s.io/v1beta1 apiextensions.k8s.io/v1 apiextensions.k8s.io/v1beta1 apiregistration.k8s.io/v1 apiregistration.k8s.io/v1beta1 apps/v1 authentication.k8s.io/v1 authentication.k8s.io/v1beta1 authorization.k8s.io/v1 authorization.k8s.io/v1beta1 autoscaling/v1 autoscaling/v2beta1 autoscaling/v2beta2 batch/v1 batch/v1beta1 certificates.k8s.io/v1beta1 coordination.k8s.io/v1 coordination.k8s.io/v1beta1 discovery.k8s.io/v1beta1 events.k8s.io/v1beta1 extensions/v1beta1 networking.k8s.io/v1 networking.k8s.io/v1beta1 node.k8s.io/v1beta1 policy/v1beta1 rbac.authorization.k8s.io/v1 rbac.authorization.k8s.io/v1beta1 scheduling.k8s.io/v1 scheduling.k8s.io/v1beta1 storage.k8s.io/v1 storage.k8s.io/v1beta1 v1
提示
随着API的发展,Kubernetes会定期进行API重组或升级,并弃用过期的版本,因而不同版本的Kubernetes所支持的API群组以及资源类型的归属可能会有所不同。API弃用策略请参考文档https://kubernetes.io/docs/reference/using-api/deprecation-policy/。
Kubernetes将RESTful风格的API以层级结构组织在一起,每个API群组表现为一个以/apis为根路径的RESTful路径,例如/apis/apps/v1,不过名称为core的核心群组有一个专用的简化路径:/api/v1。目前,常用的API群组可归为如下两类。
1)核心群组:RESTful路径为/api/v1,在资源的配置信息apiVersion字段中引用时可以不指定路径,而仅给出版本,例如apiVersion: v1,如上面的命令kubectl api-versions结果中最后一个群组所示。
2)命名的群组:RESTful路径为/apis/$GROUP_NAME/$VERSION,例如/apis/apps/v1,在apiVersion字段中引用它时需要移除/apis前缀,例如apiVersion: apps/v1等。
名称空间级别的每一个资源类型在API的URL路径表示都可简单抽象为形如/apis/<group>/<version>/namespaces/<namespace>/<kind-plural>的路径。例如default名称空间中,Deployment类型的路径为/apis/apps/v1/namespaces/default/deployments,通过此路径可获取到default名称空间中所有Deployment对象的列表。
~$ kubectl get --raw /apis/apps/v1/namespaces/default/deployments | jq . { "kind": "DeploymentList", "apiVersion": "apps/v1", "metadata": { "selfLink": "/apis/apps/v1/namespaces/default/deployments", "resourceVersion": "454758" }, "items": [] }
另外,Kubernetes还支持由用户自定义资源类型,目前常用的方式有3种:一是修改Kubernetes源代码自定义类型;二是创建一个自定义的API Server,并将其聚合至集群中;三是使用CRD(Custom Resource Definition,自定义资源),它们都可用于API群组扩展。
3.1.3 访问Kubernetes RESTful API
为安全起见,kubeadm部署的API Server通常仅支持双向SSL/TLS认证的HTTPS通信,客户端需要事先在服务器端认证才能与之建立通信。在临时测试的场景中,用户也可以借助kubectl proxy命令在本地主机上为API Server启动一个代理网关,从而在本地支持HTTP协议,即使用curl命令向该代理发起请求便能模拟资源对象的请求和响应过程。代理网关的工作逻辑如图3-3所示。
例如,下面的命令中,kubectl命令在本地回环接口上的8080端口启动了API Server的一个代理网关:
~$ kubectl proxy --port=8080 Starting to serve on 127.0.0.1:8080
而后可在该主机的另一终端使用curl一类的客户端工具对此套接字地址发起访问请求,例如下面的命令请求获取集群上的NamespaceList资源对象,以列出集群上所有的Namespace对象:
~$ curl localhost:8080/api/v1/namespaces/ { "kind": "NamespaceList", "apiVersion": "v1", …… }
我们也可以使用JSON的命令行处理器的jq命令对响应的JSON数据流进行内容过滤,例如下面的命令仅显示相关NamespaceList对象中的各成员对象的名称:
~$ curl -s localhost:8080/api/v1/namespaces/ | jq .items[].metadata.name "default" "kube-public" "kube-system"
给出特定的Namespace资源对象的名称便能直接获取到相应的资源信息,以kube-system名称空间为例:
~$ curl -s localhost:8080/api/v1/namespaces/kube-system { "kind": "Namespace", "apiVersion": "v1", "metadata": { "name": "kube-system", "selfLink": "/api/v1/namespaces/kube-system", "uid": " 9db2a2a3-c0bc-4501-bc42-8cd5815abdac ", "resourceVersion": "4", "creationTimestamp": " 2020-05-16T06:23:03Z " }, "spec": { "finalizers": [ "kubernetes" ] }, "status": { "phase": "Active" }
上述命令响应的结果中展现了Kubernetes大多数资源对象的资源配置格式,它是一个JSON序列化的数据结构,具有kind、apiVersion、metadata、spec和status这5个一级字段,各字段的意义和功能将在下一节中重点介绍。