cloudnativeto / sig-kubernetes

云原生社区 Kubernetes SIG
https://i.cloudnative.to/kubernetes/
553 stars 88 forks source link

[提问]APIAggregator, APIServer 和APIExtension 是怎么通过APIServerHandler串联起来的? #7

Open luffyao opened 4 years ago

luffyao commented 4 years ago

大家都知道APIService是有三部分组成的,APIAggregator, APIServer 和APIExtension。 它们是通过一个delegateChain串联起来了。但是具体怎么实现的呢。并没有很多文章说的很详细。包括源码剖析中。由于这部分涉及的代码块比较多,来回切换看,不太容易记得。所以导致不太好理解。

经过在微信群里面请教,基本上算是里明白啦,在这里记录一下,可以方便有同困惑的同学们可以参考,以共同学习进步!

我有下面两个困惑:

  1. 这个APIServerHandler结构,为啥这里Director里面已经包含了GoRestfulContainer 和NonGoRestfulMux 为啥还要在APIServerHandler中暴露出来?下面是这部分相关的源码:
// 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
}

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()

    director := director{
        name:               name,
        goRestfulContainer: gorestfulContainer,
        nonGoRestfulMux:    nonGoRestfulMux,
    }

    return &APIServerHandler{
        FullHandlerChain:   handlerChainBuilder(director),
        GoRestfulContainer: gorestfulContainer,
        NonGoRestfulMux:    nonGoRestfulMux,
        Director:           director,
    }
}

type director struct {
    name               string
    goRestfulContainer *restful.Container
    nonGoRestfulMux    *mux.PathRecorderMux
}

对于FullHandlerChain和Director比较好理解,FullHandlerChain就是将director进行了一层filterHandler的封装。而Director更直接,从代码中看到,它就是根据不同的name存储了对应的goRestful的API指针和nonGoRestful的API的指针,为了后面可以使用。 而这里的APIServerHandler中的GoRestfulContainer和NonGoRestfulMux,我是不太明白为啥要暴露出来。不过从注释上来看,它只是在installAPI的时候要把API都添加进去。然后Director由于存的是他们的指针,所以Director中对应的API也都有了,因此后面再APIChain的调用中,调用Director就能处理到这些API了。所以我的理解可能是不想直接操作Director这个结构吧。毕竟它是一个interface 指向了director 这个结构。

  1. APIAggregator, APIServer 和APIExtension 是怎么通过这个APIServerHandler 串联起来了呢?

通过源码的分析,总结出下面这个调用流图可供参考:

apiserverhandler

这里就是当你调用一个API的时候,就会按照这个处理流程去处理。首先就是filterHandler,这个是一些筛选handler,包括认证授权等。后面就是三种server的调用链了。

最后,如果你有同样的问题,希望可以帮到你!

如果大牛们对我的分析和理解有误。还请指出!