Kubernetes进阶实战
上QQ阅读APP看书,第一时间看更新

3.1 资源对象及API群组

REST是Representational State Transfer的缩写,意为“表征状态转移”,它是一种程序架构风格,基本元素为资源(resource)、表征(representation)和行为(action)。资源即对象,一个资源通常意味着一个附带类型和关联数据、支持的操作方法以及与其他对象的关系的对象,它们是持有状态的事物,即REST中的S(State)。REST组件通过使用“表征”来捕获资源的当前或预期状态并在组件之间传输该表征从而对资源执行操作。表征是一个字节序列,由数据、描述数据的元数据以及偶尔描述元数据的元数据组成(通常用于验证消息的完整性),表征还有一些其他常用但不太精确的名称,如文档、文件和HTTP消息实体等。表征的数据格式称为媒体类型(media type),常用的有JSON或XML。API客户端不能直接访问资源,它们需要执行“动作”(action)来改变资源的状态,于是资源的状态从一种形式“转移”(Transfer)为另一种形式。

资源可以分组为集合(collection),每个集合只包含单一类型的资源,并且各资源间是无序的。当然,资源也可以不属于任何集合,它们称为单体资源。事实上,集合本身也是资源,它可以部署于全局级别,位于API的顶层,也可以包含于某个资源中,表现为“子集合”。集合、资源、子集合及子资源间的关系如图3-1所示。

图3-1 集合、资源和子资源

Kubernetes系统将一切事物都抽象为API资源,其遵循REST架构风格组织并管理这些资源及其对象,同时还支持通过标准的HTTP方法(POST、PUT、PATCH、DELETE和GET)对资源进行增、删、改、查等管理操作。不过,在Kubernetes系统的语境中,“资源”用于表示“对象”的集合,例如,Pod资源可用于描述所有Pod类型的对象,但本书将不加区别地使用资源、对象和资源对象,并将它们统统理解为资源类型生成的实例——对象。

3.1.1 Kubernetes的资源对象

依据资源的主要功能作为分类标准,Kubernetes的API对象大体可分为工作负载(Workload)、发现和负载均衡(Discovery & LB)、配置和存储(Config & Storage)、集群(Cluster)以及元数据(Metadata)五个类别。它们基本上都是围绕一个核心目的而设计:如何更好地运行和丰富Pod资源,从而为容器化应用提供更灵活、更完善的操作与管理组件,如图3-2所示。

图3-2 Kubernetes常用资源对象

工作负载型资源用于确保Pod资源对象能够更好地运行容器化应用,具有同一种负载的各Pod对象需要以负载均衡的方式服务于各请求,而各种容器化应用彼此之间需要彼此“发现”以完成工作协同。Pod资源具有生命周期,存储型资源能够为重构的Pod对象提供持久化的数据存储机制,共享同一配置的Pod资源可从配置型资源中统一获取配置改动信息,这些资源作为配置中心为管理容器化应用的配置文件提供了极为便捷的管理机制。集群型资源为管理集群本身的工作特性提供了配置接口,而元数据型资源则用于配置集群内部的其他资源的行为。

(1)工作负载型资源

Pod是工作负载型资源中的基础资源,它负责运行容器,并为其解决环境性的依赖,例如,向容器注入共享的或持久化的存储卷、配置信息或密钥数据等。但Pod可能会因为资源超限或节点故障等原因而终止,这些非正常终止的Pod资源需要被重建,不过,这类工作将由工作负载型的控制器来完成,它们通常也称为pod控制器。

应用程序分为无状态有状态两种类型,它们对环境的依赖及工作特性有很大的不同,因此分属两种不同类型的Pod控制器来管理,ReplicationController、ReplicaSet和Deployment负责管理无状态应用,StatefulSet用于管控有状态类应用。ReplicationController是上一代的控制器,其功能由ReplicaSet和Deployment负责实现,因此几近于废弃。还有些应用较为独特,它们需要在集群中的每个节点上运行单个Pod资源,负责收集日志或运行系统服务等任务,这些Pod资源的管理则属于DaemonSet控制器的分内之事。另外,有些容器化应用需要继续运行以为守护进程不间断地提供服务,而有些则应该在正常完成后退出,这些在正常完成后就应该退出的容器化应用则由Job控制器负责管控。下面是各Pod控制器更为详细的说明。

