Kubernetes

Kubernetes资源类型发现

在基于Kubernetes平台开发过程中,经常需要访问不同Kuberntes版本的集群资源,这时就需要去获取所访问集群支持的资源版本信息。下面我们一起来看一下,如何来实现Kubernetes资源类型发现? 文章分为下面几部分为大家介绍: 1,kubectl命令查看Kubernetes集群资源 2,client-go库获取Kubernetes集群资源 3,controller-runtime动态获取Kubernetes集群资源 kubectl命令 kubectl命令行工具提供api-resources,api-versions命令来查看kubernetes集群当前支持的资源类型。 kubectl api-resources查看k8s所有资源和版本列表。 sukai@sukai:~$ kubectl api-resources NAME SHORTNAMES APIVERSION NAMESPACED KIND bindings v1 true Binding componentstatuses cs v1 false ComponentStatus configmaps cm v1 true ConfigMap endpoints ep v1 true Endpoints events ev v1 true Event limitranges limits v1 true LimitRange namespaces ns v1 false Namespace nodes no v1 false Node persistentvolumeclaims pvc v1 true PersistentVolumeClaim persistentvolumes pv v1 false PersistentVolume pods po v1 true Pod .

继续阅读

通过Karmada实现应用多Kubernetes集群管理--调度器

前面文章介绍了Karmada的控制器流程,了解了Karmada如何实现Kubernetes资源下发到成员集群的。今天我们一起看一下Karmada的调度器,看看Karmada如何实现Kubernetes资源下发调度的。 前面控制器流程里讲过,用户创建了Kubernetes资源对象模板,下发策略和差异策略后,由resourceDetector根据下发策略,创建ResourceBinding绑定资源与策略,再由BindingController根据ResourceBinding,查找并应用OverridePolicy,最终生成创建成员集群资源的Work,由ExecutionController在成员集群中执行Work完成Kubernetes资源操作。 在流程上,Karmada调度器工作在ResourceBinding创建生成后,BindingController控制器工作之前。在功能上,Karmada调度器主要负责Kubernetes资源对象在成员集群的分布,Karmada调度器通过算法得出在哪些成员集群上运行多少个副本数量的结果,将调度结果保存到ResourceBinding的Clusters参数中。 业务流程 1,监听事件加入队列:Informer监听资源绑定ResourceBinding, 下发策略PropagationPolicy事件,将对应的ResourceBinding资源加入工作队列。 2,取出队列中ResourceBinding对象:每秒中开启一个worker,从队列中取出ResourceBinding对象进行处理。循环处理工作队列,直到队列处理结束。 3,获取分布规则:根据ResourceBinding的Annotation中下发策略PropagationPolicy名称,获取下发策略的分布规则。分布规则包括:集群亲和,集群容忍,拓扑分布约束规则以及副本调度策略等信息。 4,判断是否进行ResourceBinding调度:比对新旧分布规则,判断是否需要进行ResourceBinding调度。 5,调度ResourceBinding,计算出成员集群分配副本数量: a,FilterPlugin过滤插件判断集群亲和和容忍是否匹配条件,得到匹配集群。 b,ScorePlugin计算匹配集群的得分,得到集群的优先级。 c,根据SpreadConstraint拓扑分布约束规则,得到最后的下发成员集群。 d,发配副本,副本调度策略类型分两种:Duplicated复制, Divided切分。如果是复制类型,每个成员集群部署与模板相同的资源副本数量。如果是切分类型,可以配置PreferenceWeighted权重优先和PreferenceAggregated聚合优先,前者会根据权重比例来进行切分,后者根据总的副本数量来判断是scaleUP还是scaleDown,再根据成员集群的最大可用副本数来分配副本数量。 6,更新ResourceBinding中的Clusters字段,设置为计算出的成员集群分配副本数量结果。 7,完成了一个ResourceBinding的处理,继续处理下一条。 代码实现 过滤和计分插件 构造调度算法实例,算法插件包括:集群亲和,污点容忍,已安装支持的资源API,已下发集群。 algorithm := core.NewGenericScheduler(schedulerCache, []string{clusteraffinity.Name, tainttoleration.Name, apiinstalled.Name, clusterlocality.Name}) 集群亲和:过滤插件,1,集群名称是否在亲和策略的排除集群列表中。2,集群的标签、字段过滤是否与亲和策略中的标签和字段过滤匹配。返回是否成功结果。 // Filter checks if the cluster matched the placement cluster affinity constraint. func (p *ClusterAffinity) Filter(ctx context.Context, placement *policyv1alpha1.Placement, resource *workv1alpha2.ObjectReference, cluster *clusterv1alpha1.Cluster) *framework.Result { affinity := placement.ClusterAffinity if affinity != nil { if util.ClusterMatches(cluster, *affinity) { return framework.NewResult(framework.Success) } return framework.NewResult(framework.Unschedulable, "cluster is not matched the placement cluster affinity constraint") } // If no clusters specified and it is not excluded, mark it matched return framework.

