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 的實現

相關文章
相關標籤/搜索