Docker源码分析
上QQ阅读APP看书,第一时间看更新

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对象注册特定的处理方法。