继续阅读

通过Karmada实现应用多Kubernetes集群管理--控制器

Karmada是华为云开源的,提供应用的跨云多集群统一管理和部署。今天一起来看一下Karmada的控制器,怎么来完成集群纳管和Kubernetes应用工作负载在成员集群创建的。 基本概念 Cluster 在Karmada集群管理中,将Kubernetes集群分为两种:控制面集群,成员集群。控制面集群是Karmada管理组件所在的集群。成员集群为纳管的业务集群。Cluster自定义资源指的是成员集群,指定成员集群的API地址,访问密钥,伪装身份,同步模式。同步模式分为Push和Pull,控制面集群能够主动建立与成员集群的连接,创建资源的为Push模式,控制面集群不能与成员集群主动建立连接的,成员集群建立与控制面集群的连接,监听控制面集群的资源事件,创建资源的为Pull模式。 PropagationPolicy Namespaced下发策略,Kubernetes资源对象下发到成员集群的策略,指定资源对象,成员集群。ClusterPropagationPolicy,非Namespaced下发策略。PropagationPolicy只能下发自己所在命名空间的资源,ClusterPropagationPolicy能够下发集群范围的除了系统保留命名空间外的任意命名空间的资源。 OverridePolicy Namespaced差异策略,Kubernetes资源对象下发到某些集群时,使用指定的参数值。ClusterOverridePolicy,非Namespaced差异策略。 ResourceBinding 根据下发策略生成ResourceBinding,指定具体版本的Kubernetes资源对象与下发策略PropagationPolicy绑定。ClusterResourceBinding绑定Kubernetes资源与ClusterPropagationPolicy。 Work 下发到成员集群的资源列表,可以为Deployment, Configmap, Service, Role, CRD等Kubernetes资源。控制面集群通过Work来实现对成员集群的资源控制。Push模式下,控制面集群监听Work资源事件,执行对成员集群的资源对象操作。Pull模式下,成员集群Agent监听Work资源事件,并在成员集群里执行资源对象的操作。 Karmada用户操作 1,添加成员集群,创建Cluster自定义资源的实例对象 2,创建Kubernetes的资源,这里就是Kubernetes原生的Deployment, Statefulset, Daemonset, Job, Configmap, Secret, Service等。 3,创建下发策略PropagationPolicy,指定资源对象部署到哪些集群中。 4,创建差异策略OverridePolicy,指定资源对象在哪些集群中覆盖哪些参数值。 Karmada用户操作完成后,由Karmada控制器进行资源调谐,最终完成在指定的成员集群中创建Kubernetes资源对象。 Karmada控制器 ClusterController 负责调谐Cluster自定义资源,创建集群对应的execution命名空间。Cluster为纳入管理的业务成员集群。 ClusterStatusController 负责调谐Cluster子资源Status,检测并更新成员集群的健康状态、资源使用信息、集群版本信息、集群主机资源信息以及支持的APIResource。 HpaController Pod水平自动扩展控制器,负责调谐HorizontalPodAutoscaler自定义资源。在成员集群创建对应的HorizontalPodAutoscaler。 BindingController 包括两个控制器,ResourceBindingController监听Work, OveridePolicy, ClusterOverridePolicy资源的事件,调谐ResourceBinding负责创建对应的Work,指定要创建的Kubernetes工作负载Workload。ClusterResourceBindingController主要调谐ClusterResourceBinding。 ExecutionController 负责调谐Work自定义资源,在指定集群创建用户定义的Kubernetes工作负载Workload。 WorkStatusController 负责调谐Work的子资源Status,将引用的资源信息保存到Status中。 NamespaceController 监听Cluster自定义资源事件,创建Work,指定创建namespace。 ServiceExportController 监听Work事件,启动对应集群的Informer,监听serviceexports,endpointslices事件,将事件处理后放入worker队列。 EndpointSliceController 监听Work事件,根据Work定义,创建对应的EndpointSlice。 ServiceImportController 调谐ServiceImport资源,创建Kubernetes Service资源对象。 UnifiedAuthController 监听Cluster, ClusterRole, ClusterRoleBinding资源事件,生成Work指定创建ClusterRole, ClusterRoleBinding资源对象。 FederatedResourceQuotaSyncController 调谐FederatedResourceQuota,监听Cluster事件,创建Work指定创建ResourceQuota资源。 FederatedResourceQuotaStatusController 调谐FederatedResourceQuota子资源Status,更新Status信息。 Karmada控制器执行流程 1,创建一个成员集群Cluster资源实例 2,ClusterController创建成员集群对应的执行命名空间executionNamespace。 3,UnifiedAuthController生成创建成员集群ClusterRole, ClusterRoleBinding的Work。 4,ExecutionController根据Work中的集群和资源对象,在成员集群中执行对应操作,比如创建ClusterRole, ClusterRoleBinding等。 5,ClusterStatusController更新成员集群的健康状态,集群及主机信息。 6,成员集群加入成功后,用户创建Kubernetes资源对象模板,下发策略PropagationPolicy,差异配置策略OverridePolicy。