‰□ReplicationController:用于确保每个Pod副本在任一时刻均能满足目标数量,换言之,它用于保证每个容器或容器组总是运行并且可访问;它是上一代的无状态Pod应用控制器,建议读者使用新型控制器Deployment和ReplicaSet来取代它。

‰□ReplicaSet:新一代ReplicationController,它与ReplicationController的唯一不同之处仅在于支持的标签选择器不同,ReplicationController只支持等值选择器,而ReplicaSet还额外支持基于集合的选择器。

‰□Deployment:用于管理无状态的持久化应用,例如HTTP服务器;它用于为Pod和ReplicaSet提供声明式更新,是建构在ReplicaSet之上的更为高级的控制器。

‰□StatefulSet:用于管理有状态的持久化应用,如database服务程序;其与Deployment的不同之处在于StatefulSet会为每个Pod创建一个独有的持久性标识符,并会确保各Pod之间的顺序性。

‰□DaemonSet:用于确保每个节点都运行了某Pod的一个副本,新增的节点一样会被添加此类Pod;在节点移除时,此类Pod会被回收;DaemonSet常用于运行集群存储守护进程——如glusterd和ceph,还有日志收集进程——如fluentd和logstash,以及监控进程——如Prometheus的Node Exporter、collectd、Datadog agent和Ganglia的gmond等。

‰□Job:用于管理运行完成后即可终止的应用,例如批处理作业任务;换句话讲,Job创建一个或多个Pod,并确保其符合目标数量,直到Pod正常结束而终止。

(2)发现和负载均衡

Pod资源可能会因为任何意外故障而被重建,于是它需要固定的可被“发现”的方式。另外,Pod资源仅在集群内可见,它的客户端也可能是集群内的其他Pod资源,若要开放给外部网络中的用户访问,则需要事先将其暴露到集群外部,并且要为同一种工作负载的访问流量进行负载均衡。Kubernetes使用标准的资源对象来解决此类问题,它们是用于为工作负载添加发现机制及负载均衡功能的Service资源和Endpoint资源,以及通过七层代理实现请求流量负载均衡的Ingress资源。

(3)配置与存储

Docker容器分层联合挂载的方式决定了不宜在容器内部存储需要持久化的数据,于是它通过引入挂载外部存储卷的方式来解决此类问题,而Kubernetes则为此设计了Volume资源,它支持众多类型的存储设备或存储系统,如GlusterFS、CEPH RBD和Flocker等。另外,新版本的Kubernetes还支持通过标准的CSI(Container Storage Interface)统一存储接口以及扩展支持更多类型的存储系统。

另外,基于镜像构建容器应用时,其配置信息于镜像制作时焙入,从而为不同的环境定制配置就变得较为困难。Docker使用环境变量等作为解决方案,但这么一来就得于容器启动时将值传入,且无法在运行时修改。ConfigMap资源能够以环境变量或存储卷的方式接入到Pod资源的容器中,并且可被多个同类的Pod共享引用,从而实现“一次修改,多处生效”。不过,这种方式不适于存储敏感数据,如私钥、密码等,那是另一个资源类型Secret的功能。

(4)集群级资源

Pod、Deployment、Service和ConfigMap等资源属于名称空间级别,可由相应的项目管理员所管理。然而,Kubernetes还存在一些集群级别的资源,用于定义集群自身配置信息的对象,它们仅应该由集群管理员进行操作。集群级资源主要包含以下几种类型。

‰□Namespace:资源对象名称的作用范围,绝大多数对象都隶属于某个名称空间,默认时隶属于“default”。

