在整个 Kubernetes 体系架构中,资源是 Kubernetes 最重要的概念,可以说 Kubernetes 的生态系统都围绕着资源运作。Kubernetes 系统虽然有相当复杂和众多的功能,但它本质上是一个资源控制系统——注册、管理、调度资源并维护资源的状态。

1、GVR 概念

在 kubernetes 庞大的资源系统中,单用资源的概念远远不够,因此将资源再次分组和版本化,形成 Group(资源组)、Version(资源版本)、Resource(资源)等概念。

  • Group:被称为资源组,可称其为 APIGroup。

  • Version:被称为资源版本,也可称其为 APIVersions。

  • Resource:被称为资源,也可称其为APIResource。

  • Kind:资源种类,描述 Resource 的种类,与 Resource 为同一级别。

kubernetes crd.png

Kubernetes 的每个资源可使用 metav1.APIResource 结构进行描述,它描述资源的基本信息,例如资源名称(Name)、资源所属的命名空间(Namespaced)、资源种类(Kind)、资源可操作的方法列表(Verbs),资源版本通过 metav1.APIVersions 来描述。

2、Group

Kubernetes 系统中定义了许多资源组,这些资源组按照不同功能将资源进行了划分,资源组特点如下:

  • 将众多资源按照功能划分成不同的资源组,并允许单独启用/禁用资源组;

  • 支持资源组中拥有不同的资源版本,便于资源的版本升级;

  • 支持同名的资源种类存在于不同的资源组内;

  • 资源组与资源版本通过 API Server 对外暴露,允许开发者进行资源发现;

  • 支持CRD自定义资源扩展;

其在代码中的定义表示为:

type APIGroup struct {
    TypeMeta
    Name string // 资源组名称
    Versions []GroupVersionForDiscovery // 资源组支持版本
    PreferredVersion GroupVersionForDiscovery // 资源组优先版本
    ServerAddressByClientCIDRs []ServerAddressByClientCIDR
}

在实际过程中会发现一些 没有组名的资源组,被称为 Core Groups(即核心资源组)或 Legacy Groups,也可被称为GroupLess(即无组)。其表现形式为 /<version>/<resource>,例如 /v1/pods 的资源路径。并且其和拥有组名的资源组在形成路径上面也略有不同,拥有组名的以 /apis 开始,而没有组名的以 /api 开始。

3、Version

Kubernetes 的资源版本控制可分为3种,分别是 Alpha、Beta、Stable,它们之间的迭代顺序为由前至后,其通常用来表示软件测试过程的三个阶段。

  • Alpha 是第1个阶段,一般用于内部测试,随时可能被官方进行废弃不再支持,例如 v1alpha2、v2alpha1;

  • Beta 是第2个阶段,该版本已经修复了大部分不完善之处,但仍有可能存在缺陷和漏洞,在迭代中会有稍微改动,例如 v1beta2、v2beta1;

  • Stable 是第3个阶段,此时基本形成了产品并达到了一定的成熟度,可稳定运行,例如 v1、v2。

4、Resource

Kubernetes 系统虽然有相当复杂和众多的功能,但它本质上是一个资源控制系统——管理、调度资源并维护资源的状态。

一个资源被实例化后会表达为一个资源对象,在系统中目前支持两种资源对象:

  1. 持久性资源:在资源对象被创建后,Kubernetes 会持久确保该资源对象存在。大部分资源对象属于持久性实体,例如 Deployment 资源对象;

  2. 短暂性资源:也可称其为非持久性资源,在资源对象被创建后,如果出现故障或调度失败,不会重新创建该资源对象,例如 Pod 资源对象。

type APIResource struct {
    Name string // 资源名称
    SingularName string // 资源的单数名称,它必须由小写字母组成,默认使用资源种类(Kind)的小写形式进行命名。例如,Pod资源的单数名称为pod,复数名称为pods
    Namespaced bool // 资源是否拥有命名空间
    Group string // 资源组名称
    Version string // 资源组版本
    Kind string // 资源类型
    Verbs Verbs // 资源操作列表
    ShortNames []string // 资源简称
    Categories []string
    StorageVersionHash string
}

4.1 资源外部版本与内部版本

在 Kubernetes 系统中,同一资源对应着两个版本,分别是外部版本和内部版本。例如,Deployment 资源,它所属的外部版本表现形式为 apps/v1,内部版本(内部版本一般与资源组在同一级目录下)表现形式为 apps/__internal

  • 外部版本资源对象:也称为 Versioned Object。外部版本用于对外暴露给用户请求的接口所使用的资源对象,例如,用户在通过YAML或JSON格式的描述文件创建资源对象时,所使用的是外部版本的资源对象。

  • 内部版本资源对象:内部版本不对外暴露,仅在内部使用。内部版本用于多资源版本的转换,例如将 v1beta1 版本转换为 v1 版本,其过程为 v1beta1→internal→v1。

