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

3.3.3 创建engine对象

在mainDaemon()运行过程中,flag参数检查完毕之后,Docker随即创建engine对象,代码如下:

eng := engine.New()

Engine是Docker架构中的运行引擎,同时也是Docker运行的核心模块。Engine扮演着Docker Container存储仓库的角色,并且通过Job的形式管理Docker运行中涉及的所有任务。

Engine结构体的定义位于./docker/docker/engine/engine.go#L47-L60,具体代码如下:

type Engine struct {
     handlers   map[string]Handler
     catchall   Handler
     hack       Hack // data for temporary hackery (see hack.go)
     id         string
     Stdout     io.Writer
     Stderr     io.Writer
     Stdin      io.Reader
     Logging    bool
     tasks      sync.WaitGroup
     l          sync.RWMutex // lock for shutdown
     shutdown   bool
     onShutdown []func() // shutdown handlers
}

Engine结构体中最为重要的是handlers属性,handlers属性为map类型,key的类型是string,value的类型是Handler。其中Handler类型的定义位于./docker/docker/engine/engine.go#L23,具体代码如下:

type Handler func(*Job) Status

可见,Handler为一个定义的函数。该函数传入的参数为Job指针,返回为Status状态。

了解完Engine以及Handler的基本知识之后,我们真正进入创建Engine实例的部分,即New()函数的实现,具体代码如下:

func New() *Engine {
     eng := &Engine{
          handlers: make(map[string]Handler),
          id:       utils.RandomString(),
          Stdout:   os.Stdout,
          Stderr:   os.Stderr,
          Stdin:    os.Stdin,
          Logging:  true,
     }
     eng.Register("commands", func(job *Job) Status {
          for _, name := range eng.commands() {
               job.Printf("%s\n", name)
          }
          return StatusOK
     })
     // Copy existing global handlers
     for k, v := range globalHandlers {
          eng.handlers[k] = v
     }
     return eng
}

分析以上代码,从返回结果可以发现,New()函数最终返回一个Engine实例对象。而在代码实现部分,大致可以将其分为三个步骤:

1)创建一个Engine结构体实例eng,并初始化部分属性,如handlers、id、标准输出stdout、日志属性Logging等。

2)向eng对象注册名为commands的Handler,其中Handler为临时定义的函数func(job*Job)Status{},该函数的作用是通过Job来打印所有已经注册完毕的command名称,最终返回状态StatusOK。

3)将变量globalHandlers中定义完毕的所有Handler都复制到eng对象的handlers属性中。

至此,一个基本的Engine对象实例eng已经创建完毕,并实现部分属性的初始化。Docker Daemon启动的后续过程中,仍然会对Engine对象实例进行额外的配置。