‰□Node:Kubernetes集群的工作节点,其标识符在当前集群中必须是唯一的。

‰□Role:名称空间级别的由规则组成的权限集合,可被RoleBinding引用。

‰□ClusterRole:Cluster级别的由规则组成的权限集合,可被RoleBinding和ClusterRole Binding引用。

‰□RoleBinding:将Role中的许可权限绑定在一个或一组用户之上,它隶属于且仅能作用于一个名称空间;绑定时,可以引用同一名称空间中的Role,也可以引用全局名称空间中的ClusterRole。

‰□ClusterRoleBinding:将ClusterRole中定义的许可权限绑定在一个或一组用户之上;它能够引用全局名称空间中的ClusterRole,并能通过Subject添加相关信息。

(5)元数据型资源

此类资源对象用于为集群内部的其他资源配置其行为或特性,如HorizontalPodAutoscaler资源可用于自动伸缩工作负载类型的资源对象的规模,Pod模板资源可用于为pod资源的创建预制模板,而LimitRange则可为名称空间的资源设置其CPU和内存等系统级资源的数量限制等。

提示

一个应用通常需要多个资源的支撑,例如,使用Deployment资源管理应用实例(Pod)、使用ConfigMap资源保存应用配置、使用Service或Ingress资源暴露服务、使用Volume资源提供外部存储等。

本书后面篇幅的主体部分就展开介绍这些资源类型,它们是将容器化应用托管运行于Kubernetes集群的重要工具组件。

3.1.2 资源及其在API中的组织形式

在Kubernetes上,资源对象代表了系统上的持久类实体,Kubernetes用这些持久类实体来表达集群的状态,包括容器化的应用程序正运行于哪些节点,每个应用程序有哪些资源可用,以及每个应用程序各自的行为策略,如重启、升级及容错策略等。一个对象可能会包含多个资源,用户可对这些资源执行增、删、改、查等管理操作。Kubernetes通常利用标准的RESTful术语来描述API概念。

‰□资源类型(resource type)是指在URL中使用的名称,如Pod、Namespace和Service等,其URL格式为“GROUP/VERSION/RESOURCE”,如apps/v1/deployment。

‰□所有资源类型都有一个对应的JSON表示格式,称为“种类”(kind);客户端创建对象必须以JSON提交对象的配置信息。

‰□隶属于同一种资源类型的对象组成的列表称为“集合”(collection),如PodList。

‰□某种类型的单个实例称为“资源”(resource)或“对象”(object),如名为pod-demo的Pod对象。

kind代表着资源对象所属的类型,如Namespace、Deployment、Service及Pod等,而这些资源类型大体又可以分为三个类别,具体如下。

‰□对象(Object)类:对象表示Kubernetes系统上的持久化实体,一个对象可能包含多个资源,客户端可用它执行多种操作。Namespace、Deployment、Service及Pod等都属于这个类别。

‰□列表(List)类:列表通常是指同一类型资源的集合,如PodLists、NodeLists等。

‰□简单(Simple)类:常用于在对象上执行某种特殊操作,或者管理非持久化的实体,如/binding或/status等。

Kubernetes绝大多数的API资源类型都是“对象”,它们代表着集群中某个概念的实例。有一小部分的API资源类型为“虚拟”(virtual)类型,它们用于表达一类“操作”(operation)。所有的对象型资源都拥有一个独有的名称标识以实现其幂等的创建及获取操作,不过,虚拟型资源无须获取或不依赖于幂等性时也可以不使用专用标识符。

有些资源类型隶属于集群范畴,如Namespace和PersistentVolume,而多数资源类型则受限于名称空间,如Pod、Deployment和Service等。名称空间级别的资源的URL路径中含有其所属空间的名称,这些资源对象在名称空间被删除时会被一并删除,并且这些资源对象的访问也将受控于其所属的名称空间级别的授权审查。

