3.3.5 加载builtins
DockerDaemon设置完Trap特定信号的处理方法(即eng.shutdown()函数)之后,Docker Daemon实现了builtins的加载。Docker的builtins可以理解为:Docker Daemon运行过程中,注册的一些任务(Job),这部分任务一般与容器的运行无关,与Docker Daemon的运行时信息有关。加载builtins的源码实现如下:
if err := builtins.Register(eng); err != nil { log.Fatal(err) }
加载builtins完成的具体工作是:向engine注册多个Handler,以便后续在执行相应任务时,运行指定的Handler。这些Handler包括:Docker Daemon宿主机的网络初始化、Web API服务、事件查询、版本查看、Docker Registry的验证与搜索等。源码实现位于./docker/docker/builtins/builtins.go#L16-L30,如下:
func Register(eng *engine.Engine) error { if err := daemon(eng); err != nil { return err } if err := remote(eng); err != nil { return err } if err := events.New().Install(eng); err != nil { return err } if err := eng.Register("version", dockerVersion); err != nil { return err } return registry.NewService().Install(eng) }
下面分析Register函数实现过程中最为主要的5个部分:daemon(eng)、remote(eng)、events.New().Install(eng)、eng.Register("version",dockerVersion)以及registry.NewService().Install(eng)。
1.注册网络初始化处理方法
daemon(eng)的实现过程,主要为eng对象注册了一个键为"init_networkdriver"的处理方法,此处理方法的值为bridge.InitDriver函数,源码如下:
func daemon(eng *engine.Engine) error { return eng.Register("init_networkdriver", bridge.InitDriver) }
需要注意的是,向eng对象注册处理方法,并不代表处理方法的值函数会被立即调用执行,如注册init_networkdrive时bridge.InitDriver并不会直接运行,而是将bridge.InitDriver的函数入口作为init_networkdriver的值,写入eng的handlers属性中。当Docker Daemon接收到名为init_networkdriver的Job的执行请求时,bridge.InitDriver才被Docker Daemon调用执行。
Bridge.InitDriver的具体实现位于./docker/docker/daemon/networkdriver/bridge/driver.go#79-L175,主要作用为:
□ 获取为Docker服务的网络设备地址。
□ 创建指定IP地址的网桥。
□ 配置网络iptables规则。
□ 另外还为eng对象注册了多个Handler,如allocate_interface、release_interface、allocate_port以及link等。
本书将在第6章详细分析Docker Daemon如何初始化宿主机的网络环境。
2.注册API服务处理方法
remote(eng)的实现过程,主要为eng对象注册了两个Handler,分别为serveapi与acceptconnections,源码实现如下:
func remote(eng *engine.Engine) error { if err := eng.Register("serveapi", apiserver.ServeApi); err != nil { return err } return eng.Register("acceptconnections", apiserver.AcceptConnections) }
注册的两个处理方法名称分别为serveapi与acceptconnections,相应的执行方法分别为apiserver.ServeApi与apiserver.AcceptConnections,具体实现位于./docker/docker/api/server/server.go。其中,ServeApi执行时,通过循环多种指定协议,创建出goroutine协调来配置指定的http.Server,最终为不同协议的请求服务;而AcceptConnections的作用主要是:通知宿主机上init守护进程Docker Daemon已经启动完毕,可以让Docker Daemon开始服务API请求。
3.注册events事件处理方法
events.New().Install(eng)的实现过程,为Docker注册了多个event事件,功能是给Docker用户提供API,使得用户可以通过这些API查看Docker内部的events信息,log信息以及subscribers_count信息。具体的源码位于./docker/docker/events/events.go#L29-L42,如下所示:
func (e *Events) Install(eng *engine.Engine) error { jobs := map[string]engine.Handler{ "events": e.Get, "log": e.Log, "subscribers_count": e.SubscribersCount, } for name, job := range jobs { if err := eng.Register(name, job); err != nil { return err } } return nil }
4.注册版本处理方法
eng.Register("version",dockerVersion)的实现过程,向eng对象注册key为version,value为dockerVersion执行方法的Handler。dockerVersion的执行过程中,会向名为version的Job的标准输出中写入Docker的版本、Docker API的版本、git版本、Go语言运行时版本,以及操作系统版本等信息。dockerVersion的源码实现如下:
func dockerVersion(job *engine.Job) engine.Status { v := &engine.Env{} v.SetJson("Version", dockerversion.VERSION) v.SetJson("ApiVersion", api.APIVERSION) v.Set("GitCommit", dockerversion.GITCOMMIT) v.Set("GoVersion", runtime.Version()) v.Set("Os", runtime.GOOS) v.Set("Arch", runtime.GOARCH) if kernelVersion, err := kernel.GetKernelVersion(); err == nil { v.Set("KernelVersion", kernelVersion.String()) } if _, err := v.WriteTo(job.Stdout); err != nil { return job.Error(err) } return engine.StatusOK }
5.注册registry处理方法
registry.NewService().Install(eng)的实现过程位于./docker/docker/registry/service.go,功能是:在eng对象对外暴露的API信息中添加docker registry的信息。若registry.NewService()被成功安装,则会有两个相应的处理方法注册至eng,Docker Daemon通过Docker Client提供的认证信息向registry发起认证请求;search,在公有registry上搜索指定的镜像,目前公有的registry只支持Docker Hub。
Install的具体实现如下:
func (s *Service) Install(eng *engine.Engine) error { eng.Register("auth", s.Auth) eng.Register("search", s.Search) return nil }
至此,Docker Daemon所有builtins的加载全部完成,实现了向eng对象注册特定的处理方法。