开源代码:KubeSphere 核心架构解析

一、核心组件

  • ks-console 前端服务组件
  • ks-apiserver后端服务组件
  • ks-controller-manager资源状态维护组件
在这里插入图片描述

Kubesphere的后端设计中沿用了K8s声明式API的风格,所有可操作的资源都尽可能的抽象成为<code>CustomResource</code>与命令式API的使用更加简洁,并且提供了更好的抽象性,告诉程序最终的期望状态(做什么),而不关心怎么做。

典型的,在声明式API中:

  1. 你得API包含相对而言为数不多的,尺寸较小的对象(资源)。
  2. 对象定义了应用或者基础设施的配置信息。
  3. 对象更新操作频率较低。
  4. 通常需要人来读取或者写入对象。
  5. 对象的主要操作是CRUD风格的(创建、读取、更新和删除)。
  6. 不需要跨对象的事务支持:API对象代表的是期望状态而非确切实际状态。

命令式API与声明式有所不同,以下的特征表明你得API不是声明式的:

  1. 客户端发出“做这个操作”的指令,之后在该操作结束时获得同步响应。
  2. 客户端发出“做这个操作”的指令,并获得一个操作ID,之后需要判断请求是否成功完成。
  3. 你会将你得API类比为RPC。
  4. 直接存储大量数据。
  5. 在对象上执行的常规操作并非CRUD风格。
  6. API不太容易用对象来建模。

借助kube-apiserver、为题材的进行数据同步和数据持久化,通过ks-controller-manager维护这些资源的状态。以达到最终状态的一致性。

例如Kubesphere中的流水线、用户凭证、用户实体、告警通知的配置,都可以抽象为资源实体,借助K8s成熟的架构与工具链,可以方便的与K8s进行结合,降低各组件之间的耦合,降低系统的复杂度。

二、ks-apiserver 的核心架构

ks-apiserver是kubesphere核心的后端组件,负责后端数据的交互,请求的代理分发、认证与鉴权。下图是ks-apiserver的核心架构:

在这里插入图片描述

ks-apiserver的开发使用了<code>go-restful</code>框架,可以在请求链路中增加多个Filter用于动态的拦截请求和响应,实现认证、鉴权、审计逻辑转发和反向代理功能,Kubesphere的API风格也尽可能的学习<code>K8s的模式</code>,方便使用<code>RBAC</code>进行权限控制。

借助CRD +controller的方式进行解耦,可以极大的简化与第三方工具、软件的集成方式。
k8s摄取也提供了丰富的工具链,借助<code>controller-runtime和kubebuiler</code>可以迅速的搭建起开发脚手架

API 聚合与权限控制

可以通过拓展ks-apiserver实现API的聚合,进一步实现功能拓展,聚合查询等功能。在API的开发过程中需要遵循以下规范,以便于Kubesphere的租户体系、资源体系进行整合。

API聚合、权限控制、CRD+controller

API规范

# 通过 api group 进行分组
/apis/{api-group}/{version}/{resources}
# 示例
/apis/apps/v1/deployments
/kapis/iam.kubesphere.io/v1alpha2/users
# api core
/api/v1/namespaces


# 通过 path 区分不同的动作
/api/{version}/watch/{resources}
/api/{version}/proxy/{resources}/{resource}

# 通过 path 区分不同的资源层级
/kapis/{api-group}/{version}/workspaces/{workspace}/{resources}/{resource}
/api/{version}/namespaces/{namespace}/{resource}

规范API的目的:

  1. 更好的对资源进行抽象,抽象为Object更适合声明式API
  2. 更好的对API进行管理,版本、分组、分层、更方便API的拓展
  3. 更好的与权限控制进行整合,可以方便的从请求中获取元数据,apigroup,scope,version,verb

权限控制

Kubesphere权限控制的核心是<code>RBAC</code>基于角色的访问控制
关键的对象有:Role、User、Rolebinding
Role定义了一个角色可以访问的资源

<font color = #999AAA>角色是根据资源层进行划分的,clusterrole、workspacerole、namespaceRole 不同层级的角色定义了该角色在当前层级可以访问的资源</font>

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: role-grantor
rules:
- apiGroups: ["rbac.authorization.k8s.io"]
  resources: ["rolebindings"]
  verbs: ["create"]
- apiGroups: ["rbac.authorization.k8s.io"]
  resources: ["clusterroles"]
  verbs: ["bind"]
  # 忽略 resourceNames 意味着允许绑定任何 ClusterRole
  resourceNames: ["admin","edit","view"]
- nonResourceURLs: ["/healthz", "/healthz/*"] # nonResourceURL 中的 '*' 是一个全局通配符
  verbs: ["get", "post"]

