github.com/zhouyu0/docker-note@v0.0.0-20190722021225-b8d3825084db/cmd/dockerd/daemon.go (about)

     1  package main
     2  
     3  import (
     4  	"context"
     5  	"crypto/tls"
     6  	"fmt"
     7  	"os"
     8  	"path/filepath"
     9  	"runtime"
    10  	"strings"
    11  	"time"
    12  
    13  	containerddefaults "github.com/containerd/containerd/defaults"
    14  	"github.com/docker/distribution/uuid"
    15  	"github.com/docker/docker/api"
    16  	apiserver "github.com/docker/docker/api/server"
    17  	buildbackend "github.com/docker/docker/api/server/backend/build"
    18  	"github.com/docker/docker/api/server/middleware"
    19  	"github.com/docker/docker/api/server/router"
    20  	"github.com/docker/docker/api/server/router/build"
    21  	checkpointrouter "github.com/docker/docker/api/server/router/checkpoint"
    22  	"github.com/docker/docker/api/server/router/container"
    23  	distributionrouter "github.com/docker/docker/api/server/router/distribution"
    24  	"github.com/docker/docker/api/server/router/image"
    25  	"github.com/docker/docker/api/server/router/network"
    26  	pluginrouter "github.com/docker/docker/api/server/router/plugin"
    27  	sessionrouter "github.com/docker/docker/api/server/router/session"
    28  	swarmrouter "github.com/docker/docker/api/server/router/swarm"
    29  	systemrouter "github.com/docker/docker/api/server/router/system"
    30  	"github.com/docker/docker/api/server/router/volume"
    31  	buildkit "github.com/docker/docker/builder/builder-next"
    32  	"github.com/docker/docker/builder/dockerfile"
    33  	"github.com/docker/docker/builder/fscache"
    34  	"github.com/docker/docker/cli/debug"
    35  	"github.com/docker/docker/daemon"
    36  	"github.com/docker/docker/daemon/cluster"
    37  	"github.com/docker/docker/daemon/config"
    38  	"github.com/docker/docker/daemon/listeners"
    39  	"github.com/docker/docker/dockerversion"
    40  	"github.com/docker/docker/libcontainerd/supervisor"
    41  	dopts "github.com/docker/docker/opts"
    42  	"github.com/docker/docker/pkg/authorization"
    43  	"github.com/docker/docker/pkg/jsonmessage"
    44  	"github.com/docker/docker/pkg/pidfile"
    45  	"github.com/docker/docker/pkg/plugingetter"
    46  	"github.com/docker/docker/pkg/signal"
    47  	"github.com/docker/docker/pkg/system"
    48  	"github.com/docker/docker/plugin"
    49  	"github.com/docker/docker/runconfig"
    50  	"github.com/docker/go-connections/tlsconfig"
    51  	swarmapi "github.com/docker/swarmkit/api"
    52  	"github.com/moby/buildkit/session"
    53  	"github.com/pkg/errors"
    54  	"github.com/sirupsen/logrus"
    55  	"github.com/spf13/pflag"
    56  )
    57  
    58  // DaemonCli represents the daemon CLI.
    59  type DaemonCli struct {
    60  	*config.Config
    61  	configFile *string
    62  	flags      *pflag.FlagSet
    63  
    64  	api             *apiserver.Server
    65  	d               *daemon.Daemon
    66  	authzMiddleware *authorization.Middleware // authzMiddleware enables to dynamically reload the authorization plugins
    67  }
    68  
    69  // NewDaemonCli returns a daemon CLI
    70  func NewDaemonCli() *DaemonCli {
    71  	return &DaemonCli{}
    72  }
    73  
    74  func (cli *DaemonCli) start(opts *daemonOptions) (err error) {
    75  	// 停止信号处理
    76  	stopc := make(chan bool)
    77  
    78  	defer close(stopc)
    79  	// warn from uuid package when running the daemon
    80  	uuid.Loggerf = logrus.Warnf
    81  
    82  	// 设置TLS相关
    83  	opts.SetDefaultOptions(opts.flags)
    84  
    85  	// 1、加载config,主要是合并json config file和flags参数
    86  	if cli.Config, err = loadDaemonCliConfig(opts); err != nil {
    87  		return err
    88  	}
    89  	cli.configFile = &opts.configFile
    90  	cli.flags = opts.flags
    91  
    92  	// 如果设置了debug就将logrus level设置成debug,并且设置环境变量DEBUG=1
    93  	if cli.Config.Debug {
    94  		debug.Enable()
    95  	}
    96  
    97  	// Experimental开关
    98  	if cli.Config.Experimental {
    99  		logrus.Warn("Running experimental build")
   100  	}
   101  
   102  	// logrus format设置
   103  	logrus.SetFormatter(&logrus.TextFormatter{
   104  		TimestampFormat: jsonmessage.RFC3339NanoFixed,
   105  		DisableColors:   cli.Config.RawLogs,
   106  		FullTimestamp:   true,
   107  	})
   108  
   109  	// 只有windows有用
   110  	system.InitLCOW(cli.Config.Experimental)
   111  
   112  	// 2、将系统umask值设置成了0022
   113  	if err := setDefaultUmask(); err != nil {
   114  		return fmt.Errorf("Failed to set umask: %v", err)
   115  	}
   116  
   117  	// 3、data-root的初始化,默认配置是/var/lib/docker
   118  	// Create the daemon root before we create ANY other files (PID, or migrate keys)
   119  	// to ensure the appropriate ACL is set (particularly relevant on Windows)
   120  	if err := daemon.CreateDaemonRoot(cli.Config); err != nil {
   121  		return err
   122  	}
   123  
   124  	// 4、创建exec-data目录,默认就是/var/run/docker目录
   125  	if err := system.MkdirAll(cli.Config.ExecRoot, 0700, ""); err != nil {
   126  		return err
   127  	}
   128  
   129  	// 5、dockerFile默认是/var/run/docker.pid
   130  	if cli.Pidfile != "" {
   131  		// 校验pidfile是否存在,如果不存在就创建,并且写入pid号
   132  		pf, err := pidfile.New(cli.Pidfile)
   133  		if err != nil {
   134  			return fmt.Errorf("Error starting daemon: %v", err)
   135  		}
   136  		// 设置程序运行结束后删除pid file
   137  		defer func() {
   138  			if err := pf.Remove(); err != nil {
   139  				logrus.Error(err)
   140  			}
   141  		}()
   142  	}
   143  
   144  	// 初始化了一个api server config对象
   145  	serverConfig, err := newAPIServerConfig(cli)
   146  	if err != nil {
   147  		return fmt.Errorf("Failed to create API server: %v", err)
   148  	}
   149  	// 6、用config得到一个server对象
   150  	cli.api = apiserver.New(serverConfig)
   151  
   152  	// 将hosts初始化为listeners对象,加入到cli.api.server中
   153  	hosts, err := loadListeners(cli, serverConfig)
   154  	if err != nil {
   155  		return fmt.Errorf("Failed to load listeners: %v", err)
   156  	}
   157  
   158  	ctx, cancel := context.WithCancel(context.Background())
   159  	if cli.Config.ContainerdAddr == "" && runtime.GOOS != "windows" {
   160  		if !systemContainerdRunning() {
   161  			// containerd 获取选项配置
   162  			opts, err := cli.getContainerdDaemonOpts()
   163  			if err != nil {
   164  				cancel()
   165  				return fmt.Errorf("Failed to generate containerd options: %v", err)
   166  			}
   167  
   168  			// 7、启动docker containerd
   169  			r, err := supervisor.Start(ctx, filepath.Join(cli.Config.Root, "containerd"), filepath.Join(cli.Config.ExecRoot, "containerd"), opts...)
   170  			if err != nil {
   171  				cancel()
   172  				return fmt.Errorf("Failed to start containerd: %v", err)
   173  			}
   174  			cli.Config.ContainerdAddr = r.Address()
   175  
   176  			// Try to wait for containerd to shutdown
   177  			defer r.WaitTimeout(10 * time.Second)
   178  		} else {
   179  			cli.Config.ContainerdAddr = containerddefaults.DefaultAddress
   180  		}
   181  	}
   182  	// 设置程序结束关闭containerd
   183  	defer cancel()
   184  
   185  	// 8、设置信号处理
   186  	signal.Trap(func() {
   187  		cli.stop()
   188  		<-stopc // wait for daemonCli.start() to return
   189  	}, logrus.StandardLogger())
   190  
   191  	// Notify that the API is active, but before daemon is set up.
   192  	preNotifySystem()
   193  
   194  	pluginStore := plugin.NewStore()
   195  
   196  	// 使用中间件包装api
   197  	if err := cli.initMiddlewares(cli.api, serverConfig, pluginStore); err != nil {
   198  		logrus.Fatalf("Error creating middlewares: %v", err)
   199  	}
   200  
   201  	// 9、初始化核心结构daemon
   202  	d, err := daemon.NewDaemon(ctx, cli.Config, pluginStore)
   203  	if err != nil {
   204  		return fmt.Errorf("Error starting daemon: %v", err)
   205  	}
   206  
   207  	// 设置hosts地址是在监听的状态
   208  	d.StoreHosts(hosts)
   209  
   210  	// validate after NewDaemon has restored enabled plugins. Don't change order.
   211  	if err := validateAuthzPlugins(cli.Config.AuthorizationPlugins, pluginStore); err != nil {
   212  		return fmt.Errorf("Error validating authorization plugin: %v", err)
   213  	}
   214  
   215  	// 如果配置了metrics监控地址和开启了expermental则开始metrics服务
   216  	// TODO: move into startMetricsServer()
   217  	if cli.Config.MetricsAddress != "" {
   218  		if !d.HasExperimental() {
   219  			return fmt.Errorf("metrics-addr is only supported when experimental is enabled")
   220  		}
   221  		if err := startMetricsServer(cli.Config.MetricsAddress); err != nil {
   222  			return err
   223  		}
   224  	}
   225  
   226  	// 在daemon对象上设置cluster,没有特殊配置的话理论上没有{data-root}/swarm/docker-state.json文件,cluster不能启动
   227  	c, err := createAndStartCluster(cli, d)
   228  	if err != nil {
   229  		logrus.Fatalf("Error starting cluster component: %v", err)
   230  	}
   231  
   232  	// 如果容器列表中有停止的容器,并且设置了自动重启和swarm endpoinnt就将容器启动
   233  	// Restart all autostart containers which has a swarm endpoint
   234  	// and is not yet running now that we have successfully
   235  	// initialized the cluster.
   236  	d.RestartSwarmContainers()
   237  
   238  	logrus.Info("Daemon has completed initialization")
   239  
   240  	cli.d = d
   241  
   242  	// 配置路由选项
   243  	routerOptions, err := newRouterOptions(cli.Config, d)
   244  	if err != nil {
   245  		return err
   246  	}
   247  	routerOptions.api = cli.api
   248  	routerOptions.cluster = c
   249  
   250  	// 10、初始化路由
   251  	initRouter(routerOptions)
   252  
   253  	// 开始swarm chan中的消息通知
   254  	go d.ProcessClusterNotifications(ctx, c.GetWatchStream())
   255  
   256  	// 11、设置SIGHUP信号来做config reload
   257  	cli.setupConfigReloadTrap()
   258  
   259  	// 12、开始监听apiServer
   260  	// The serve API routine never exits unless an error occurs
   261  	// We need to start it as a goroutine and wait on it so
   262  	// daemon doesn't exit
   263  	serveAPIWait := make(chan error)
   264  	go cli.api.Wait(serveAPIWait)
   265  
   266  	// 13、daemon 开始运行之后通知设置的系统内
   267  	// after the daemon is done setting up we can notify systemd api
   268  	notifySystem()
   269  
   270  	// 14、阻塞主进程,直到apiServer结束(错误或者正确)
   271  	// Daemon is fully initialized and handling API traffic
   272  	// Wait for serve API to complete
   273  	errAPI := <-serveAPIWait
   274  
   275  	// 15. 进程结束后的清理工作
   276  	c.Cleanup()
   277  	// 关闭daemon
   278  	shutdownDaemon(d)
   279  
   280  	// 关闭之前使用 context.WithCancel(context.Background())创建的ctx
   281  	// Stop notification processing and any background processes
   282  	cancel()
   283  
   284  	if errAPI != nil {
   285  		return fmt.Errorf("Shutting down due to ServeAPI error: %v", errAPI)
   286  	}
   287  
   288  	return nil
   289  }
   290  
   291  type routerOptions struct {
   292  	sessionManager *session.Manager
   293  	buildBackend   *buildbackend.Backend
   294  	buildCache     *fscache.FSCache // legacy
   295  	features       *map[string]bool
   296  	buildkit       *buildkit.Builder
   297  	daemon         *daemon.Daemon
   298  	api            *apiserver.Server
   299  	cluster        *cluster.Cluster
   300  }
   301  
   302  func newRouterOptions(config *config.Config, d *daemon.Daemon) (routerOptions, error) {
   303  	opts := routerOptions{}
   304  	sm, err := session.NewManager()
   305  	if err != nil {
   306  		return opts, errors.Wrap(err, "failed to create sessionmanager")
   307  	}
   308  
   309  	builderStateDir := filepath.Join(config.Root, "builder")
   310  
   311  	buildCache, err := fscache.NewFSCache(fscache.Opt{
   312  		Backend: fscache.NewNaiveCacheBackend(builderStateDir),
   313  		Root:    builderStateDir,
   314  		GCPolicy: fscache.GCPolicy{ // TODO: expose this in config
   315  			MaxSize:         1024 * 1024 * 512,  // 512MB
   316  			MaxKeepDuration: 7 * 24 * time.Hour, // 1 week
   317  		},
   318  	})
   319  	if err != nil {
   320  		return opts, errors.Wrap(err, "failed to create fscache")
   321  	}
   322  
   323  	manager, err := dockerfile.NewBuildManager(d.BuilderBackend(), sm, buildCache, d.IdentityMapping())
   324  	if err != nil {
   325  		return opts, err
   326  	}
   327  	cgroupParent := newCgroupParent(config)
   328  	bk, err := buildkit.New(buildkit.Opt{
   329  		SessionManager:      sm,
   330  		Root:                filepath.Join(config.Root, "buildkit"),
   331  		Dist:                d.DistributionServices(),
   332  		NetworkController:   d.NetworkController(),
   333  		DefaultCgroupParent: cgroupParent,
   334  		ResolverOpt:         d.NewResolveOptionsFunc(),
   335  		BuilderConfig:       config.Builder,
   336  	})
   337  	if err != nil {
   338  		return opts, err
   339  	}
   340  
   341  	bb, err := buildbackend.NewBackend(d.ImageService(), manager, buildCache, bk)
   342  	if err != nil {
   343  		return opts, errors.Wrap(err, "failed to create buildmanager")
   344  	}
   345  	return routerOptions{
   346  		sessionManager: sm,
   347  		buildBackend:   bb,
   348  		buildCache:     buildCache,
   349  		buildkit:       bk,
   350  		features:       d.Features(),
   351  		daemon:         d,
   352  	}, nil
   353  }
   354  
   355  func (cli *DaemonCli) reloadConfig() {
   356  	reload := func(c *config.Config) {
   357  
   358  		// Revalidate and reload the authorization plugins
   359  		if err := validateAuthzPlugins(c.AuthorizationPlugins, cli.d.PluginStore); err != nil {
   360  			logrus.Fatalf("Error validating authorization plugin: %v", err)
   361  			return
   362  		}
   363  		cli.authzMiddleware.SetPlugins(c.AuthorizationPlugins)
   364  
   365  		// The namespaces com.docker.*, io.docker.*, org.dockerproject.* have been documented
   366  		// to be reserved for Docker's internal use, but this was never enforced.  Allowing
   367  		// configured labels to use these namespaces are deprecated for 18.05.
   368  		//
   369  		// The following will check the usage of such labels, and report a warning for deprecation.
   370  		//
   371  		// TODO: At the next stable release, the validation should be folded into the other
   372  		// configuration validation functions and an error will be returned instead, and this
   373  		// block should be deleted.
   374  		if err := config.ValidateReservedNamespaceLabels(c.Labels); err != nil {
   375  			logrus.Warnf("Configured labels using reserved namespaces is deprecated: %s", err)
   376  		}
   377  
   378  		if err := cli.d.Reload(c); err != nil {
   379  			logrus.Errorf("Error reconfiguring the daemon: %v", err)
   380  			return
   381  		}
   382  
   383  		if c.IsValueSet("debug") {
   384  			debugEnabled := debug.IsEnabled()
   385  			switch {
   386  			case debugEnabled && !c.Debug: // disable debug
   387  				debug.Disable()
   388  			case c.Debug && !debugEnabled: // enable debug
   389  				debug.Enable()
   390  			}
   391  		}
   392  	}
   393  
   394  	if err := config.Reload(*cli.configFile, cli.flags, reload); err != nil {
   395  		logrus.Error(err)
   396  	}
   397  }
   398  
   399  func (cli *DaemonCli) stop() {
   400  	cli.api.Close()
   401  }
   402  
   403  // shutdownDaemon just wraps daemon.Shutdown() to handle a timeout in case
   404  // d.Shutdown() is waiting too long to kill container or worst it's
   405  // blocked there
   406  func shutdownDaemon(d *daemon.Daemon) {
   407  	shutdownTimeout := d.ShutdownTimeout()
   408  	ch := make(chan struct{})
   409  	go func() {
   410  		d.Shutdown()
   411  		close(ch)
   412  	}()
   413  	if shutdownTimeout < 0 {
   414  		<-ch
   415  		logrus.Debug("Clean shutdown succeeded")
   416  		return
   417  	}
   418  	select {
   419  	case <-ch:
   420  		logrus.Debug("Clean shutdown succeeded")
   421  	case <-time.After(time.Duration(shutdownTimeout) * time.Second):
   422  		logrus.Error("Force shutdown daemon")
   423  	}
   424  }
   425  
   426  func loadDaemonCliConfig(opts *daemonOptions) (*config.Config, error) {
   427  	conf := opts.daemonConfig
   428  	flags := opts.flags
   429  	conf.Debug = opts.Debug
   430  	conf.Hosts = opts.Hosts
   431  	conf.LogLevel = opts.LogLevel
   432  	conf.TLS = opts.TLS
   433  	conf.TLSVerify = opts.TLSVerify
   434  	conf.CommonTLSOptions = config.CommonTLSOptions{}
   435  
   436  	if opts.TLSOptions != nil {
   437  		conf.CommonTLSOptions.CAFile = opts.TLSOptions.CAFile
   438  		conf.CommonTLSOptions.CertFile = opts.TLSOptions.CertFile
   439  		conf.CommonTLSOptions.KeyFile = opts.TLSOptions.KeyFile
   440  	}
   441  
   442  	if conf.TrustKeyPath == "" {
   443  		conf.TrustKeyPath = filepath.Join(
   444  			getDaemonConfDir(conf.Root),
   445  			defaultTrustKeyFile)
   446  	}
   447  
   448  	// graph和data-root不能同时设置
   449  	if flags.Changed("graph") && flags.Changed("data-root") {
   450  		return nil, fmt.Errorf(`cannot specify both "--graph" and "--data-root" option`)
   451  	}
   452  
   453  	// 加载配置文件,也就是'/etc/docker/docker.json'
   454  	if opts.configFile != "" {
   455  
   456  		// 合并json config file和flags config
   457  		c, err := config.MergeDaemonConfigurations(conf, flags, opts.configFile)
   458  		if err != nil {
   459  			if flags.Changed("config-file") || !os.IsNotExist(err) {
   460  				return nil, fmt.Errorf("unable to configure the Docker daemon with file %s: %v", opts.configFile, err)
   461  			}
   462  		}
   463  		// the merged configuration can be nil if the config file didn't exist.
   464  		// leave the current configuration as it is if when that happens.
   465  		if c != nil {
   466  			conf = c
   467  		}
   468  	}
   469  
   470  	if err := config.Validate(conf); err != nil {
   471  		return nil, err
   472  	}
   473  
   474  	if runtime.GOOS != "windows" {
   475  		if flags.Changed("disable-legacy-registry") {
   476  			// TODO: Remove this error after 3 release cycles (18.03)
   477  			return nil, errors.New("ERROR: The '--disable-legacy-registry' flag has been removed. Interacting with legacy (v1) registries is no longer supported")
   478  		}
   479  		if !conf.V2Only {
   480  			// TODO: Remove this error after 3 release cycles (18.03)
   481  			return nil, errors.New("ERROR: The 'disable-legacy-registry' configuration option has been removed. Interacting with legacy (v1) registries is no longer supported")
   482  		}
   483  	}
   484  
   485  	if flags.Changed("graph") {
   486  		logrus.Warnf(`The "-g / --graph" flag is deprecated. Please use "--data-root" instead`)
   487  	}
   488  
   489  	// 验证配置中是否有lables冲突
   490  	// Check if duplicate label-keys with different values are found
   491  	newLabels, err := config.GetConflictFreeLabels(conf.Labels)
   492  	if err != nil {
   493  		return nil, err
   494  	}
   495  	// The namespaces com.docker.*, io.docker.*, org.dockerproject.* have been documented
   496  	// to be reserved for Docker's internal use, but this was never enforced.  Allowing
   497  	// configured labels to use these namespaces are deprecated for 18.05.
   498  	//
   499  	// The following will check the usage of such labels, and report a warning for deprecation.
   500  	//
   501  	// TODO: At the next stable release, the validation should be folded into the other
   502  	// configuration validation functions and an error will be returned instead, and this
   503  	// block should be deleted.
   504  	if err := config.ValidateReservedNamespaceLabels(newLabels); err != nil {
   505  		logrus.Warnf("Configured labels using reserved namespaces is deprecated: %s", err)
   506  	}
   507  	conf.Labels = newLabels
   508  
   509  	// Regardless of whether the user sets it to true or false, if they
   510  	// specify TLSVerify at all then we need to turn on TLS
   511  	if conf.IsValueSet(FlagTLSVerify) {
   512  		conf.TLS = true
   513  	}
   514  
   515  	// ensure that the log level is the one set after merging configurations
   516  	setLogLevel(conf.LogLevel)
   517  
   518  	return conf, nil
   519  }
   520  
   521  func initRouter(opts routerOptions) {
   522  	decoder := runconfig.ContainerDecoder{}
   523  
   524  	routers := []router.Router{
   525  		// we need to add the checkpoint router before the container router or the DELETE gets masked
   526  		checkpointrouter.NewRouter(opts.daemon, decoder),
   527  		container.NewRouter(opts.daemon, decoder),
   528  		image.NewRouter(opts.daemon.ImageService()),
   529  		systemrouter.NewRouter(opts.daemon, opts.cluster, opts.buildCache, opts.buildkit, opts.features),
   530  		volume.NewRouter(opts.daemon.VolumesService()),
   531  		build.NewRouter(opts.buildBackend, opts.daemon, opts.features),
   532  		sessionrouter.NewRouter(opts.sessionManager),
   533  		swarmrouter.NewRouter(opts.cluster),
   534  		pluginrouter.NewRouter(opts.daemon.PluginManager()),
   535  		distributionrouter.NewRouter(opts.daemon.ImageService()),
   536  	}
   537  
   538  	if opts.daemon.NetworkControllerEnabled() {
   539  		routers = append(routers, network.NewRouter(opts.daemon, opts.cluster))
   540  	}
   541  
   542  	if opts.daemon.HasExperimental() {
   543  		for _, r := range routers {
   544  			for _, route := range r.Routes() {
   545  				if experimental, ok := route.(router.ExperimentalRoute); ok {
   546  					experimental.Enable()
   547  				}
   548  			}
   549  		}
   550  	}
   551  
   552  	opts.api.InitRouter(routers...)
   553  }
   554  
   555  // TODO: remove this from cli and return the authzMiddleware
   556  func (cli *DaemonCli) initMiddlewares(s *apiserver.Server, cfg *apiserver.Config, pluginStore plugingetter.PluginGetter) error {
   557  	v := cfg.Version
   558  
   559  	exp := middleware.NewExperimentalMiddleware(cli.Config.Experimental)
   560  	s.UseMiddleware(exp)
   561  
   562  	vm := middleware.NewVersionMiddleware(v, api.DefaultVersion, api.MinVersion)
   563  	s.UseMiddleware(vm)
   564  
   565  	if cfg.CorsHeaders != "" {
   566  		c := middleware.NewCORSMiddleware(cfg.CorsHeaders)
   567  		s.UseMiddleware(c)
   568  	}
   569  
   570  	cli.authzMiddleware = authorization.NewMiddleware(cli.Config.AuthorizationPlugins, pluginStore)
   571  	cli.Config.AuthzMiddleware = cli.authzMiddleware
   572  	s.UseMiddleware(cli.authzMiddleware)
   573  	return nil
   574  }
   575  
   576  func (cli *DaemonCli) getContainerdDaemonOpts() ([]supervisor.DaemonOpt, error) {
   577  	opts, err := cli.getPlatformContainerdDaemonOpts()
   578  	if err != nil {
   579  		return nil, err
   580  	}
   581  
   582  	if cli.Config.Debug {
   583  		opts = append(opts, supervisor.WithLogLevel("debug"))
   584  	} else if cli.Config.LogLevel != "" {
   585  		opts = append(opts, supervisor.WithLogLevel(cli.Config.LogLevel))
   586  	}
   587  
   588  	if !cli.Config.CriContainerd {
   589  		opts = append(opts, supervisor.WithPlugin("cri", nil))
   590  	}
   591  
   592  	return opts, nil
   593  }
   594  
   595  func newAPIServerConfig(cli *DaemonCli) (*apiserver.Config, error) {
   596  	// 创建apiserver Config对象, 其中socketGroup默认值是’docker‘,CorsHeaders默认是空
   597  	serverConfig := &apiserver.Config{
   598  		Logging:     true,
   599  		SocketGroup: cli.Config.SocketGroup,
   600  		Version:     dockerversion.Version,
   601  		CorsHeaders: cli.Config.CorsHeaders,
   602  	}
   603  
   604  	// TLS相关设置
   605  	if cli.Config.TLS {
   606  		tlsOptions := tlsconfig.Options{
   607  			CAFile:             cli.Config.CommonTLSOptions.CAFile,
   608  			CertFile:           cli.Config.CommonTLSOptions.CertFile,
   609  			KeyFile:            cli.Config.CommonTLSOptions.KeyFile,
   610  			ExclusiveRootPools: true,
   611  		}
   612  
   613  		if cli.Config.TLSVerify {
   614  			// server requires and verifies client's certificate
   615  			tlsOptions.ClientAuth = tls.RequireAndVerifyClientCert
   616  		}
   617  		tlsConfig, err := tlsconfig.Server(tlsOptions)
   618  		if err != nil {
   619  			return nil, err
   620  		}
   621  		serverConfig.TLSConfig = tlsConfig
   622  	}
   623  
   624  	if len(cli.Config.Hosts) == 0 {
   625  		cli.Config.Hosts = make([]string, 1)
   626  	}
   627  
   628  	return serverConfig, nil
   629  }
   630  
   631  func loadListeners(cli *DaemonCli, serverConfig *apiserver.Config) ([]string, error) {
   632  	var hosts []string
   633  	// 如果用户不指定,默认情况下只有一个,而且是空值
   634  	for i := 0; i < len(cli.Config.Hosts); i++ {
   635  		var err error
   636  		// 如果用户不指定,并且没有开启TLS的话,这个host就是unix:///var/run/docker.sock
   637  		if cli.Config.Hosts[i], err = dopts.ParseHost(cli.Config.TLS, cli.Config.Hosts[i]); err != nil {
   638  			return nil, fmt.Errorf("error parsing -H %s : %v", cli.Config.Hosts[i], err)
   639  		}
   640  
   641  		protoAddr := cli.Config.Hosts[i]
   642  		protoAddrParts := strings.SplitN(protoAddr, "://", 2)
   643  		if len(protoAddrParts) != 2 {
   644  			return nil, fmt.Errorf("bad format %s, expected PROTO://ADDR", protoAddr)
   645  		}
   646  
   647  		proto := protoAddrParts[0]
   648  		addr := protoAddrParts[1]
   649  
   650  		// It's a bad idea to bind to TCP without tlsverify.
   651  		if proto == "tcp" && (serverConfig.TLSConfig == nil || serverConfig.TLSConfig.ClientAuth != tls.RequireAndVerifyClientCert) {
   652  			logrus.Warn("[!] DON'T BIND ON ANY IP ADDRESS WITHOUT setting --tlsverify IF YOU DON'T KNOW WHAT YOU'RE DOING [!]")
   653  		}
   654  
   655  		// 根据host,分解出来protocol和path,生成net.Listener对象列表
   656  		ls, err := listeners.Init(proto, addr, serverConfig.SocketGroup, serverConfig.TLSConfig)
   657  		if err != nil {
   658  			return nil, err
   659  		}
   660  
   661  		// 对标准的listener进行封装
   662  		ls = wrapListeners(proto, ls)
   663  		// If we're binding to a TCP port, make sure that a container doesn't try to use it.
   664  		if proto == "tcp" {
   665  			if err := allocateDaemonPort(addr); err != nil {
   666  				return nil, err
   667  			}
   668  		}
   669  
   670  		logrus.Debugf("Listener created for HTTP on %s (%s)", proto, addr)
   671  		hosts = append(hosts, protoAddrParts[1])
   672  		cli.api.Accept(addr, ls...)
   673  	}
   674  
   675  	return hosts, nil
   676  }
   677  
   678  func createAndStartCluster(cli *DaemonCli, d *daemon.Daemon) (*cluster.Cluster, error) {
   679  	name, _ := os.Hostname()
   680  
   681  	// Use a buffered channel to pass changes from store watch API to daemon
   682  	// A buffer allows store watch API and daemon processing to not wait for each other
   683  	watchStream := make(chan *swarmapi.WatchMessage, 32)
   684  
   685  	c, err := cluster.New(cluster.Config{
   686  		Root:                   cli.Config.Root,
   687  		Name:                   name,
   688  		Backend:                d,
   689  		VolumeBackend:          d.VolumesService(),
   690  		ImageBackend:           d.ImageService(),
   691  		PluginBackend:          d.PluginManager(),
   692  		NetworkSubnetsProvider: d,
   693  		DefaultAdvertiseAddr:   cli.Config.SwarmDefaultAdvertiseAddr,
   694  		RaftHeartbeatTick:      cli.Config.SwarmRaftHeartbeatTick,
   695  		RaftElectionTick:       cli.Config.SwarmRaftElectionTick,
   696  		RuntimeRoot:            cli.getSwarmRunRoot(),
   697  		WatchStream:            watchStream,
   698  	})
   699  	if err != nil {
   700  		return nil, err
   701  	}
   702  	d.SetCluster(c)
   703  	err = c.Start()
   704  
   705  	return c, err
   706  }
   707  
   708  // validates that the plugins requested with the --authorization-plugin flag are valid AuthzDriver
   709  // plugins present on the host and available to the daemon
   710  func validateAuthzPlugins(requestedPlugins []string, pg plugingetter.PluginGetter) error {
   711  	for _, reqPlugin := range requestedPlugins {
   712  		if _, err := pg.Get(reqPlugin, authorization.AuthZApiImplements, plugingetter.Lookup); err != nil {
   713  			return err
   714  		}
   715  	}
   716  	return nil
   717  }
   718  
   719  func systemContainerdRunning() bool {
   720  	_, err := os.Lstat(containerddefaults.DefaultAddress)
   721  	return err == nil
   722  }