温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

API Basics怎么实现

发布时间:2022-01-11 17:57:09 来源:亿速云 阅读:350 作者:iii 栏目:云计算

本文小编为大家详细介绍“API Basics怎么实现”,内容详细,步骤清晰,细节处理妥当,希望这篇“API Basics怎么实现”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。

Introduction

所谓的云原生应用,能够清楚自己运行在k8s上,并且使用k8s api 和资源当作其扩展。

一方面,云原生应用能够轻便地在不同的云上迁移。另一方面,受益于k8s提供的简洁可定义声明式api。

Extension Patterns

  1. cloud providers: in-tree controller manager:

  2. kubelet: network, devices, storage, container runtimes

  3. extend kubectl with plugins

  4. extensions in the API server, dynamic admission control with webhook

  5. Custom resources and custom controllers.

  6. custom apiserver

  7. scheduler extensions.

Controllers and operators

  1. controller: 实现了一个控制循环,从API server监听到的集群状态,并且把当前状态调整到预期状态。

  2. operator: 是指controller+ 自定义资源的方式,去做像应用生命周期管理相关的一些操作。

the controller loop

  1. 读取资源的状态,更倾向于事件驱动。

  2. 改变集群或外部集群的对象的状态。

  3. 通过apiserver更新存储在etcd中资源的状态。

  4. 重复循环。回到步骤1.

不管controller的实现复杂与否,这三步骤都是一致的。读取资源状态->改变the world-> 更新资源状态。

API Basics怎么实现

informers:

负责watch期望的状态,实现resync机制加强周期性的调谐,通常用来确保集群状态和存在内存中的期望状态不飘动。

work queues:

在client-go的workqueue包中实现了,为event handler提供work queues来“存储”状态变更操作的队列及其各种重试操作。当更新当前资源对象状态出错时,资源需要重新被排序。

Events

k8s的控制面通过事件驱动 进行解耦,其他分布式系统通过远程过程调用来触发各种行为。controller 通过watch k8s对象的变化对APISERVER的增、删、改请求。

example:

  1. 用户 创建一个dp时,dp controller通过dp informer 创建一个rs。

  2. rs controller通过 rs informer 创建一个新的rs,并且创建一个pod对象。

  3. scheduler通过pod informer观测到新的pod,且它的spec.nodeName 为空,就把这个pod放入调度队列。

  4. 与此同时,kubelet通过pod informer观测到新的pod,且它的spec.nodeName 为空。所以并没有match到kubelet的nodeName,会忽略这个pod 继续等待下一次事件。

  5. scheduler从workqueue中拿出pod,并且通过更新spec.nodeName字段,调度到有足够资源的指定node,并且写入apiserver。

  6. kubelet因为pod update事件,继续比较spec.NodeName 和其本身的nodeName. 当match之后,通过启动pod的container,并且把container启动的状态信息写入pod status, 返回存储到apiserver。

  7. rs controller注意到pod改变。

  8. 最后pod销毁时,kubelet watch到pod事件并且将pod状态设置为“terminated”状态,并更新到apiserver。

  9. rs controller观测到结束的pod,决定这个pod一定需要被替换。于是通过apiserver删除 terminated状态的pod,并且创建一个新的。

一系列独立的控制循环,通过watch apiserver中对象的变化,并且这些变更事件通过informers来触发变更。

watch events 和 event对象是两个东西:

  1. 前者通过在apiserver和controllers之间建立http streaming 的链接用来驱动informers.

  2. 后者是一种资源,像pod,dp,services这些,带有特殊的时效属性并且自动从etcd里消失。

Edge-driven triggers or Level-driven triggers 

前者是基于某个状态值变更的瞬间去触发handler,后者是在某个时间段内、状态被验证与期望值相符,则去触发handler。

后者更像是一种polling轮询,能否扩容到指定数量、控制器注意到变更的延迟依赖于polling轮询的时间间隔以及apiserver的响应时间。与很多异步的控制器相关,最终系统需要花费一段时间才能达到预期状态。