Rolebinding 可绑定角色到某个主体上(Subject)上,主体可以是组,用户或者服务账户。

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: role-grantor-binding
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: role-grantor
subjects:
- apiGroup: rbac.authorization.k8s.io
  kind: User
  name: user-1

CRD +controller

自定义资源(Custom Resource)是对Kubernetes API的扩展,可以通过动态注册的方式进行创建,自定义资源可以是不同层级下。用户可以使用kubectl来创建和访问其中的对象,就像操作内置资源一样。

通过CRD对资源进行抽象,在通过 controller 去 watch 资源变化维护资源状态, controller 的核心是 Reconcile, 与他的意思一样,controller 会监听资源的变化,通过被动、定时触发的方式对资源状态进行维护,直至打到声明的状态。


在这里插入图片描述

以 User 资源为例,我们可以定义一下结构的 CRD 对 User 进行抽象:

apiVersion: iam.kubesphere.io/v1alpha2
kind: User
metadata:
  annotations:
    iam.kubesphere.io/last-password-change-time: "2021-05-12T05:50:07Z"
  name: admin
  resourceVersion: "478503717"
  selfLink: /apis/iam.kubesphere.io/v1alpha2/users/admin
  uid: 9e438fcc-f179-4254-b534-e913dfd7a727
spec:
  email: admin@kubesphere.io
  lang: zh
  description: 'description'
  password: $2a$10$w312tzLTvXObnfEYiIrk9u5Nu/reJpwQeI66vrM1XJETWtpjd1/q2
status:
  lastLoginTime: "2021-06-08T06:37:36Z"
  state: Active

对应的API为:

# 创建
POST /apis/iam.kubesphere.io/v1alpha2/users

# 删除
DELETE /apis/iam.kubesphere.io/v1alpha2/users/{username}

# 修改
PUT /apis/iam.kubesphere.io/v1alpha2/users/{username}
PATCH /apis/iam.kubesphere.io/v1alpha2/users/{username}

# 查询
GET /apis/iam.kubesphere.io/v1alpha2/users
GET /apis/iam.kubesphere.io/v1alpha2/users/{username}

ks-apiserver负责将这些数据写入k8s再由k8s informer 同步到各个副本中

ks-controller-manager 通过watch informer 中的数据变化,对资源状态进行维护,以创建用户为例, 通过<font color = #999AAA>POST /apis/iam.kubesphere.io/v1alpha2/users </font>创建用户之后, ks-controller 会对用户资源状态进行同步。

func (c *userController) reconcile(key string) error {
    // Get the user with this name
    user, err := c.userLister.Get(key)

        if err != nil {
            // The user may no longer exist, in which case we stop
            // processing.
            if errors.IsNotFound(err) {
                utilruntime.HandleError(fmt.Errorf("user '%s' in work queue no longer exists", key))
                return nil
            }
            klog.Error(err)
            return err
        }

    if user, err = c.encryptPassword(user); err != nil {
        klog.Error(err)
        return err
    }

    if user, err = c.syncUserStatus(user); err != nil {
        klog.Error(err)
        return err
    }

    // synchronization through kubefed-controller when multi cluster is enabled
    if c.multiClusterEnabled {
        if err = c.multiClusterSync(user); err != nil {
            c.recorder.Event(user, corev1.EventTypeWarning, controller.FailedSynced, fmt.Sprintf(syncFailMessage, err))
            return err
        }
    }

    c.recorder.Event(user, corev1.EventTypeNormal, successSynced, messageResourceSynced)
    return nil
}

通过声明式的API将复杂的逻辑放到controller进行处理,方便解耦。可以很方便的与其他系统,服务进行集成,例如:

/apis/devops.kubesphere.io/v1alpha2/namespaces/{namespace}/pipelines
/apis/devops.kubesphere.io/v1alpha2/namespaces/{namespace}/credentials
/apis/openpitrix.io/v1alpha2/namespaces/{namespace}/applications
/apis/notification.kubesphere.io/v1alpha2/configs

对应的权限控制策略:
定义一个可以增删查改user资源的角色

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: user-manager
rules:
- apiGroups: ["iam.kubesphere.io"]
  resources: ["users"]
  verbs: ["create","delete","patch","update","get","list"]

定义一个可以创建piepeline资源的角色

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: devops-manager
rules:
- apiGroups: ["devops.kubesphere.io"]
  resources: ["pipelines"]
  verbs: ["create","delete","patch","update","get","list"]
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,884评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,347评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,435评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,509评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,611评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,837评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,987评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,730评论 0 267
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,194评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,525评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,664评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,334评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,944评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,764评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,997评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,389评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,554评论 2 349

推荐阅读更多精彩内容