github.com/jfrazelle/docker@v1.1.2-0.20210712172922-bf78e25fe508/cmd/dockerd/daemon.go (about) 1 package main 2 3 import ( 4 "context" 5 "crypto/tls" 6 "fmt" 7 "net" 8 "os" 9 "path/filepath" 10 "runtime" 11 "strings" 12 "time" 13 14 containerddefaults "github.com/containerd/containerd/defaults" 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 grpcrouter "github.com/docker/docker/api/server/router/grpc" 25 "github.com/docker/docker/api/server/router/image" 26 "github.com/docker/docker/api/server/router/network" 27 pluginrouter "github.com/docker/docker/api/server/router/plugin" 28 sessionrouter "github.com/docker/docker/api/server/router/session" 29 swarmrouter "github.com/docker/docker/api/server/router/swarm" 30 systemrouter "github.com/docker/docker/api/server/router/system" 31 "github.com/docker/docker/api/server/router/volume" 32 buildkit "github.com/docker/docker/builder/builder-next" 33 "github.com/docker/docker/builder/dockerfile" 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/homedir" 44 "github.com/docker/docker/pkg/jsonmessage" 45 "github.com/docker/docker/pkg/pidfile" 46 "github.com/docker/docker/pkg/plugingetter" 47 "github.com/docker/docker/pkg/signal" 48 "github.com/docker/docker/pkg/sysinfo" 49 "github.com/docker/docker/pkg/system" 50 "github.com/docker/docker/plugin" 51 "github.com/docker/docker/rootless" 52 "github.com/docker/docker/runconfig" 53 "github.com/docker/go-connections/tlsconfig" 54 swarmapi "github.com/docker/swarmkit/api" 55 "github.com/moby/buildkit/session" 56 "github.com/pkg/errors" 57 "github.com/sirupsen/logrus" 58 "github.com/spf13/pflag" 59 ) 60 61 // DaemonCli represents the daemon CLI. 62 type DaemonCli struct { 63 *config.Config 64 configFile *string 65 flags *pflag.FlagSet 66 67 api *apiserver.Server 68 d *daemon.Daemon 69 authzMiddleware *authorization.Middleware // authzMiddleware enables to dynamically reload the authorization plugins 70 } 71 72 // NewDaemonCli returns a daemon CLI 73 func NewDaemonCli() *DaemonCli { 74 return &DaemonCli{} 75 } 76 77 func (cli *DaemonCli) start(opts *daemonOptions) (err error) { 78 opts.SetDefaultOptions(opts.flags) 79 80 if cli.Config, err = loadDaemonCliConfig(opts); err != nil { 81 return err 82 } 83 84 if opts.Validate { 85 // If config wasn't OK we wouldn't have made it this far. 86 fmt.Fprintln(os.Stderr, "configuration OK") 87 return nil 88 } 89 90 warnOnDeprecatedConfigOptions(cli.Config) 91 92 if err := configureDaemonLogs(cli.Config); err != nil { 93 return err 94 } 95 96 logrus.Info("Starting up") 97 98 cli.configFile = &opts.configFile 99 cli.flags = opts.flags 100 101 if cli.Config.Debug { 102 debug.Enable() 103 } 104 105 if cli.Config.Experimental { 106 logrus.Warn("Running experimental build") 107 } 108 109 if cli.Config.IsRootless() { 110 logrus.Warn("Running in rootless mode. This mode has feature limitations.") 111 } 112 if rootless.RunningWithRootlessKit() { 113 logrus.Info("Running with RootlessKit integration") 114 if !cli.Config.IsRootless() { 115 return fmt.Errorf("rootless mode needs to be enabled for running with RootlessKit") 116 } 117 } 118 119 // return human-friendly error before creating files 120 if runtime.GOOS == "linux" && os.Geteuid() != 0 { 121 return fmt.Errorf("dockerd needs to be started with root. To see how to run dockerd in rootless mode with unprivileged user, see the documentation") 122 } 123 124 if err := setDefaultUmask(); err != nil { 125 return err 126 } 127 128 // Create the daemon root before we create ANY other files (PID, or migrate keys) 129 // to ensure the appropriate ACL is set (particularly relevant on Windows) 130 if err := daemon.CreateDaemonRoot(cli.Config); err != nil { 131 return err 132 } 133 134 if err := system.MkdirAll(cli.Config.ExecRoot, 0700); err != nil { 135 return err 136 } 137 138 potentiallyUnderRuntimeDir := []string{cli.Config.ExecRoot} 139 140 if cli.Pidfile != "" { 141 pf, err := pidfile.New(cli.Pidfile) 142 if err != nil { 143 return errors.Wrap(err, "failed to start daemon") 144 } 145 potentiallyUnderRuntimeDir = append(potentiallyUnderRuntimeDir, cli.Pidfile) 146 defer func() { 147 if err := pf.Remove(); err != nil { 148 logrus.Error(err) 149 } 150 }() 151 } 152 153 if cli.Config.IsRootless() { 154 // Set sticky bit if XDG_RUNTIME_DIR is set && the file is actually under XDG_RUNTIME_DIR 155 if _, err := homedir.StickRuntimeDirContents(potentiallyUnderRuntimeDir); err != nil { 156 // StickRuntimeDirContents returns nil error if XDG_RUNTIME_DIR is just unset 157 logrus.WithError(err).Warn("cannot set sticky bit on files under XDG_RUNTIME_DIR") 158 } 159 } 160 161 serverConfig, err := newAPIServerConfig(cli) 162 if err != nil { 163 return errors.Wrap(err, "failed to create API server") 164 } 165 cli.api = apiserver.New(serverConfig) 166 167 hosts, err := loadListeners(cli, serverConfig) 168 if err != nil { 169 return errors.Wrap(err, "failed to load listeners") 170 } 171 172 ctx, cancel := context.WithCancel(context.Background()) 173 waitForContainerDShutdown, err := cli.initContainerD(ctx) 174 if waitForContainerDShutdown != nil { 175 defer waitForContainerDShutdown(10 * time.Second) 176 } 177 if err != nil { 178 cancel() 179 return err 180 } 181 defer cancel() 182 183 stopc := make(chan bool) 184 defer close(stopc) 185 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 preNotifyReady() 193 194 pluginStore := plugin.NewStore() 195 196 if err := cli.initMiddlewares(cli.api, serverConfig, pluginStore); err != nil { 197 logrus.Fatalf("Error creating middlewares: %v", err) 198 } 199 200 d, err := daemon.NewDaemon(ctx, cli.Config, pluginStore) 201 if err != nil { 202 return errors.Wrap(err, "failed to start daemon") 203 } 204 205 d.StoreHosts(hosts) 206 207 // validate after NewDaemon has restored enabled plugins. Don't change order. 208 if err := validateAuthzPlugins(cli.Config.AuthorizationPlugins, pluginStore); err != nil { 209 return errors.Wrap(err, "failed to validate authorization plugin") 210 } 211 212 cli.d = d 213 214 if err := startMetricsServer(cli.Config.MetricsAddress); err != nil { 215 return errors.Wrap(err, "failed to start metrics server") 216 } 217 218 c, err := createAndStartCluster(cli, d) 219 if err != nil { 220 logrus.Fatalf("Error starting cluster component: %v", err) 221 } 222 223 // Restart all autostart containers which has a swarm endpoint 224 // and is not yet running now that we have successfully 225 // initialized the cluster. 226 d.RestartSwarmContainers() 227 228 logrus.Info("Daemon has completed initialization") 229 230 routerOptions, err := newRouterOptions(cli.Config, d) 231 if err != nil { 232 return err 233 } 234 routerOptions.api = cli.api 235 routerOptions.cluster = c 236 237 initRouter(routerOptions) 238 239 go d.ProcessClusterNotifications(ctx, c.GetWatchStream()) 240 241 cli.setupConfigReloadTrap() 242 243 // The serve API routine never exits unless an error occurs 244 // We need to start it as a goroutine and wait on it so 245 // daemon doesn't exit 246 serveAPIWait := make(chan error) 247 go cli.api.Wait(serveAPIWait) 248 249 // after the daemon is done setting up we can notify systemd api 250 notifyReady() 251 252 // Daemon is fully initialized and handling API traffic 253 // Wait for serve API to complete 254 errAPI := <-serveAPIWait 255 c.Cleanup() 256 257 // notify systemd that we're shutting down 258 notifyStopping() 259 shutdownDaemon(d) 260 261 // Stop notification processing and any background processes 262 cancel() 263 264 if errAPI != nil { 265 return errors.Wrap(errAPI, "shutting down due to ServeAPI error") 266 } 267 268 logrus.Info("Daemon shutdown complete") 269 return nil 270 } 271 272 type routerOptions struct { 273 sessionManager *session.Manager 274 buildBackend *buildbackend.Backend 275 features *map[string]bool 276 buildkit *buildkit.Builder 277 daemon *daemon.Daemon 278 api *apiserver.Server 279 cluster *cluster.Cluster 280 } 281 282 func newRouterOptions(config *config.Config, d *daemon.Daemon) (routerOptions, error) { 283 opts := routerOptions{} 284 sm, err := session.NewManager() 285 if err != nil { 286 return opts, errors.Wrap(err, "failed to create sessionmanager") 287 } 288 289 manager, err := dockerfile.NewBuildManager(d.BuilderBackend(), d.IdentityMapping()) 290 if err != nil { 291 return opts, err 292 } 293 cgroupParent := newCgroupParent(config) 294 bk, err := buildkit.New(buildkit.Opt{ 295 SessionManager: sm, 296 Root: filepath.Join(config.Root, "buildkit"), 297 Dist: d.DistributionServices(), 298 NetworkController: d.NetworkController(), 299 DefaultCgroupParent: cgroupParent, 300 RegistryHosts: d.RegistryHosts(), 301 BuilderConfig: config.Builder, 302 Rootless: d.Rootless(), 303 IdentityMapping: d.IdentityMapping(), 304 DNSConfig: config.DNSConfig, 305 ApparmorProfile: daemon.DefaultApparmorProfile(), 306 }) 307 if err != nil { 308 return opts, err 309 } 310 311 bb, err := buildbackend.NewBackend(d.ImageService(), manager, bk, d.EventsService) 312 if err != nil { 313 return opts, errors.Wrap(err, "failed to create buildmanager") 314 } 315 return routerOptions{ 316 sessionManager: sm, 317 buildBackend: bb, 318 buildkit: bk, 319 features: d.Features(), 320 daemon: d, 321 }, nil 322 } 323 324 func (cli *DaemonCli) reloadConfig() { 325 reload := func(c *config.Config) { 326 327 // Revalidate and reload the authorization plugins 328 if err := validateAuthzPlugins(c.AuthorizationPlugins, cli.d.PluginStore); err != nil { 329 logrus.Fatalf("Error validating authorization plugin: %v", err) 330 return 331 } 332 cli.authzMiddleware.SetPlugins(c.AuthorizationPlugins) 333 334 if err := cli.d.Reload(c); err != nil { 335 logrus.Errorf("Error reconfiguring the daemon: %v", err) 336 return 337 } 338 339 if c.IsValueSet("debug") { 340 debugEnabled := debug.IsEnabled() 341 switch { 342 case debugEnabled && !c.Debug: // disable debug 343 debug.Disable() 344 case c.Debug && !debugEnabled: // enable debug 345 debug.Enable() 346 } 347 } 348 } 349 350 if err := config.Reload(*cli.configFile, cli.flags, reload); err != nil { 351 logrus.Error(err) 352 } 353 } 354 355 func (cli *DaemonCli) stop() { 356 cli.api.Close() 357 } 358 359 // shutdownDaemon just wraps daemon.Shutdown() to handle a timeout in case 360 // d.Shutdown() is waiting too long to kill container or worst it's 361 // blocked there 362 func shutdownDaemon(d *daemon.Daemon) { 363 shutdownTimeout := d.ShutdownTimeout() 364 ch := make(chan struct{}) 365 go func() { 366 d.Shutdown() 367 close(ch) 368 }() 369 if shutdownTimeout < 0 { 370 <-ch 371 logrus.Debug("Clean shutdown succeeded") 372 return 373 } 374 375 timeout := time.NewTimer(time.Duration(shutdownTimeout) * time.Second) 376 defer timeout.Stop() 377 378 select { 379 case <-ch: 380 logrus.Debug("Clean shutdown succeeded") 381 case <-timeout.C: 382 logrus.Error("Force shutdown daemon") 383 } 384 } 385 386 func loadDaemonCliConfig(opts *daemonOptions) (*config.Config, error) { 387 conf := opts.daemonConfig 388 flags := opts.flags 389 conf.Debug = opts.Debug 390 conf.Hosts = opts.Hosts 391 conf.LogLevel = opts.LogLevel 392 393 if opts.flags.Changed(FlagTLS) { 394 conf.TLS = &opts.TLS 395 } 396 if opts.flags.Changed(FlagTLSVerify) { 397 conf.TLSVerify = &opts.TLSVerify 398 v := true 399 conf.TLS = &v 400 } 401 402 conf.CommonTLSOptions = config.CommonTLSOptions{} 403 404 if opts.TLSOptions != nil { 405 conf.CommonTLSOptions.CAFile = opts.TLSOptions.CAFile 406 conf.CommonTLSOptions.CertFile = opts.TLSOptions.CertFile 407 conf.CommonTLSOptions.KeyFile = opts.TLSOptions.KeyFile 408 } 409 410 if conf.TrustKeyPath == "" { 411 daemonConfDir, err := getDaemonConfDir(conf.Root) 412 if err != nil { 413 return nil, err 414 } 415 conf.TrustKeyPath = filepath.Join(daemonConfDir, defaultTrustKeyFile) 416 } 417 418 if flags.Changed("graph") && flags.Changed("data-root") { 419 return nil, errors.New(`cannot specify both "--graph" and "--data-root" option`) 420 } 421 422 if opts.configFile != "" { 423 c, err := config.MergeDaemonConfigurations(conf, flags, opts.configFile) 424 if err != nil { 425 if flags.Changed("config-file") || !os.IsNotExist(err) { 426 return nil, errors.Wrapf(err, "unable to configure the Docker daemon with file %s", opts.configFile) 427 } 428 } 429 430 // the merged configuration can be nil if the config file didn't exist. 431 // leave the current configuration as it is if when that happens. 432 if c != nil { 433 conf = c 434 } 435 } 436 437 if err := config.Validate(conf); err != nil { 438 return nil, err 439 } 440 441 if flags.Changed("graph") { 442 logrus.Warnf(`The "-g / --graph" flag is deprecated. Please use "--data-root" instead`) 443 } 444 445 // Check if duplicate label-keys with different values are found 446 newLabels, err := config.GetConflictFreeLabels(conf.Labels) 447 if err != nil { 448 return nil, err 449 } 450 conf.Labels = newLabels 451 452 // Regardless of whether the user sets it to true or false, if they 453 // specify TLSVerify at all then we need to turn on TLS 454 if conf.IsValueSet(FlagTLSVerify) { 455 v := true 456 conf.TLS = &v 457 } 458 459 if conf.TLSVerify == nil && conf.TLS != nil { 460 conf.TLSVerify = conf.TLS 461 } 462 463 return conf, nil 464 } 465 466 func warnOnDeprecatedConfigOptions(config *config.Config) { 467 if config.ClusterAdvertise != "" { 468 logrus.Warn(`The "cluster-advertise" option is deprecated. To be removed soon.`) 469 } 470 if config.ClusterStore != "" { 471 logrus.Warn(`The "cluster-store" option is deprecated. To be removed soon.`) 472 } 473 if len(config.ClusterOpts) > 0 { 474 logrus.Warn(`The "cluster-store-opt" option is deprecated. To be removed soon.`) 475 } 476 } 477 478 func initRouter(opts routerOptions) { 479 decoder := runconfig.ContainerDecoder{ 480 GetSysInfo: func() *sysinfo.SysInfo { 481 return opts.daemon.RawSysInfo(true) 482 }, 483 } 484 485 routers := []router.Router{ 486 // we need to add the checkpoint router before the container router or the DELETE gets masked 487 checkpointrouter.NewRouter(opts.daemon, decoder), 488 container.NewRouter(opts.daemon, decoder, opts.daemon.RawSysInfo(true).CgroupUnified), 489 image.NewRouter(opts.daemon.ImageService()), 490 systemrouter.NewRouter(opts.daemon, opts.cluster, opts.buildkit, opts.features), 491 volume.NewRouter(opts.daemon.VolumesService()), 492 build.NewRouter(opts.buildBackend, opts.daemon, opts.features), 493 sessionrouter.NewRouter(opts.sessionManager), 494 swarmrouter.NewRouter(opts.cluster), 495 pluginrouter.NewRouter(opts.daemon.PluginManager()), 496 distributionrouter.NewRouter(opts.daemon.ImageService()), 497 } 498 499 grpcBackends := []grpcrouter.Backend{} 500 for _, b := range []interface{}{opts.daemon, opts.buildBackend} { 501 if b, ok := b.(grpcrouter.Backend); ok { 502 grpcBackends = append(grpcBackends, b) 503 } 504 } 505 if len(grpcBackends) > 0 { 506 routers = append(routers, grpcrouter.NewRouter(grpcBackends...)) 507 } 508 509 if opts.daemon.NetworkControllerEnabled() { 510 routers = append(routers, network.NewRouter(opts.daemon, opts.cluster)) 511 } 512 513 if opts.daemon.HasExperimental() { 514 for _, r := range routers { 515 for _, route := range r.Routes() { 516 if experimental, ok := route.(router.ExperimentalRoute); ok { 517 experimental.Enable() 518 } 519 } 520 } 521 } 522 523 opts.api.InitRouter(routers...) 524 } 525 526 // TODO: remove this from cli and return the authzMiddleware 527 func (cli *DaemonCli) initMiddlewares(s *apiserver.Server, cfg *apiserver.Config, pluginStore plugingetter.PluginGetter) error { 528 v := cfg.Version 529 530 exp := middleware.NewExperimentalMiddleware(cli.Config.Experimental) 531 s.UseMiddleware(exp) 532 533 vm := middleware.NewVersionMiddleware(v, api.DefaultVersion, api.MinVersion) 534 s.UseMiddleware(vm) 535 536 if cfg.CorsHeaders != "" { 537 c := middleware.NewCORSMiddleware(cfg.CorsHeaders) 538 s.UseMiddleware(c) 539 } 540 541 cli.authzMiddleware = authorization.NewMiddleware(cli.Config.AuthorizationPlugins, pluginStore) 542 cli.Config.AuthzMiddleware = cli.authzMiddleware 543 s.UseMiddleware(cli.authzMiddleware) 544 return nil 545 } 546 547 func (cli *DaemonCli) getContainerdDaemonOpts() ([]supervisor.DaemonOpt, error) { 548 opts, err := cli.getPlatformContainerdDaemonOpts() 549 if err != nil { 550 return nil, err 551 } 552 553 if cli.Config.Debug { 554 opts = append(opts, supervisor.WithLogLevel("debug")) 555 } else if cli.Config.LogLevel != "" { 556 opts = append(opts, supervisor.WithLogLevel(cli.Config.LogLevel)) 557 } 558 559 if !cli.Config.CriContainerd { 560 opts = append(opts, supervisor.WithPlugin("cri", nil)) 561 } 562 563 return opts, nil 564 } 565 566 func newAPIServerConfig(cli *DaemonCli) (*apiserver.Config, error) { 567 serverConfig := &apiserver.Config{ 568 Logging: true, 569 SocketGroup: cli.Config.SocketGroup, 570 Version: dockerversion.Version, 571 CorsHeaders: cli.Config.CorsHeaders, 572 } 573 574 if cli.Config.TLS != nil && *cli.Config.TLS { 575 tlsOptions := tlsconfig.Options{ 576 CAFile: cli.Config.CommonTLSOptions.CAFile, 577 CertFile: cli.Config.CommonTLSOptions.CertFile, 578 KeyFile: cli.Config.CommonTLSOptions.KeyFile, 579 ExclusiveRootPools: true, 580 } 581 582 if cli.Config.TLSVerify == nil || *cli.Config.TLSVerify { 583 // server requires and verifies client's certificate 584 tlsOptions.ClientAuth = tls.RequireAndVerifyClientCert 585 } 586 tlsConfig, err := tlsconfig.Server(tlsOptions) 587 if err != nil { 588 return nil, err 589 } 590 serverConfig.TLSConfig = tlsConfig 591 } 592 593 if len(cli.Config.Hosts) == 0 { 594 cli.Config.Hosts = make([]string, 1) 595 } 596 597 return serverConfig, nil 598 } 599 600 // checkTLSAuthOK checks basically for an explicitly disabled TLS/TLSVerify 601 // Going forward we do not want to support a scenario where dockerd listens 602 // on TCP without either TLS client auth (or an explicit opt-in to disable it) 603 func checkTLSAuthOK(c *config.Config) bool { 604 if c.TLS == nil { 605 // Either TLS is enabled by default, in which case TLS verification should be enabled by default, or explicitly disabled 606 // Or TLS is disabled by default... in any of these cases, we can just take the default value as to how to proceed 607 return DefaultTLSValue 608 } 609 610 if !*c.TLS { 611 // TLS is explicitly disabled, which is supported 612 return true 613 } 614 615 if c.TLSVerify == nil { 616 // this actually shouldn't happen since we set TLSVerify on the config object anyway 617 // But in case it does get here, be cautious and assume this is not supported. 618 return false 619 } 620 621 // Either TLSVerify is explicitly enabled or disabled, both cases are supported 622 return true 623 } 624 625 func loadListeners(cli *DaemonCli, serverConfig *apiserver.Config) ([]string, error) { 626 var hosts []string 627 seen := make(map[string]struct{}, len(cli.Config.Hosts)) 628 629 useTLS := DefaultTLSValue 630 if cli.Config.TLS != nil { 631 useTLS = *cli.Config.TLS 632 } 633 634 for i := 0; i < len(cli.Config.Hosts); i++ { 635 var err error 636 if cli.Config.Hosts[i], err = dopts.ParseHost(useTLS, honorXDG, cli.Config.Hosts[i]); err != nil { 637 return nil, errors.Wrapf(err, "error parsing -H %s", cli.Config.Hosts[i]) 638 } 639 if _, ok := seen[cli.Config.Hosts[i]]; ok { 640 continue 641 } 642 seen[cli.Config.Hosts[i]] = struct{}{} 643 644 protoAddr := cli.Config.Hosts[i] 645 protoAddrParts := strings.SplitN(protoAddr, "://", 2) 646 if len(protoAddrParts) != 2 { 647 return nil, fmt.Errorf("bad format %s, expected PROTO://ADDR", protoAddr) 648 } 649 650 proto := protoAddrParts[0] 651 addr := protoAddrParts[1] 652 653 // It's a bad idea to bind to TCP without tlsverify. 654 authEnabled := serverConfig.TLSConfig != nil && serverConfig.TLSConfig.ClientAuth == tls.RequireAndVerifyClientCert 655 if proto == "tcp" && !authEnabled { 656 logrus.WithField("host", protoAddr).Warn("Binding to IP address without --tlsverify is insecure and gives root access on this machine to everyone who has access to your network.") 657 logrus.WithField("host", protoAddr).Warn("Binding to an IP address, even on localhost, can also give access to scripts run in a browser. Be safe out there!") 658 time.Sleep(time.Second) 659 660 // If TLSVerify is explicitly set to false we'll take that as "Please let me shoot myself in the foot" 661 // We do not want to continue to support a default mode where tls verification is disabled, so we do some extra warnings here and eventually remove support 662 if !checkTLSAuthOK(cli.Config) { 663 ipAddr, _, err := net.SplitHostPort(addr) 664 if err != nil { 665 return nil, errors.Wrap(err, "error parsing tcp address") 666 } 667 668 // shortcut all this extra stuff for literal "localhost" 669 // -H supports specifying hostnames, since we want to bypass this on loopback interfaces we'll look it up here. 670 if ipAddr != "localhost" { 671 ip := net.ParseIP(ipAddr) 672 if ip == nil { 673 ipA, err := net.ResolveIPAddr("ip", ipAddr) 674 if err != nil { 675 logrus.WithError(err).WithField("host", ipAddr).Error("Error looking up specified host address") 676 } 677 if ipA != nil { 678 ip = ipA.IP 679 } 680 } 681 if ip == nil || !ip.IsLoopback() { 682 logrus.WithField("host", protoAddr).Warn("Binding to an IP address without --tlsverify is deprecated. Startup is intentionally being slowed down to show this message") 683 logrus.WithField("host", protoAddr).Warn("Please consider generating tls certificates with client validation to prevent exposing unauthenticated root access to your network") 684 logrus.WithField("host", protoAddr).Warnf("You can override this by explicitly specifying '--%s=false' or '--%s=false'", FlagTLS, FlagTLSVerify) 685 logrus.WithField("host", protoAddr).Warnf("Support for listening on TCP without authentication or explicit intent to run without authentication will be removed in the next release") 686 687 time.Sleep(15 * time.Second) 688 } 689 } 690 } 691 } 692 ls, err := listeners.Init(proto, addr, serverConfig.SocketGroup, serverConfig.TLSConfig) 693 if err != nil { 694 return nil, err 695 } 696 // If we're binding to a TCP port, make sure that a container doesn't try to use it. 697 if proto == "tcp" { 698 if err := allocateDaemonPort(addr); err != nil { 699 return nil, err 700 } 701 } 702 logrus.Debugf("Listener created for HTTP on %s (%s)", proto, addr) 703 hosts = append(hosts, protoAddrParts[1]) 704 cli.api.Accept(addr, ls...) 705 } 706 707 return hosts, nil 708 } 709 710 func createAndStartCluster(cli *DaemonCli, d *daemon.Daemon) (*cluster.Cluster, error) { 711 name, _ := os.Hostname() 712 713 // Use a buffered channel to pass changes from store watch API to daemon 714 // A buffer allows store watch API and daemon processing to not wait for each other 715 watchStream := make(chan *swarmapi.WatchMessage, 32) 716 717 c, err := cluster.New(cluster.Config{ 718 Root: cli.Config.Root, 719 Name: name, 720 Backend: d, 721 VolumeBackend: d.VolumesService(), 722 ImageBackend: d.ImageService(), 723 PluginBackend: d.PluginManager(), 724 NetworkSubnetsProvider: d, 725 DefaultAdvertiseAddr: cli.Config.SwarmDefaultAdvertiseAddr, 726 RaftHeartbeatTick: cli.Config.SwarmRaftHeartbeatTick, 727 RaftElectionTick: cli.Config.SwarmRaftElectionTick, 728 RuntimeRoot: cli.getSwarmRunRoot(), 729 WatchStream: watchStream, 730 }) 731 if err != nil { 732 return nil, err 733 } 734 d.SetCluster(c) 735 err = c.Start() 736 737 return c, err 738 } 739 740 // validates that the plugins requested with the --authorization-plugin flag are valid AuthzDriver 741 // plugins present on the host and available to the daemon 742 func validateAuthzPlugins(requestedPlugins []string, pg plugingetter.PluginGetter) error { 743 for _, reqPlugin := range requestedPlugins { 744 if _, err := pg.Get(reqPlugin, authorization.AuthZApiImplements, plugingetter.Lookup); err != nil { 745 return err 746 } 747 } 748 return nil 749 } 750 751 func systemContainerdRunning(honorXDG bool) (string, bool, error) { 752 addr := containerddefaults.DefaultAddress 753 if honorXDG { 754 runtimeDir, err := homedir.GetRuntimeDir() 755 if err != nil { 756 return "", false, err 757 } 758 addr = filepath.Join(runtimeDir, "containerd", "containerd.sock") 759 } 760 _, err := os.Lstat(addr) 761 return addr, err == nil, nil 762 } 763 764 // configureDaemonLogs sets the logrus logging level and formatting 765 func configureDaemonLogs(conf *config.Config) error { 766 if conf.LogLevel != "" { 767 lvl, err := logrus.ParseLevel(conf.LogLevel) 768 if err != nil { 769 return fmt.Errorf("unable to parse logging level: %s", conf.LogLevel) 770 } 771 logrus.SetLevel(lvl) 772 } else { 773 logrus.SetLevel(logrus.InfoLevel) 774 } 775 logrus.SetFormatter(&logrus.TextFormatter{ 776 TimestampFormat: jsonmessage.RFC3339NanoFixed, 777 DisableColors: conf.RawLogs, 778 FullTimestamp: true, 779 }) 780 return nil 781 }