• 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
    }
    

      

    没有什么是写一万遍还不会的,如果有那就再写一万遍。
  • 相关阅读:
    【刷题】洛谷 P1501 [国家集训队]Tree II
    【刷题】BZOJ 2816 [ZJOI2012]网络
    【刷题】BZOJ 2049 [Sdoi2008]Cave 洞穴勘测
    【刷题】BZOJ 2002 [Hnoi2010]Bounce 弹飞绵羊
    【刷题】洛谷 P3690 【模板】Link Cut Tree (动态树)
    【刷题】BZOJ 2190 [SDOI2008]仪仗队
    【刷题】BZOJ 2005 [Noi2010]能量采集
    【刷题】BZOJ 3262 [HNOI2008]GT考试
    (74)Wangdao.com第十三天_Object 对象_属性描述对象
    (73)Wangdao.com第十二天_JavaScript consol 对象与控制台
  • 原文地址:https://www.cnblogs.com/waken-captain/p/10527009.html
Copyright © 2020-2023  润新知