前者效率更高,延迟则依赖在控制器处理事件时,运行的工作线程。因此k8s基于事件驱动,即edge-driven triggers.

API Basics怎么实现

reconciliation with resync:每5分钟持续调谐。

edge-triggered, level-driven

level-triggering-and-reconciliation

Changing Cluster Objects or the External world

Optimistic Concurrency

单体式:

二阶段:

共享状态:

并行调度架构:

新一代的并发调度架构依赖共享状态,使用乐观并发控制达到实现可扩展和性能可伸缩。

k8s 中乐观锁的场景是:

retry loop中,获取了foo对象最新的状态后,尝试根据foo spec更新real world 和foo status,实际修改的操作在Update事件之前执行。

通过client.Get返回的foo对象,包含资源的版本,ObjectMeta结构体。这个结构体会在client.Update调用时,通过写操作更新etcd的数据。所谓的资源版本,在etcd中存储的实际上是<string,int> 键值对。etcd维护了一个计数器counter,每次key的值被修改时,counter值加一。

在API machinery代码中,资源版本的处理像是任意的string,实际上还是遵循一些规则。实际的实现细节在etcd存储后端。

essence: 控制器中的冲突错误十分常见,处理和期待十分优雅。

Operators

operator是一种针对特定应用的控制器,扩展了k8s API的创建、配置、管理复杂的有状态应用的实例。

一个operator包括一个 CRD+ controller。

API Basics怎么实现

Kubernetes API Basics

apiserver作为挡在存储etcd前的唯一组件,跟etcd进行直接交互。主要职责是作为k8s api的server 和集群组件的proxy。

伺服API意味着 读取状态和 操作状态。

声明式状态管理

通过比较期望状态的spec和当前实际状态的值,

例如:当你在dp的声明yaml里指定20个副本数,dp controller读到dp spec并且创建rs,实际去接管rs- 即特定个数的pods。如果有任何副本跪了,dp controller会让你在状态中感知到。

APIServer Processes Requests

API Basics怎么实现

DefaultBuildHandlerChain()

WithPanicRecovery(): 处理恢复和日志panic

Basics of client-go

Repos

ClientLibrary

