kubernetes api-server 路由解析
1. 简介
apiserver使用go-restful来构建REST-style Web服务,所以我们先来了解一下这个包的相关内容,以便更好地理解apiserver的源码。
3. 创建http server步骤
- 创建Container。
- 创建自定义的Resource Handle,实现Resource相关的处理方法。
- 创建对应于Resource的WebService,在WebService中添加相应Route,并将WebService加入到Container中。
- 启动监听服务。
// 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 }
没有什么是写一万遍还不会的,如果有那就再写一万遍。