继续阅读

Kubernetes应用系统API用户认证与鉴权 -- 鉴权篇

上篇文章讲了通过LDAP和Dex实现两种不同的API用户认证的方式,用户认证是识别API请求的来源,让系统知道请求的访问者是谁。应用系统可以根据请求的身份,来判断该用户可以访问哪些API接口获得数据,这就是用户鉴权。下面我们一起来看一下,在Kubernetes平台上,如何通过RBAC来实现资源访问限制,同样我们还是通过Kubesphere的代码来学习。 鉴权实现的过程: 1,构建一个HandlerChain,HandlerChain中包含了:WithAuthentication, WithRequestInfo和WithAuthorization用户认证和鉴权的三个Filter以及WithAuditing Filter用于审计日志。Filter可以理解为web 框架的Middleware。 2,filters.WithAuthentication上篇文章介绍过,完成用户身份识别和分发Token,将用户信息写入Context。 3,filters.WithRequestInfo处理API请求信息,将请求信息保存到context中。请求信息包括:Path, Verb, APIPrefix, APIGroup, APIVersion, Namespace, Resource, Name这些RBAC鉴权需要用到的资源信息,以及客户端信息等。 4,filters.WithAuthorization根据RequestInfo和RBAC规则,判断请求的合法性,终止或者允许请求继续下去。 代码实现: 1,HandlerChain处理请求 这里可以看到有两个鉴权,一个是pathAuthorizer,一个是RBACAuthorizer,pathAuthorizer定义了哪些URL Path不需要鉴权,RBACAuthorizer顾名思义就是通过RBAC鉴权,后面我们详细介绍这两个鉴权。 var authorizers authorizer.Authorizer switch s.Config.AuthorizationOptions.Mode { case authorization.AlwaysAllow: authorizers = authorizerfactory.NewAlwaysAllowAuthorizer() case authorization.AlwaysDeny: authorizers = authorizerfactory.NewAlwaysDenyAuthorizer() default: fallthrough case authorization.RBAC: excludedPaths := []string{"/oauth/*", "/kapis/config.kubesphere.io/*", "/kapis/version", "/kapis/metrics"} pathAuthorizer, _ := path.NewAuthorizer(excludedPaths) amOperator := am.NewReadOnlyOperator(s.InformerFactory, s.DevopsClient) authorizers = unionauthorizer.New(pathAuthorizer, rbac.NewRBACAuthorizer(amOperator)) } handler = filters.WithAuthorization(handler, authorizers) handler = filters.WithAuthentication(handler, authn) handler = filters.WithRequestInfo(handler, requestInfoResolver) s.

