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 }