• docker 源码分析daemon2


    run函数流程很简单

    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
    }

    看下start的处理明显复杂很多

    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 = api

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

        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.go

       //  /var/run/docker路径 ,创建 containerd Remote,container相关处理启动grpc的client api,事件监控等

    ....
        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
    }

  • 相关阅读:
    弱网测试及app弱网测试点
    adb相关记录
    vmware虚拟机启动centos黑屏
    python中+与+=,=+
    mysql客户端不能插入中文字符
    wampserver3 集成环境 启动Apache失败
    python 局部变量与全局变量
    pyhton 函数参数,递归函数,高阶函数(一点点笔记)
    在CentOS7安装redis服务器
    Servlet生命周期的四个阶段
  • 原文地址:https://www.cnblogs.com/arwen-spy/p/6580553.html
Copyright © 2020-2023  润新知