k8s :kube-apiserver 启动流程 - 2

前端之家收集整理的这篇文章主要介绍了k8s :kube-apiserver 启动流程 - 2前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

前言

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

回顾

上回讲到 Run 方法

  1. // kubernetes/cmd/kube-apiserver/app.server.go
  2. func Run(runOptions *options.ServerRunOptions,stopCh <-chan struct{}) error {
  3. ...
  4. server,err := CreateServerChain(runOptions,stopCh)
  5. if err != nil {
  6. return err
  7. }
  8. return server.PrepareRun().Run(stopCh)
  9. }

目前系统中有以下 api server:

  • 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 创建为例:

  1. func CreateServerChain(
  2. runOptions *options.ServerRunOptions,stopCh <-chan struct{})
  3. (*genericapiserver.GenericAPIServer,error) {
  4. ...
  5. kubeAPIServerConfig,... := CreateKubeAPIServerConfig(...)
  6. ...
  7. kubeAPIServer,err := CreateKubeAPIServer(kubeAPIServerConfig,apiExtensionsServer.GenericAPIServer,sharedInformers,versionedInformers)
  8. ...
  9. }

下面将简要介绍 Master api server 的创建过程,主要分析 kube-apiserver 是如何将 资源对象(Node,Pod,Service 等)绑定到具体的 RESTful API,使得客户端可以通过 RESTful API 操作资源对象

如果是你会怎么做?

在大概看了一些源代码之后,我不禁问自己:如果是你来设计代码架构,你会怎么做?
例如给定一个实体 Student(Java 伪代码,下同),持久化在 etcd 里

  1. public class Student {
  2.  
  3. public int id;
  4.  
  5. public String name;
  6.  
  7. public String phone;
  8. }

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

api 接口示例:

  1. PUT /user?id=xxx&name=yyy&phone=zzz
  2. DELETE /user?id=xxx
  3. POST /user?id=xxx&name=yyy
  4. GET /user?id=xxx

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

  1. public interface Backend {
  2.  
  3. String get(String key);
  4.  
  5. void set(String key,String value);
  6. }

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

  1. public class EtcdBackend implements Backend {
  2.  
  3. public String get(String key) { ... }
  4.  
  5. public void set(String key,String value) { ... }
  6. }
  7.  
  8. public class ConsulBackend implements Backend {
  9.  
  10. public String get(String key) { ... }
  11.  
  12. public void set(String key,String value) { ... }
  13. }
  14.  
  15. public class BackendFactory {
  16.  
  17. Backend get(String name) { ... }
  18. }

Backend 搞定了,现在我们需要一个 DAO(Data access object)来访问它

  1. public class UserDao {
  2.  
  3. private Backend backend;
  4.  
  5. // CRUD 方法
  6. ...
  7. }

我们注意到会有很多实体,他们都需要使用 Backend 接口访问后端存储,所以可以搞个基类 AbstractDao,将 backedn 字段移到基类里头

  1. pubic class AbstractDao {
  2.  
  3. private Backend backend;
  4. }
  5.  
  6. public class User extends AbstractDao {
  7.  
  8. // CRUD 方法
  9. ...
  10. }

进一步观察,其实各个 DAO 的 CRUD 方法也有很多重复的(模版)代码,比如如果我们能够封装以下变化点:

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

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

  1. public class AbstractDao {
  2.  
  3. private Backend backend;
  4.  
  5. // CRUD 方法
  6. ...
  7. }
  8.  
  9. public class UserDao extends AbstractDao {
  10.  
  11. // Template 方法
  12. ...
  13. }

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

  1. map.put("/user",userDao)

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

猜你在找的Go相关文章