资源版本与外部版本、内部版本概念不同。拥有资源版本的资源属于外部版本,拥有 runtime.APIVersionInternal 标识的资源属于内部版本。

资源的内部版本定义了所支持的资源类型(types.go)、资源验证方法(validation.go)、资源注册至资源注册表的方法(install/install.go)等。而资源的外部版本定义了资源的转换方法(conversion.go)、资源的默认值(defaults.go)等。

4.2 资源注册

在每一个 Kubernetes 资源组目录中,都拥有一个 install/install.go 代码文件,它负责将资源信息注册到资源注册表(Scheme)中。

func init() {
    Install(legacyscheme.Scheme)
}
​
// Install registers the API group and adds types to a scheme
func Install(scheme *runtime.Scheme) {
    utilruntime.Must(core.AddToScheme(scheme))
    utilruntime.Must(v1.AddToScheme(scheme))
    utilruntime.Must(scheme.SetVersionPriority(v1.SchemeGroupVersion))
}
  • legacyscheme.Scheme 是 kube-apiserver 组件的全局资源注册表,而 Kubernetes 的所有资源信息都交给资源注册表统一管理。

  • core.AddToScheme 函数注册 core 资源组内部版本的资源;

  • v1.AddToScheme 函数注册core资源组外部版本的资源;

  • scheme.SetVersionPriority 函数注册资源组的版本顺序,多个资源版本之间最前面的为资源首选版本。

4.3 资源首选版本

上面提到组可以拥有很多个版本,在明确指定了使用哪个版本的资源时则使用具体版本,否则会使用优选版本。

scheme.PreferredVersionAllGroups 方法中则是直接遍历版本,选择第一个版本。除此之外,还有其他两个方法用于版本获取,scheme.PrioritizedVersionsForGroup1 取指定资源组的资源版本,按照优先顺序返回;scheme.PrioritizedVersionsAllGroups 获取所有资源组的资源版本,按照优先顺序返回。

4.4 资源操作方法

Kubernetes 系统所支持的操作方法目前有 8 种操作,分别是 create、delete、deletecollection、get、list、patch、update、watch,符合 RESTFUL 接口的定义,可以划分为增删改查四类操作。

资源对象的操作方法与存储(Storage)相关联,增、删、改、查实际上都是针对存储的操作。通过查看与存储相关联的源码包 vendor/k8s.io/apiserver/pkg/registry/,每种操作方法对应一个操作方法接口(Interface)。以 get 操作为例,其是一个接口, 如果某个资源对象(pod)在存储上实现了 Get,就可以认为该资源对象拥有了 get 操作方法。

// Getter is an object that can retrieve a named RESTful resource.
type Getter interface {
    // Get finds a resource in the storage by name and returns it.
    // Although it can return an arbitrary error value, IsNotFound(err) is true for the
    // returned error value err when the specified resource is not found.
    Get(ctx context.Context, name string, options *metav1.GetOptions) (runtime.Object, error)
}
​
func (e *Store) Get(ctx context.Context, name string, options *metav1.GetOptions) (runtime.Object, error) {
    obj := e.NewFunc()
    key, err := e.KeyFunc(ctx, name)
    if err != nil {
        return nil, err
    }
    if err := e.Storage.Get(ctx, key, storage.GetOptions{ResourceVersion: options.ResourceVersion}, obj); err != nil {
        return nil, storeerr.InterpretGetError(err, e.qualifiedResourceFromContext(ctx), name)
    }
    if e.Decorator != nil {
        e.Decorator(obj)
    }
    return obj, nil
}

4.5 命名空间

系统支持命名空间(Namespace),用来解决集群中资源对象过多导致管理复杂的问题,其中每个命名空间相当于一个"虚拟集群",不同命名空间之间可以进行隔离,也可以通过某种方式跨命名空间通信。

Kubernetes 系统中默认内置了4个命名空间:

  • default:所有未指定命名空间的资源对象都会被分配给该命名空间;

  • kube-system:所有由 Kubernetes 系统创建的资源对象都会被分配给该命名空间;

  • kube-public:此命名空间下的资源对象可以被所有人访问(包括未认证用户);

  • kube-node-lease:此命名空间下存放来自节点的心跳记录(节点租约信息)。

4.6 自定义资源

Kubernetes 系统附带了许多内置资源,但是仍有些需求需要使用自定义资源(custom resource)来扩展 Kubernetes 的功能。在系统早期,是通过 ThirdPartyResource(TPR)来实现扩展,但自 Kubernetes 1.7 版本后,取而代之的是CustomResourceDefinitions(自定义资源定义,CRD)。

通过 CRD 可以实现自定义资源,它允许用户将自己定义的资源添加到 Kubernetes 系统中,并像使用 Kubernetes 内置资源一样使用这些资源,而通过一个 operator 控制器来对自定义资源进行控制操作。