首先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中。