docker1.9源码分析(五):server分配handler提供服务的流程

首先docker/docker/daemon.go中的代码

serverConfig := &apiserver.Config{
   Logging: true,
   Version: dockerversion.VERSION,
}
serverConfig = setPlatformServerConfig(serverConfig, cli.Config)

if commonFlags.TLSOptions != nil {
   if !commonFlags.TLSOptions.InsecureSkipVerify {
      // server requires and verifies client's certificate
      commonFlags.TLSOptions.ClientAuth = tls.RequireAndVerifyClientCert  }
   tlsConfig, err := tlsconfig.Server(*commonFlags.TLSOptions)
   if err != nil {
      logrus.Fatal(err)
   }
   serverConfig.TLSConfig = tlsConfig
}
该段代码是运行server之前的参数配置和初始化,主要是位于docker/api/server/server.go中的Server结构和Config结构,Server结构代表了一个server的实例,其中包含了server的配置即Config结构,同时包含了提供连接和监听服务的数组[]*HTTPServer和提供路由的router.Router。接下来会调用apiserver.New(serviceConfig)函数,该函数根据serviceConfig配置返回一个Server结构,该结构中已经含有要提供服务的HTTPServer。再向下就到了

go func() {
   if err := api.ServeAPI(); err != nil {
      logrus.Errorf("ServeAPI error: %v", err)
      serveAPIWait <- err
      return  }
   serveAPIWait <- nil
}()
ServeAPI()的实现位于api/server/server.go中,实现的功能是检查Server结构中的servers变量中保存的所有HTTPServer地址,并对每个地址都创建一个goroutine,在这个goroutine内启动一个服务于HTTP请求的server端,创建服务的语句如下

go func(srv *HTTPServer) {
   var err error
   logrus.Infof("API listen on %s", srv.l.Addr())
   if err = srv.Serve(); err != nil && strings.Contains(err.Error(), "use of closed network connection") {
      err = nil
   }
   chErrors <- err
}(srv)
其中最重要的是srv.Serve(),该函数在HTTPServer的net.Listener上监听并接受连接,为每个连接新建一个协程提供服务,为每个协程调用一个srv.Handler来回复,实现该功能的语句是go c.serve(),该函数已经是Go语言包实现的功能了,再次没必要细究。

上述Server端启动后,daemon还会做一些诸如registry等服务的初始后,之后执行的代码为api.InitRouters(d),d为Daemon结构,提供了Docker daemon的信息。InitRouters的具体实现在docker/api/server/server.go中,它为每个server初始化一个router,并将该router注册为Handler


func (s *Server) InitRouters(d *daemon.Daemon) {
   s.addRouter(local.NewRouter(d))
   s.addRouter(network.NewRouter(d))
   for _, srv := range s.servers {
      srv.srv.Handler = s.CreateMux()
   }
}
addRouter为docker源码的Server结构[]*HTTPServer添加route信息,CreateMux()为GO语言包的句柄srv.srv.Handler创建服务,CreateMux()函数如下:

func (s *Server) CreateMux() *mux.Router {
   m := mux.NewRouter()
   if os.Getenv("DEBUG") != "" {
      profilerSetup(m, "/debug/")
   }

   logrus.Debugf("Registering routers")
   for _, apiRouter := range s.routers {
      for _, r := range apiRouter.Routes() {
         f := s.makeHTTPHandler(r.Handler())

         logrus.Debugf("Registering %s, %s", r.Method(), r.Path())
         m.Path(versionMatcher + r.Path()).Methods(r.Method()).Handler(f)
         m.Path(r.Path()).Methods(r.Method()).Handler(f)
      }
   }

   return m
}
NewRouter()函数返回一个全新的router实例m。 在创建Router实例时,给Router对象的两个属性进行赋值,这两个属性为nameRoutes和KeepContext。其中namedRoutes属性为一个map类型,其中key为string类型,value为Route路由记录类型;另外,KeepContext属性为false,表示Docker Server在处理完请求之后,就清除请求的内容,不对请求做存储操作。mux.Router会通过一系列已经注册过的路由记录,来为接受的请求做匹配,首先通过请求的URL或者其他条件,找到相应的路由记录,并调用这条路由记录中的执行Handler。

上代码,在第一层循环中,按HTTP请求方法划分,获得请求方法各自的路由记录比如是Post,第二层循环,按匹配请求的URL进行划分,获得与URL相对应的执行Handler,比如url为ImageLoad。在嵌套循环中,通过makeHttpHandler返回一个执行的函数f,函数名即为PostImageLoad。具体实现在api/server/router/local/image.go中。


你可能感兴趣的:(docker1.9源码分析(五):server分配handler提供服务的流程)