k8s :kube-apiserver 启动流程 - 2

前言

文章字数一多,在线编辑不方便,本文是 k8s:kube-apiserver 启动流程的第2部分
传送门:k8s :kube-apiserver 启动流程 - 1segmentfault

回顾

上回讲到 Run 方法:后端

// kubernetes/cmd/kube-apiserver/app.server.go
func Run(runOptions *options.ServerRunOptions, stopCh <-chan struct{}) error {
    ...
    server, err := CreateServerChain(runOptions, stopCh)
    if err != nil {
        return err
    }
    return server.PrepareRun().Run(stopCh)
}

目前系统中有如下 api server:api

  • CustomResourceDefinitions
  • Master
  • APIAggregator

每一个 api server 都对应一个 Config(配置)架构

  • apiextensionsapiserver.Config
  • master.Config
  • aggregatorapiserver.Config

CreateServerChain 的任务就是根据 ServerRunOptions 建立 XXXConfig,而后再用 XXXConfig 建立 api server,各个 api server 经过 GenericAPIServer 的 delegationTarget 字段组成《责任链》
以 Master api server 建立为例:app

func CreateServerChain(
    runOptions *options.ServerRunOptions, stopCh <-chan struct{})
        (*genericapiserver.GenericAPIServer, error) {
    ...
    kubeAPIServerConfig, ... := CreateKubeAPIServerConfig(...)
    ...
    kubeAPIServer, err := CreateKubeAPIServer(kubeAPIServerConfig, 
        apiExtensionsServer.GenericAPIServer, sharedInformers, versionedInformers)
    ...
}

下面将简要介绍 Master api server 的建立过程,主要分析 kube-apiserver 是如何将 资源对象(Node,Pod,Service 等)绑定到具体的 RESTful API,使得客户端能够经过 RESTful API 操做资源对象框架

若是是你会怎么作?

在大概看了一些源代码以后,我不由问本身:若是是你来设计代码架构,你会怎么作?
例如给定一个实体 Student(Java 伪代码,下同),持久化在 etcd 里url

public class Student {

    public int id;

    public String name;

    public String phone;
}

如何提供 RESTful api 接口提供对 Student 的 CRUD 操做? 设计代码框架使之适应全部的实体设计

api 接口示例:code

PUT: /user?id=xxx&name=yyy&phone=zzz
DELETE: /user?id=xxx
POST: /user?id=xxx&name=yyy
GET: /user?id=xxx

咱们分几步来考虑,首先考虑持久化,为了支持不一样的持久化框架,或者即时咱们就使用一种持久化框架也须要考虑框架版本匹配问题,这就须要将对持久化框架的基本操做进行抽象,抽取出接口 Backendorm

public interface Backend {

    String get(String key);

    void set(String key, String value);
}

而后咱们有具体的实现类 EtcdBackend, ConsulBackend 以及 工厂类 BackendFactory

public class EtcdBackend implements Backend {

    public String get(String key) { ... }

    public void set(String key, String value) { ... }
}

public class ConsulBackend implements Backend {

    public String get(String key) { ... }

    public void set(String key, String value) { ... }
}

public class BackendFactory {

    Backend get(String name) { ... }
}

Backend 搞定了,如今咱们须要一个 DAO(Data access object)来访问它

public class UserDao {

    private Backend backend;

    // CRUD 方法
    ...
}

咱们注意到会有不少实体,他们都须要使用 Backend 接口访问后端存储,因此能够搞个基类 AbstractDao,将 backedn 字段移到基类里头

pubic class AbstractDao {

    private Backend backend;
}

public class User extends AbstractDao {

    // CRUD 方法
    ...
}

进一步观察,其实各个 DAO 的 CRUD 方法也有不少重复的(模版)代码,好比若是咱们可以封装如下变化点:

  • 生成后端存储须要的key
  • 序列化和反序列化对象

DAO 中的 CRUD 方法能够进一步抽取到 AbstractDao 中,那些实在须要子类特例化的方法,能够经过《模版方法》模式来实现

public class AbstractDao {

    private Backend backend;

    // CRUD 方法
    ...
}

public class UserDao extends AbstractDao {

    // Template 方法
    ...
}

咱们如今离最后的完工又近了一步,还剩一个问题,就是如何将 url 和 DAO 对应起来,这是一个映射问题,可使用 map 来保持 url 对应的 DAO

map.put("/user", userDao)

以上只是一个简单的推导,k8s 的实现远比这个 demo 复杂的多,考虑到各类解耦和扩展性,下回将正式介绍 k8s 的实现

相关文章
相关标签/搜索