docker 源碼分析daemon2

run函數流程很簡單linux

func runDaemon(opts daemonOptions) error {
    if opts.version {   // 若是是查詢版本,直接顯示版本信息
        showVersion()
        return nil
    }
    daemonCli := NewDaemonCli()  //  daemon.go  新建一個daemoncli
    .... // windows 的特殊處理
    err = daemonCli.start(opts)   // daemon.go  關鍵語句,開始運行daemon
    notifyShutdown(err)  // 進程退出前的處理,只是windows系統在使用
    return err
}docker

看下start的處理明顯複雜不少json

func (cli *DaemonCli) start(opts daemonOptions) (err error) {
    stopc := make(chan bool)  // 建立一個通道,看上去退出時候阻塞用的
    defer close(stopc)  // 函數結束時候關閉通道

    // warn from uuid package when running the daemon
    uuid.Loggerf = logrus.Warnf

    opts.common.SetDefaultOptions(opts.flags)  // 同client,設置默認參數

    if cli.Config, err = loadDaemonCliConfig(opts); err != nil {  // 從opt裏面將參數導入到config
        return err
    }
    cli.configFile = &opts.configFile  //  "/etc/docker/daemon.json"
    cli.flags = opts.flags
    ....  //config 的一些處理
    // Create the daemon root before we create ANY other files (PID, or migrate keys)
    // to ensure the appropriate ACL is set (particularly relevant on Windows)
    if err := daemon.CreateDaemonRoot(cli.Config); err != nil {   //  daemon/daemon.go  先建立daemon 的root路徑,linux 爲 /var/lib/docker
        return err
    }

    if cli.Pidfile != "" {    //  "/var/run/docker.pid "  非空則建立一個pidfile
        pf, err := pidfile.New(cli.Pidfile)
        if err != nil {
            return fmt.Errorf("Error starting daemon: %v", err)
        }
        defer func() {  //start函數結束的時候清除文件
            if err := pf.Remove(); err != nil {
                logrus.Error(err)
            }
        }()
    }

    serverConfig := &apiserver.Config{    ///  server 的config文件建立以及一些賦值
        Logging:     true,
        SocketGroup: cli.Config.SocketGroup,
        Version:     dockerversion.Version,
        EnableCors:  cli.Config.EnableCors,
        CorsHeaders: cli.Config.CorsHeaders,
    }
    .....

    api := apiserver.New(serverConfig)    // api/server/server.go 新建一個server的實例
    cli.api = apiwindows

    if len(cli.Config.Hosts) == 0 {
        cli.Config.Hosts = make([]string, 1)
    }api

    for i := 0; i < len(cli.Config.Hosts); i++ {  // 循環根據配置文件裏面全部host增長server的監聽
        .......
        api.Accept(addr, ls...)
    }

    if err := migrateKey(cli.Config); err != nil {   // 把 key.json 移動到 /etc/docker 路徑
        return err
    }
......

    registryService := registry.NewService(cli.Config.ServiceOptions)   // registry/service.go 新建一個default的registryserver
    containerdRemote, err := libcontainerd.New(cli.getLibcontainerdRoot(), cli.getPlatformRemoteOptions()...)   // libcontainerd/remote_unix.goapp

   //  /var/run/docker路徑 ,建立 containerd Remote,container相關處理啓動grpc的client api,事件監控等less

....
    signal.Trap(func() {   // start時收到異常信息量的處理,關閉cli,其餘地方處理結束纔會給通道一個消息結束
        cli.stop()
        <-stopc // wait for daemonCli.start() to return
    })

    // Notify that the API is active, but before daemon is set up.
    preNotifySystem()   // 只是window系統有用

    d, err := daemon.NewDaemon(cli.Config, registryService, containerdRemote)   // daemon/daemon.go  新建daemon的全部東西,比較複雜,待後續分析
  .....

    if cli.Config.MetricsAddress != "" {  //  metrics 地址存在的話,起一個metrics server 監聽
        if !d.HasExperimental() {
            return fmt.Errorf("metrics-addr is only supported when experimental is enabled")
        }
        if err := startMetricsServer(cli.Config.MetricsAddress); err != nil {
            return err
        }
    }

    name, _ := os.Hostname()

    c, err := cluster.New(cluster.Config{    // daemon/cluster/cluster.go  新建一個cluster 實例
        Root:                   cli.Config.Root,
        Name:                   name,
        Backend:                d,
        NetworkSubnetsProvider: d,
        DefaultAdvertiseAddr:   cli.Config.SwarmDefaultAdvertiseAddr,
        RuntimeRoot:            cli.getSwarmRunRoot(),
    })
......

    // Restart all autostart containers which has a swarm endpoint
    // and is not yet running now that we have successfully
    // initialized the cluster.
    d.RestartSwarmContainers()   // daemon/daemon.go   重啓 container ,條件見函數內
......
    cli.d = d

    // initMiddlewares needs cli.d to be populated. Dont change this init order.
    if err := cli.initMiddlewares(api, serverConfig); err != nil {   //  給apiserver初始化中間件,要求cli.d必須被賦值
        logrus.Fatalf("Error creating middlewares: %v", err)
    }
    d.SetCluster(c)   //   d.cluster = c
    initRouter(api, d, c)   // 註冊api消息處理函數,daemon命令的處理能夠在這裏面查

    cli.setupConfigReloadTrap()    //  設置一個系統調用從新加載配置

    // The serve API routine never exits unless an error occurs
    // We need to start it as a goroutine and wait on it so
    // daemon doesn't exit
    serveAPIWait := make(chan error)  //  等待錯誤的通道
    go api.Wait(serveAPIWait)  //  起server的協程,出現錯誤向serveAPIWait通道寫入信息

    // after the daemon is done setting up we can notify systemd api
    notifySystem()    // 通知系統daemon 已經起來

    // Daemon is fully initialized and handling API traffic
    // Wait for serve API to complete
    errAPI := <-serveAPIWait  // 利用通道阻塞等待 server退出
    c.Cleanup()   // 關閉cluster
    shutdownDaemon(d)   // 關閉daemon
    containerdRemote.Cleanup()  // 關閉 container
......

    return nil
}ide

相關文章
相關標籤/搜索