Kubernetes将API分割为多个逻辑组合,称为API群组,它们支持单独启用或禁用,并能够再次分解。API Server支持在不同的群组中使用不同的版本,允许各组以不同的速度演进,而且也支持同一群组同时存在不同的版本,如apps/v1、apps/v1beta2和apps/v1beta1,也因此能够在不同的群组中使用同名的资源类型,从而能在稳定版本的群组及新的实验群组中以不同的特性同时使用同一个资源类型。群组化管理的API使得其可以更轻松地进行扩展。当前系统的API Server上的相关信息可通过“kubectl api-versions”命令获取。命令结果中显示的不少API群组在后续的章节中配置资源清单时会多次用到:

        [root@master~]# kubectl api-versions
        admissionregistration.k8s.io/v1beta1
        apiextensions.k8s.io/v1beta1
        apiregistration.k8s.io/v1
        apiregistration.k8s.io/v1beta1
        apps/v1
        apps/v1beta1
        apps/v1beta2
        authentication.k8s.io/v1
        authentication.k8s.io/v1beta1
        authorization.k8s.io/v1
        authorization.k8s.io/v1beta1
        autoscaling/v1
        autoscaling/v2beta1
        batch/v1
        batch/v1beta1
        certificates.k8s.io/v1beta1
        events.k8s.io/v1beta1
        extensions/v1beta1
        networking.k8s.io/v1
        policy/v1beta1
        rbac.authorization.k8s.io/v1
        rbac.authorization.k8s.io/v1beta1
        scheduling.k8s.io/v1beta1
        storage.k8s.io/v1
        storage.k8s.io/v1beta1
        v1

Kubernetes的API以层级结构组织在一起,每个API群组表现为一个以“/apis”为根路径的REST路径,不过核心群组core有一个专用的简化路径“/api/v1”。目前,常用的API群组可归为如下两类。

‰□核心群组(core group):REST路径为/api/v1,在资源的配置信息apiVersion字段中引用时可以不指定路径,而仅给出版本,如“apiVersion: v1”。

‰□命名的群组(named group):REST路径为/apis/$GROUP_NAME/$VERSION,例如/apis/apps/v1,它在apiVersion字段中引用的格式为“apiVersion: $GROUP_NAME/$VERSION”,如“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",
          ……
          "items": [……]
        }

另外,Kubernetes还支持用户自定义资源类型,目前常用的方式有三种:一是修改Kubernetes源代码自定义类型;二是创建一个自定义的API Server,并将其聚合至集群中;三是使用自定义资源(Custom Resource Definition, CRD)。

3.1.3 访问Kubernetes REST API

以编程的方式访问Kubernetes REST API有助于了解其流式化的集群管理机制,一种常用的方式是使用curl作为HTTP客户端直接通过API Server在集群上操作资源对象模拟请求和响应的过程。不过,由kubeadm部署的Kubernetes集群默认仅支持HTTPS的访问接口,它需进行一系列的认证检查,好在用户也可以借助kubectl proxy命令在本地主机上为API Server启动一个代理网关,由它支持使用HTTP进行通信,其工作逻辑如图3-3所示。

图3-3 kubectl在本地代理API Server

例如,于本地127.0.0.1的8080端口上启动API Server的一个代理网关:

     ~]$ kubectl proxy --port=8080
        Starting to serve on 127.0.0.1:8080

而后即可于另一终端使用curl一类的客户端工具对此套接字地址发起访问请求,例如,请求Kubernetes集群上的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": "eb6bf659-9d0e-11e8-bf0d-000c29ab0f5b",
            "resourceVersion": "33",
            "creationTimestamp": "2018-08-11T02:33:23Z"
          },
          "spec": {
            "finalizers": [
              "kubernetes"
            ]
          },
          "status": {
            "phase": "Active"
          }

上述命令响应的结果中展现了Kubernetes大多数资源对象的资源配置格式,它是一个JSON序列化的数据结构,具有kind、apiVersion、metadata、spec和status五个一级字段,各字段的意义和功能将在3.2节中重点介绍。