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