继续阅读

Kubernetes应用系统API用户认证与鉴权 -- 认证篇

前面文章介绍了Kubernetes应用系统用户管理,实现了外部用户存储(LDAP)与Kubernetes用户映射,下面以Kubesphere为参考,一起看一下如何实现Kubernetes应用系统用户的认证。 应用平台用户认证主要实现两个功能: 1,用户身份鉴别 用户身份认证可以通过LDAP进行用户名和密码认证,也可以通过第三方认证服务进行OAuth认证。 2,Token管理 Client端认证通过后,带上获取Token请求API。应用系统根据Token提取用户ID,进行请求权限鉴别。同时应用系统负责Token的生命周期管理。 基本概念: OpenID Connect(OIDC)是基于OAuth 2.0身份认证协议,增加了OAuth 2.0中末定义的规范,例如scope, Claim用户信息字段。 代码实现 基本认证方式 API路由 // legacy auth API legacy := &restful.WebService{} legacy.Path("/aiapis/iam.aiscope/v1alpha2/login"). Consumes(restful.MIME_JSON). Produces(restful.MIME_JSON) legacy.Route(legacy.POST(""). To(handler.login). Deprecate(). Doc("Aiscope APIs support token-based authentication via the Authtoken request header. The POST Login API is used to retrieve the authentication token. After the authentication token is obtained, it must be inserted into the Authtoken header for all requests."). Reads(LoginRequest{}). Returns(http.StatusOK, api.StatusOK, oauth.Token{}). Metadata(restfulspec.

继续阅读

Kubernetes应用平台API开发实战

