zoukankan      html  css  js  c++  java
  • kubernetes api-server 路由解析

     1. 简介

        apiserver使用go-restful来构建REST-style Web服务,所以我们先来了解一下这个包的相关内容,以便更好地理解apiserver的源码。

     3. 创建http server步骤

    1. 创建Container。
    2. 创建自定义的Resource Handle,实现Resource相关的处理方法。
    3. 创建对应于Resource的WebService,在WebService中添加相应Route,并将WebService加入到Container中。
    4. 启动监听服务。

      

    // APIServerHandlers holds the different http.Handlers used by the API server.
    // This includes the full handler chain, the director (which chooses between gorestful and nonGoRestful,
    // the gorestful handler (used for the API) which falls through to the nonGoRestful handler on unregistered paths,
    // and the nonGoRestful handler (which can contain a fallthrough of its own)
    // FullHandlerChain -> Director -> {GoRestfulContainer,NonGoRestfulMux} based on inspection of registered web services
    type APIServerHandler struct {
    	// FullHandlerChain is the one that is eventually served with.  It should include the full filter
    	// chain and then call the Director.
    	FullHandlerChain http.Handler
    	// The registered APIs.  InstallAPIs uses this.  Other servers probably shouldn't access this directly.
    	GoRestfulContainer *restful.Container
    	// NonGoRestfulMux is the final HTTP handler in the chain.
    	// It comes after all filters and the API handling
    	// This is where other servers can attach handler to various parts of the chain.
    	NonGoRestfulMux *mux.PathRecorderMux
    
    	// Director is here so that we can properly handle fall through and proxy cases.
    	// This looks a bit bonkers, but here's what's happening.  We need to have /apis handling registered in gorestful in order to have
    	// swagger generated for compatibility.  Doing that with `/apis` as a webservice, means that it forcibly 404s (no defaulting allowed)
    	// all requests which are not /apis or /apis/.  We need those calls to fall through behind goresful for proper delegation.  Trying to
    	// register for a pattern which includes everything behind it doesn't work because gorestful negotiates for verbs and content encoding
    	// and all those things go crazy when gorestful really just needs to pass through.  In addition, openapi enforces unique verb constraints
    	// which we don't fit into and it still muddies up swagger.  Trying to switch the webservices into a route doesn't work because the
    	//  containing webservice faces all the same problems listed above.
    	// This leads to the crazy thing done here.  Our mux does what we need, so we'll place it in front of gorestful.  It will introspect to
    	// decide if the route is likely to be handled by goresful and route there if needed.  Otherwise, it goes to PostGoRestful mux in
    	// order to handle "normal" paths and delegation. Hopefully no API consumers will ever have to deal with this level of detail.  I think
    	// we should consider completely removing gorestful.
    	// Other servers should only use this opaquely to delegate to an API server.
    	Director http.Handler
    }
    

      

      3.1 创建 container

      master.Config --> Complete() --->CompletedConfig ---> New()-->InstallAPIs --->InstallLegacyAPIGroup -> installAPIResource --> apiGroupVersion.InstallREST 

       container 容器为 : s.Handler.GoRestfulContainer

      3.2 创建handler

      s, err := c.GenericConfig.New("kube-apiserver", delegationTarget)
      
    // New creates a new server which logically combines the handling chain with the passed server.
    // name is used to differentiate for logging. The handler chain in particular can be difficult as it starts delgating.
    // delegationTarget may not be nil.
    func (c completedConfig) New(name string, delegationTarget DelegationTarget) (*GenericAPIServer, error) {
      handlerChainBuilder := func(handler http.Handler) http.Handler {
       return c.BuildHandlerChainFunc(handler, c.Config)
      }
      apiServerHandler := NewAPIServerHandler(name, c.Serializer, handlerChainBuilder, delegationTarget.UnprotectedHandler())

     

      handlerChaninBuilderFn 用于包装gorestfulcontainer的处理器,提供处理链 

    // HandlerChainBuilderFn is used to wrap the GoRestfulContainer handler using the provided handler chain.
    // It is normally used to apply filtering like authentication and authorization
    type HandlerChainBuilderFn func(apiHandler http.Handler) http.Handler

      
    func NewAPIServerHandler(name string, s runtime.NegotiatedSerializer, handlerChainBuilder HandlerChainBuilderFn, notFoundHandler http.Handler) *APIServerHandler {
    	nonGoRestfulMux := mux.NewPathRecorderMux(name)
    	if notFoundHandler != nil {
    		nonGoRestfulMux.NotFoundHandler(notFoundHandler)
    	}
    
    	gorestfulContainer := restful.NewContainer()
    // ServeMux还负责清理URL请求路径,/重定向包含的任何请求。或者.。元素或重复的斜杠/作为等效的、更干净的URL。 gorestfulContainer.ServeMux = http.NewServeMux()
         // 添加请求路径 gorestfulContainer.Router(restful.CurlyRouter{}) // e.g. for proxy/{kind}/{name}/{*} gorestfulContainer.RecoverHandler(func(panicReason interface{}, httpWriter http.ResponseWriter) { logStackOnRecover(s, panicReason, httpWriter) }) gorestfulContainer.ServiceErrorHandler(func(serviceErr restful.ServiceError, request *restful.Request, response *restful.Response) { serviceErrorHandler(s, serviceErr, request, response) }) director := director{ name: name, goRestfulContainer: gorestfulContainer, nonGoRestfulMux: nonGoRestfulMux, } return &APIServerHandler{ FullHandlerChain: handlerChainBuilder(director), GoRestfulContainer: gorestfulContainer, NonGoRestfulMux: nonGoRestfulMux, Director: director, } }

      https://blog.csdn.net/Daniel_greenspan/article/details/78624725

      3.3 WebService加入到Container中

        apiResources, ws, registrationErrors := installer.Install()
      
    // InstallREST registers the REST handlers (storage, watch, proxy and redirect) into a restful Container.
    // It is expected that the provided path root prefix will serve all operations. Root MUST NOT end
    // in a slash.
    func (g *APIGroupVersion) InstallREST(container *restful.Container) error {
    	prefix := path.Join(g.Root, g.GroupVersion.Group, g.GroupVersion.Version)
    	installer := &APIInstaller{
    		group:                        g,
    		prefix:                       prefix,
    		minRequestTimeout:            g.MinRequestTimeout,
    		enableAPIResponseCompression: g.EnableAPIResponseCompression,
    	}
    
    	apiResources, ws, registrationErrors := installer.Install()
    	versionDiscoveryHandler := discovery.NewAPIVersionHandler(g.Serializer, g.GroupVersion, staticLister{apiResources})
    	versionDiscoveryHandler.AddToWebService(ws)
    	container.Add(ws)
    	return utilerrors.NewAggregate(registrationErrors)
    }
    

      

    // Install handlers for API resources.
    func (a *APIInstaller) Install() ([]metav1.APIResource, *restful.WebService, []error) {
    	var apiResources []metav1.APIResource
    	var errors []error
    	ws := a.newWebService()
    
    	// Register the paths in a deterministic (sorted) order to get a deterministic swagger spec.
    	paths := make([]string, len(a.group.Storage))
    	var i int = 0
    	for path := range a.group.Storage {
    		paths[i] = path
    		i++
    	}
    	sort.Strings(paths)
    	for _, path := range paths {
    		apiResource, err := a.registerResourceHandlers(path, a.group.Storage[path], ws)
    		if err != nil {
    			errors = append(errors, fmt.Errorf("error in registering resource: %s, %v", path, err))
    		}
    		if apiResource != nil {
    			apiResources = append(apiResources, *apiResource)
    		}
    	}
    	return apiResources, ws, errors
    }
    

      

     创建webservice

    // newWebService creates a new restful webservice with the api installer's prefix and version.
    func (a *APIInstaller) newWebService() *restful.WebService {
    	ws := new(restful.WebService)
    	ws.Path(a.prefix)
    	// a.prefix contains "prefix/group/version"
    	ws.Doc("API at " + a.prefix)
    	// Backwards compatibility, we accepted objects with empty content-type at V1.
    	// If we stop using go-restful, we can default empty content-type to application/json on an
    	// endpoint by endpoint basis
    	ws.Consumes("*/*")
    	mediaTypes, streamMediaTypes := negotiation.MediaTypesForSerializer(a.group.Serializer)
    	ws.Produces(append(mediaTypes, streamMediaTypes...)...)
    	ws.ApiVersion(a.group.GroupVersion.String())
    
    	return ws
    }
    

      

    没有什么是写一万遍还不会的,如果有那就再写一万遍。
  • 相关阅读:
    统计nginx日志里访问次数最多的前十个IP
    while 格式化输出 运算符 字符编码
    Python 软件安装
    Python 基础
    Typora 基础的使用方法
    Django ORM (四) annotate,F,Q 查询
    Django 惰性机制
    Django ORM (三) 查询,删除,更新操作
    Django ORM (二) 增加操作
    Django ORM (一) 创建数据库和模型常用的字段类型参数及Field 重要参数介绍
  • 原文地址:https://www.cnblogs.com/waken-captain/p/10527009.html
Copyright © 2011-2022 走看看