kubernetes API 资源对象的版本控制

栏目: IT技术 · 发布时间: 6年前

内容简介:一个 API 资源对象的 Schema 的唯一标识由 apiVersion 和 kind 组成,其中 apiVersion 又分为 Group 和 Version。例如:kubernetes 的 apiVersion 有很多,可以通过 kubectl api-versions 命令查看当前支持的 API 版本:通过 kubectl api-resources 还可以查看当前支持的 API 资源对象:

一个 API 资源对象的 Schema 的唯一标识由 apiVersion 和 kind 组成,其中 apiVersion 又分为 Group 和 Version。例如:

Group    Version    Kind
apps     v1         Deployment

kubernetes 的 apiVersion 有很多,可以通过 kubectl api-versions 命令查看当前支持的 API 版本:

# 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
autoscaling/v2beta2
batch/v1
batch/v1beta1
certificates.k8s.io/v1beta1
coordination.k8s.io/v1
coordination.k8s.io/v1beta1
crd.projectcalico.org/v1
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

通过 kubectl api-resources 还可以查看当前支持的 API 资源对象:

# kubectl api-resources | grep deploy
deployments                       deploy       apps                           true         Deployment
deployments                       deploy       extensions                     true         Deployment

一个 kind 可能出现在不同的 apiVersion 中,例如 Deployment 就出现在了如下多个 apiVersion 中:

  • k8s.io/api/apps/v1.Deployment
  • k8s.io/api/apps/v1beta1.Deployment
  • k8s.io/api/apps/v1beta2.Deployment
  • k8s.io/api/extensions/v1beta1.Deployment

对于不同的 apiVersion,在 kube-apiserver 中,其对应的 HTTP Handler 是什么样子的呢?

在 kube-apiserver 的启动过程中,服务路由的安装是通过如下调用实现的:

func (c completedConfig) New(delegationTarget genericapiserver.DelegationTarget) (*Master, error) {

    ......

    restStorageProviders := []RESTStorageProvider{
        auditregistrationrest.RESTStorageProvider{},
        authenticationrest.RESTStorageProvider{Authenticator: c.GenericConfig.Authentication.Authenticator, APIAudiences: c.GenericConfig.Authentication.APIAudiences},
        authorizationrest.RESTStorageProvider{Authorizer: c.GenericConfig.Authorization.Authorizer, RuleResolver: c.GenericConfig.RuleResolver},
        autoscalingrest.RESTStorageProvider{},
        batchrest.RESTStorageProvider{},
        certificatesrest.RESTStorageProvider{},
        coordinationrest.RESTStorageProvider{},
        extensionsrest.RESTStorageProvider{},
        networkingrest.RESTStorageProvider{},
        noderest.RESTStorageProvider{},
        policyrest.RESTStorageProvider{},
        rbacrest.RESTStorageProvider{Authorizer: c.GenericConfig.Authorization.Authorizer},
        schedulingrest.RESTStorageProvider{},
        settingsrest.RESTStorageProvider{},
        storagerest.RESTStorageProvider{},
        // keep apps after extensions so legacy clients resolve the extensions versions of shared resource names.
        // See https://github.com/kubernetes/kubernetes/issues/42392
        appsrest.RESTStorageProvider{},
        admissionregistrationrest.RESTStorageProvider{},
        eventsrest.RESTStorageProvider{TTL: c.ExtraConfig.EventTTL},
    }
    m.InstallAPIs(c.ExtraConfig.APIResourceConfigSource, c.GenericConfig.RESTOptionsGetter, restStorageProviders...)

    ......

}

以 appsrest.RESTStorageProvider{} 为例,从它的 NewRESTStorage 方法可以看出,它管理了 apps 这个 Group 下支持的 Version:

func (p RESTStorageProvider) NewRESTStorage(apiResourceConfigSource serverstorage.APIResourceConfigSource, restOptionsGetter generic.RESTOptionsGetter) (genericapiserver.APIGroupInfo, bool) {
    apiGroupInfo := genericapiserver.NewDefaultAPIGroupInfo(apps.GroupName, legacyscheme.Scheme, legacyscheme.ParameterCodec, legacyscheme.Codecs)
    // If you add a version here, be sure to add an entry in `k8s.io/kubernetes/cmd/kube-apiserver/app/aggregator.go with specific priorities.
    // TODO refactor the plumbing to provide the information in the APIGroupInfo

    if apiResourceConfigSource.VersionEnabled(appsapiv1beta1.SchemeGroupVersion) {
        apiGroupInfo.VersionedResourcesStorageMap[appsapiv1beta1.SchemeGroupVersion.Version] = p.v1beta1Storage(apiResourceConfigSource, restOptionsGetter)
    }
    if apiResourceConfigSource.VersionEnabled(appsapiv1beta2.SchemeGroupVersion) {
        apiGroupInfo.VersionedResourcesStorageMap[appsapiv1beta2.SchemeGroupVersion.Version] = p.v1beta2Storage(apiResourceConfigSource, restOptionsGetter)
    }
    if apiResourceConfigSource.VersionEnabled(appsapiv1.SchemeGroupVersion) {
        apiGroupInfo.VersionedResourcesStorageMap[appsapiv1.SchemeGroupVersion.Version] = p.v1Storage(apiResourceConfigSource, restOptionsGetter)
    }

    return apiGroupInfo, true
}

而每个 Version 下面管理着支持的 Kind:

func (p RESTStorageProvider) v1Storage(apiResourceConfigSource serverstorage.APIResourceConfigSource, restOptionsGetter generic.RESTOptionsGetter) map[string]rest.Storage {
    storage := map[string]rest.Storage{}

    // deployments
    deploymentStorage := deploymentstore.NewStorage(restOptionsGetter)
    storage["deployments"] = deploymentStorage.Deployment
    storage["deployments/status"] = deploymentStorage.Status
    storage["deployments/scale"] = deploymentStorage.Scale

    ......

    return storage
}

对比不同 Version,发现对于同一个 Kind,使用的都是相同的 Storage 实现,例如 Deployment 的 Storage 实现就是 pkg/registry/apps/deployment/storage.DeploymentStorage。为何不同 apiVersion 的资源对象可以使用相同的 Storage 实现呢?

通过跟踪请求 PATCH /apis/apps/v1/namespaces/default/deployments/nginx,发现在处理过程中对资源对象版本进行了转换:

patcher.patchResource
    ...
    schemaReferenceObj, err := p.unsafeConvertor.ConvertToVersion(p.restPatcher.New(), p.kind.GroupVersion())
    // *v1.Deployment                                               *apps.Deployment        apps/v1
    ...

smpPatcher.applyPatchToCurrentObject
    ...
    versionedObjToUpdate, err := p.creater.New(p.kind) // runtime.Scheme
    // *v1.Deployment
    if err != nil {
        return nil, err
    }
    if err := strategicPatchObject(p.defaulter, currentVersionedObject, p.patchBytes, versionedObjToUpdate, p.schemaReferenceObj); err != nil {
        return nil, err
    }
    newObj, err := p.unsafeConvertor.ConvertToVersion(versionedObjToUpdate, p.hubGroupVersion)
    // *apps.Deployment                                *v1.Deployment        apps/__internal

也就是 apps/v1/Deployment 会在处理的过程中被转换为内部对象 apps/Deployment。那么这个转换又是如何完成的呢?

通过调查 p.unsafeConvertor.ConvertToVersion,其实际上调用的是:

// 该方法会将 in 转换为 target 指定的类型。
k8s.io/apimachinery/pkg/runtime.Scheme.ConvertToVersion(in Object, target GroupVersioner)
k8s.io/apimachinery/pkg/conversion.Converter.Convert(src, dest interface{}, flags FieldMatchingFlags, meta *Meta)
// 该方法会被注册到 conversion.Converter 中
pkg/apis/apps/v1.Convert_v1_Deployment_To_apps_Deployment(in *appsv1.Deployment, out *apps.Deployment, s conversion.Scope)

所以完成 apps/v1/Deployment 到 apps/Deployment 的转换就是由 pkg/apis/apps/v1.Convert_v1_Deployment_To_apps_Deployment 实现的,对应的 apps/Deployment 到 apps/v1/Deployment 的转换是由 pkg/apis/apps/v1.Convert_apps_Deployment_To_v1_Deployment 实现,用于从 Etcd 中读取资源对象后,解码出来的是 apps/Deployment,然后根据当前请求的 apiVersion 进行转换。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Probability and Computing

Probability and Computing

Michael Mitzenmacher、Eli Upfal / Cambridge University Press / 2005-01-31 / USD 66.00

Assuming only an elementary background in discrete mathematics, this textbook is an excellent introduction to the probabilistic techniques and paradigms used in the development of probabilistic algori......一起来看看 《Probability and Computing》 这本书的介绍吧!

随机密码生成器
随机密码生成器

多种字符组合密码

MD5 加密
MD5 加密

MD5 加密工具

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具