k8s项目提供client-go(https://github.com/kubernetes/client-go) 作为用户的开发工具集,提供了多种类型的API支持,以及包含许多通用库代码。

K8S API Types

client-go管理了客户端接口,像PODS,services,deployments这些接口,在这个repo中维护(https://github.com/kubernetes/api),pod等的类型在k8s.io/api/core/v1/types.go中定义,而这些文件均由code gen自动生成维护。

// Pod is a collection of containers that can run on a host. This resource is created
// by clients and scheduled onto hosts.
type Pod struct {
   metav1.TypeMeta `json:",inline"`
   // Standard object's metadata.
   // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata
   // +optional
   metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`

   // Specification of the desired behavior of the pod.
   // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status
   // +optional
   Spec PodSpec `json:"spec,omitempty" protobuf:"bytes,2,opt,name=spec"`

   // Most recently observed status of the pod.
   // This data may not be up to date.
   // Populated by the system.
   // Read-only.
   // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status
   // +optional
   Status PodStatus `json:"status,omitempty" protobuf:"bytes,3,opt,name=status"`

}

API machinery

第三个repo(https://github.com/kubernetes/apimachinery ) 包含所有通用的构建模块,不仅限于容器管理,还包括其他构建 APIs。在pkg/api/meta/v1 下可以查看到许多API类型的定义,包括如下:

ObjectMeta: Name + Namespaces + ResourceVersion + Labels + Annotations

TypeMeta : Kind + APIVersion

GetOptions,

ListOptions

构建模块用来创建k8s客户端对象,代表在k8s集群中能访问的资源。

版本和兼容

k8s 的api是按版本区分的,一方面client的不同版本去访问API server,如果版本不匹配,请求会失败。client 与特定的版本绑定,应用开发者需要选择正确的

其版本与k8s版本对应关系如图:

| Branch | Canonical source code location | Maintenance status |
| `release-1.4` | Kubernetes main repo, 1.4 branch | = - |
| `release-1.5` | Kubernetes main repo, 1.5 branch | = - |
| `release-2.0` | Kubernetes main repo, 1.5 branch | = - |
| `release-3.0` | Kubernetes main repo, 1.6 branch | = - |
| `release-4.0` | Kubernetes main repo, 1.7 branch | = - |
| `release-5.0` | Kubernetes main repo, 1.8 branch | = - |
| `release-6.0` | Kubernetes main repo, 1.9 branch | = - |
| `release-7.0` | Kubernetes main repo, 1.10 branch | = - |
| `release-8.0` | Kubernetes main repo, 1.11 branch | =- |
| `release-9.0` | Kubernetes main repo, 1.12 branch | =- |
| `release-10.0` | Kubernetes main repo, 1.13 branch | =- |
| `release-11.0` | Kubernetes main repo, 1.14 branch | ✓ |
| `release-12.0` | Kubernetes main repo, 1.15 branch | ✓ |
| `release-13.0` | Kubernetes main repo, 1.16 branch | ✓ |
| `release-14.0` | Kubernetes main repo, 1.17 branch | ✓ |
| client-go HEAD | Kubernetes main repo, master branch | ✓ |

Key:

  • Changes in main Kubernetes repo are actively published to client-go by a bot

  • = Maintenance is manual, only severe security bugs will be patched.

  • - Deprecated; please upgrade.

你看代码有哪些用的较多的公用库呀:  sharedInformer、workqueue、event、leaderelection、rest、scheme、flowcontrol、codec

K8S objects in Go

k8s资源是一种kind的实例,在API server作为一种资源结构体提供服务。

k8s中的object 实现了runtime.Object接口,来自于k8s.io/apimachinery/pkg/runtime包。其中,schema.ObjectKind主要实现的另一个接口,来自于k8s.io/apimachinery/pkg/runtime/schema.

这些Go实现的object作为数据结构主要是用来返回和设置GroupVersionKind, 以及用来深度拷贝。

type Object interface { 
  GetObjectKind () schema.ObjectKind 
  DeepCopyObject () Object 
}&nbsp;
type ObjectKind interface { 
// SetGroupVersionKind sets or clears the intended serialized kind of an 
// object. Passing kind nil should clear the current setting. 
  SetGroupVersionKind ( kind GroupVersionKind ) 
// GroupVersionKind returns the stored group, version, and kind of an // object, or nil if the object does not expose or provide these fields. 
  GroupVersionKind () GroupVersionKind 
}&nbsp;

TypeMeta

通过嵌套metav1.TypeMeta(k8s.io/apimachinery/meta/v1)来实现k8s对象schema.ObjectMeta(k8s.io/api)的getter和setter类型。

// TypeMeta describes an individual object in an API response or request
// with strings representing the type of the object and its API schema version.
// Structures that are versioned or persisted should inline TypeMeta.
//
// +k8s:deepcopy-gen=false
type TypeMeta struct {
   // Kind is a string value representing the REST resource this object represents.
   // Servers may infer this from the endpoint the client submits requests to.
   // Cannot be updated.
   // In CamelCase.
   // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds
   // +optional
   Kind string `json:"kind,omitempty" protobuf:"bytes,1,opt,name=kind"`

   // APIVersion defines the versioned schema of this representation of an object.
   // Servers should convert recognized schemas to the latest internal value, and
   // may reject unrecognized values.
   // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#resources
   // +optional
   APIVersion string `json:"apiVersion,omitempty" protobuf:"bytes,2,opt,name=apiVersion"`
}
// Pod is a collection of containers that can run on a host. This resource is created
// by clients and scheduled onto hosts.
type Pod struct {
   metav1.TypeMeta `json:",inline"`
   // Standard object's metadata.
   // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata
   // +optional
   metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`

   // Specification of the desired behavior of the pod.
   // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status
   // +optional
   Spec PodSpec `json:"spec,omitempty" protobuf:"bytes,2,opt,name=spec"`

   // Most recently observed status of the pod.
   // This data may not be up to date.
   // Populated by the system.
   // Read-only.
   // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status
   // +optional
   Status PodStatus `json:"status,omitempty" protobuf:"bytes,3,opt,name=status"`

}

基于client-go的应用这些字段在内存中值为空,在实际序列化成json或者pb时,才会有实际的值。而这些约定在版本序列中自动实现。

ObjectMeta

出了TypeMeta,大部分top-level对象还会包括metav1.ObjectMeta,来自k8s.io/apimachinery/pkg/meta/v1。

(staging/src/k8s.io/apimachinery/pkg/apis/meta/v1/types.go)

type ObjectMeta struct { 
Name string `json:"name,omitempty"` 
Namespace string `json:"namespace,omitempty"` 
UID types.UID `json:"uid,omitempty"` 
ResourceVersion string `json:"resourceVersion,omitempty"` CreationTimestamp Time `json:"creationTimestamp,omitempty"` DeletionTimestamp * Time `json:"deletionTimestamp,omitempty"` 
Labels map [ string ] string `json:"labels,omitempty"` 
Annotations map [ string ] string `json:"annotations,omitempty"` 
... 
}

metav1.ObjectMeta基本包含所有元数据信息,像name,namespace,resource version, 一些时间戳,以及labels 和annotation. 其中client-go并不能对resource version进行读写,但却是整个k8s代码中核心工作的重要信息.

它作为ObjectMeta信息的一部分,来源于etcd里所有数据的key字段。

Client Sets

kubernetes.NewForConfig(config)返回一个 client set, 用它可以访问定义在k8s.io/api中的大部分API groups和resources,除了APIServices(aggregated API servers)和CRD。

clientSet主接口如下:

type Interface interface {
   Discovery() discovery.DiscoveryInterface
   AdmissionregistrationV1alpha1() admissionregistrationv1alpha1.AdmissionregistrationV1alpha1Interface
   AdmissionregistrationV1beta1() admissionregistrationv1beta1.AdmissionregistrationV1beta1Interface
   // Deprecated: please explicitly pick a version if possible.
   Admissionregistration() admissionregistrationv1beta1.AdmissionregistrationV1beta1Interface
   AppsV1beta1() appsv1beta1.AppsV1beta1Interface
   AppsV1beta2() appsv1beta2.AppsV1beta2Interface
   AppsV1() appsv1.AppsV1Interface
   // Deprecated: please explicitly pick a version if possible.
   Apps() appsv1.AppsV1Interface
   AuthenticationV1() authenticationv1.AuthenticationV1Interface
   // Deprecated: please explicitly pick a version if possible.
   Authentication() authenticationv1.AuthenticationV1Interface
   AuthenticationV1beta1() authenticationv1beta1.AuthenticationV1beta1Interface
   AuthorizationV1() authorizationv1.AuthorizationV1Interface
   // Deprecated: please explicitly pick a version if possible.
   Authorization() authorizationv1.AuthorizationV1Interface
   AuthorizationV1beta1() authorizationv1beta1.AuthorizationV1beta1Interface
   AutoscalingV1() autoscalingv1.AutoscalingV1Interface
   // Deprecated: please explicitly pick a version if possible.
   Autoscaling() autoscalingv1.AutoscalingV1Interface
   AutoscalingV2beta1() autoscalingv2beta1.AutoscalingV2beta1Interface
   BatchV1() batchv1.BatchV1Interface
   // Deprecated: please explicitly pick a version if possible.
   Batch() batchv1.BatchV1Interface
   BatchV1beta1() batchv1beta1.BatchV1beta1Interface
   BatchV2alpha1() batchv2alpha1.BatchV2alpha1Interface
   CertificatesV1beta1() certificatesv1beta1.CertificatesV1beta1Interface
   // Deprecated: please explicitly pick a version if possible.
   Certificates() certificatesv1beta1.CertificatesV1beta1Interface
   CoreV1() corev1.CoreV1Interface
   // Deprecated: please explicitly pick a version if possible.
   Core() corev1.CoreV1Interface
   EventsV1beta1() eventsv1beta1.EventsV1beta1Interface
   // Deprecated: please explicitly pick a version if possible.
   Events() eventsv1beta1.EventsV1beta1Interface
   ExtensionsV1beta1() extensionsv1beta1.ExtensionsV1beta1Interface
   // Deprecated: please explicitly pick a version if possible.
   Extensions() extensionsv1beta1.ExtensionsV1beta1Interface
   NetworkingV1() networkingv1.NetworkingV1Interface
   // Deprecated: please explicitly pick a version if possible.
   Networking() networkingv1.NetworkingV1Interface
   PolicyV1beta1() policyv1beta1.PolicyV1beta1Interface
   // Deprecated: please explicitly pick a version if possible.
   Policy() policyv1beta1.PolicyV1beta1Interface
   RbacV1() rbacv1.RbacV1Interface
   // Deprecated: please explicitly pick a version if possible.
   Rbac() rbacv1.RbacV1Interface
   RbacV1beta1() rbacv1beta1.RbacV1beta1Interface
   RbacV1alpha1() rbacv1alpha1.RbacV1alpha1Interface
   SchedulingV1alpha1() schedulingv1alpha1.SchedulingV1alpha1Interface
   SchedulingV1beta1() schedulingv1beta1.SchedulingV1beta1Interface
   // Deprecated: please explicitly pick a version if possible.
   Scheduling() schedulingv1beta1.SchedulingV1beta1Interface
   SettingsV1alpha1() settingsv1alpha1.SettingsV1alpha1Interface
   // Deprecated: please explicitly pick a version if possible.
   Settings() settingsv1alpha1.SettingsV1alpha1Interface
   StorageV1beta1() storagev1beta1.StorageV1beta1Interface
   StorageV1() storagev1.StorageV1Interface
   // Deprecated: please explicitly pick a version if possible.
   Storage() storagev1.StorageV1Interface
   StorageV1alpha1() storagev1alpha1.StorageV1alpha1Interface
}

在这个接口中存在一些没有版本的方法:appsv1beta1.AppsV1beta1Interface。

>在过去k8s有所谓的内部客户端,为了对象在内存中存在的更加通用,并且遵循在需要的时候再定义的规范。这种规范为了从实际使用的API版本中抽象controller代码,同时方便切换不同版本。事实上,为了遵循这种规范,增加了大量的复杂性,付出了不太值得的代价。 >此外,在client和APIServer之间的交互,并没有自动协商的机制。尽管存在内部的版本和客户端,controller硬编码到指定版本导致并没有很好兼容。 >在最近的版本,k8s代码尽量避免用到这些内部版本。

所有clientset可以访问discovery client,被用作RESTMappers;

type AppsV1beta1Interface interface {
   RESTClient() rest.Interface
   ControllerRevisionsGetter
   DeploymentsGetter
   ScalesGetter
   StatefulSetsGetter
}

在每个GroupVersion(AppsV1beta1)下我们发现API group的资源都存在通用的RESTClient

读到这里,这篇“API Basics怎么实现”文章已经介绍完毕,想要掌握这篇文章的知识点还需要大家自己动手实践使用过才能领会,如果想了解更多相关内容的文章,欢迎关注亿速云行业资讯频道。

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

api
AI