前面文章介绍了通过基于go-restful框架开发API, client-go生成clientset, informers, listers来读取和写入自定义资源,基于kubebuilder开发CRD资源控制器。今天我们通过一个实例来看一下API整个开发过程。 开发步骤 1,通过kubebuilder来开发CRD控制器 2,通过client-gen,lister-gen,informer-gen生成clientset, informers, listers代码 3,开发models实现CRD资源的kubernets读写操作,读取列表时的排序,分页,过滤 4,开发handler实现CRD资源的API处理 CRD资源的读操作 CRD资源的读操作通过Informer来读取,减少API和Etcd集群的压力。 Informer的主要工作原理为:通过Reflector反射来监听Kubernetes对资源的操作事件,把资源对象和操作类型写入到一个DeltaFIFO的队列中。Reflector消费队列,将资源对象存储到indexer,indexer与Etcd集群的数据完全保持一致。 CRD资源的写操作 CRD资源的写通过client-go的clientset来完成对资源的Create,Update,Patch操作。 代码开发 这里我们需要实现上一篇讲的TrackingServer自定义资源的API。TrackingServer主要用于管理机器学习实验跟踪MLflow在k8s里的实例资源。 创建Informer informerFactories结构体实现了InformerFactory接口,这个接口有两个SharedInformerFactory,一个为Kubernetes资源的informerFactory,一个为本项目自定义资源的aiInformerFactory。aiscopeinformers.NewSharedInformerFactory创建了一个aiInformerFactory实例,这里的NewSharedInformerFactory为代码生成器生成的方法。通过代码生成器创建clientset客户端aiClient,作为参数来创建InformerFactory type InformerFactory interface { KubernetesSharedInformerFactory() k8sinformers.SharedInformerFactory AIScopeSharedInformerFactory() aiscopeinformers.SharedInformerFactory // Start shared informer factory one by one if they are not nil Start(stopCh <-chan struct{}) } type informerFactories struct { informerFactory k8sinformers.SharedInformerFactory aiInformerFactory aiscopeinformers.SharedInformerFactory } func NewInformerFactories(client kubernetes.Interface, aiClient versioned.Interface) InformerFactory { factory := &informerFactories{} if client != nil { factory.informerFactory = k8sinformers.

继续阅读

Kubebuilder开发MLflow实验跟踪控制器

前面文章讲了client-go, go-restful开发Kubernetes应用平台,今天给大家看看在这个应用平台中添加一个自定义资源控制器的开发。 需求场景: 在多租户机器学习平台中,开发一个Kubernetes控制器,实现CRD(自定义资源) TrackingServer的调谐,完成Kubernetes中对应的PersistentVolumeClaim, TLS Secret, Service, Ingress, Deployment资源管理。 功能描述: 1,当CR实例的参数中指定了VolumeSize和StorageClassName,则创建对应的PersistentVolumeClaim用于MLflow的local database sqllite的数据存储目录。当未指定时,不创建或者删除已经创建的PersistentVolumeClaim。 2,当CR实例的参数中指定了Cert和Key数据,则创建对应的TLS类型的Secret,用于Ingress的TLS证书。当未指定时,不创建或删除对应Secret。 3,查找对应命名空间和名称的Secret,如果有Ingress配置对应的TLS证书。 4,根据CR实例的参数管理Service和Deployment的创建和修改。 5,删除CR实例后,对应清理K8S资源。当删除资源时,判断被删除资源是否为CR实例的附属资源。 代码实现: 整个业务代码开发分为几个大的步骤: 1,Kubebuilder生成代码和部署文件 2,在Controller Manager中注册控制器 3,在控制器调谐代码中,实现业务逻辑 Kubebuilder中创建API 指定GVK,这里TrackingServer为我们需要的MLflow资源。 kubebuilder create api --group experiment --version v1alpha2 --kind TrackingServer kubebuilder create api --group experiment --version v1alpha2 --kind JupyterNotebook kubebuilder create api --group experiment --version v1alpha2 --kind CodeServer 自定义资源TrackingServer定义 定义VolumeSize, Cert, Key字段为omitempty,表示非必须字段。 +genclient表示代码生成器生成clientset,informer, lister代码。 printcolumn表示kubectl get资源时展示字段 // TrackingServerSpec defines the desired state of TrackingServer type TrackingServerSpec struct { // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster // Important: Run "make" to regenerate code after modifying this file Size int32 `json:"size"` Image string `json:"image"` S3_ENDPOINT_URL string `json:"s3_endpoint_url"` AWS_ACCESS_KEY string `json:"aws_access_key"` AWS_SECRET_KEY string `json:"aws_secret_key"` ARTIFACT_ROOT string `json:"artifact_root"` BACKEND_URI string `json:"backend_uri"` URL string `json:"url"` VolumeSize string `json:"volumeSize,omitempty"` StorageClassName string `json:"storageClassName,omitempty"` Cert string `json:"cert,omitempty"` Key string `json:"key,omitempty"` } // TrackingServerStatus defines the observed state of TrackingServer type TrackingServerStatus struct { // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster // Important: Run "make" to regenerate code after modifying this file } // +genclient // +kubebuilder:object:root=true // +kubebuilder:subresource:status // +kubebuilder:printcolumn:name="S3_ENDPOINT_URL",type="string",JSONPath=".

继续阅读

go-restful框架开发Kubernetes应用平台

go-restful是一个golang语言实现的RESTful库,Kubernetes APIServer使用它实现RESTful API。下面我们一起简单看一下Kubesphere如何使用go-restful的。 Container Container逻辑上是WebService的集合,功能上可以实现多终端的效果。 它包括一组restful.WebService和一个http.ServeMux对象,使用RouteSelector进行请求派发。 Webservice WebService逻辑上是Route的集合,功能上主要是为一组Route统一设置包括root path,请求响应的数据类型等一些通用的属性。 Route 路由包含两种,一种是标准JSR311接口规范的实现RouterJSR311,一种是快速路由CurlyRouter。 CurlyRouter支持正则表达式和动态参数,相比RouterJSR11更加轻量级,apiserver中使用的就是这种路由。 一种Route的设定包含:请求方法(http Method),请求路径(URL Path),输入输出类型(JSON/YAML)以及对应的回掉函数restful.RouteFunction,响应内容类型(Accept)等。 代码示例:一个API聚合服务,包含两种服务,一种是/api, /apis两个路径请求代理给Kubernetes,另一种是本地注册API提供服务。 定义APIServer结构体 type APIServer struct { ServerCount int Server *http.Server Config *apiserverconfig.Config // webservice container, where all webservice defines container *restful.Container KubernetesClient k8s.Client } APIServer构造函数 初始化kubernets Client和http server func (s *ServerRunOptions) NewAPIServer(stopCh <-chan struct{}) (*apiserver.APIServer, error) { apiServer := &apiserver.APIServer{ Config: s.Config, } kubernetesClient, err := k8s.NewKubernetesClient(s.KubernetesOptions) if err != nil { return nil, err } apiServer.

继续阅读

Kubernetes Operator实现用户管理

在Kubernetes里User只是一个用户身份辨识的ID,没有真正用户管理,k8s一般通过第三方提供用户管理和存储,k8s通过User进行身份验证与权限认证。 Kubernetes用户验证支持X509证书认证,token认证和密码验证几种方式。 RBAC是Kubernetes进行权限控制的方式。用户与角色绑定,赋予角色权限。 今天我们来一起看一下Kubesphere如何通过Operator实现kubernetes用户管理。我们在Kubernetes里创建User自定义资源,使用LDAP存储用户帐号信息。通过Kubernets CertificateSigningRequest请求X509证书,生成Kubeconfig。通过各种自定义Role资源来创建Kubernetes Role与用户绑定,分配用户权限。最终用户通过客户端使用kubeconfig来访问Kubernetes资源。 这个场景不像Dex这种Kubernetes OpenID服务,他不需要在Kubernetes APIServer上进行配置,改变Kubernetes集群的部署配置。 代码主要流程 1, User控制器调谐,创建LDAP用户,创建用户KubeConfig的Configmap 2, 在CreateKubeConfig生成kubeconfig用户信息,创建CertificateSigningRequest 3, 在Informer中监听CertificateSigningRequest事件,Approve请求,更新Configmap中用户kubeconfig的证书 代码实现 主入口,创建Kubernetes集群Client,创建Informer,创建controller,在controller的mgr中添加user, kubeconfig自定义资源控制器。 func run(s *options.AIScopeControllerManagerOptions, ctx context.Context) error { kubernetesClient, err := k8s.NewKubernetesClient(s.KubernetesOptions) if err != nil { klog.Errorf("Failed to create kubernetes clientset %v", err) return err } informerFactory := informers.NewInformerFactories( kubernetesClient.Kubernetes()) mgrOptions := manager.Options{ Port: 8443, } if s.LeaderElect { mgrOptions = manager.Options{ Port: 8443, LeaderElection: s.LeaderElect, LeaderElectionNamespace: "aiscope-system", LeaderElectionID: "aiscope-controller-manager-leader-election", LeaseDuration: &s.

继续阅读

Kubernetes部署存储Rook Ceph

Rook 是一个可以提供 Ceph 集群管理能力的 Operator。Rook 使用 CRD 一个控制器来对 Ceph 之类的资源进行部署和管理。Rook Ceph要求存储设备为块设备,支持分区或者整块硬盘。 | 磁盘分区 sukai@ceph-01:~$ sudo pvcreate /dev/sda WARNING: ext4 signature detected on /dev/sda at offset 1080. Wipe it? [y/n]: y Wiping ext4 signature on /dev/sda. Physical volume "/dev/sda" successfully created. sukai@ceph-01:~$ sudo vgcreate data /dev/sda Volume group "data" successfully created sukai@ceph-01:~$ sudo pvs PV VG Fmt Attr PSize PFree /dev/sda data lvm2 a-- <9.10t <9.10t sukai@ceph-01:~$ sudo vgs VG #PV #LV #SN Attr VSize VFree data 1 0 0 wz--n- <9.

继续阅读