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