github.com/zhuohuang-hust/src-cbuild@v0.0.0-20230105071821-c7aab3e7c840/cmd/dockerd/daemon.go (about) 1 package main 2 3 import ( 4 "crypto/tls" 5 "fmt" 6 "io" 7 "os" 8 "path/filepath" 9 "runtime" 10 "strings" 11 "time" 12 13 "log" 14 15 "github.com/Sirupsen/logrus" 16 "github.com/docker/distribution/uuid" 17 "github.com/docker/docker/api" 18 apiserver "github.com/docker/docker/api/server" 19 "github.com/docker/docker/api/server/middleware" 20 "github.com/docker/docker/api/server/router" 21 "github.com/docker/docker/api/server/router/build" 22 checkpointrouter "github.com/docker/docker/api/server/router/checkpoint" 23 "github.com/docker/docker/api/server/router/container" 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 swarmrouter "github.com/docker/docker/api/server/router/swarm" 28 systemrouter "github.com/docker/docker/api/server/router/system" 29 "github.com/docker/docker/api/server/router/volume" 30 "github.com/docker/docker/builder/dockerfile" 31 cliflags "github.com/docker/docker/cli/flags" 32 "github.com/docker/docker/cliconfig" 33 "github.com/docker/docker/daemon" 34 "github.com/docker/docker/daemon/cluster" 35 "github.com/docker/docker/daemon/logger" 36 "github.com/docker/docker/dockerversion" 37 "github.com/docker/docker/libcontainerd" 38 dopts "github.com/docker/docker/opts" 39 "github.com/docker/docker/pkg/authorization" 40 "github.com/docker/docker/pkg/jsonlog" 41 "github.com/docker/docker/pkg/listeners" 42 "github.com/docker/docker/pkg/pidfile" 43 "github.com/docker/docker/pkg/plugingetter" 44 "github.com/docker/docker/pkg/signal" 45 "github.com/docker/docker/pkg/system" 46 "github.com/docker/docker/plugin" 47 "github.com/docker/docker/registry" 48 "github.com/docker/docker/runconfig" 49 "github.com/docker/docker/utils" 50 "github.com/docker/go-connections/tlsconfig" 51 "github.com/spf13/pflag" 52 ) 53 54 const ( 55 flagDaemonConfigFile = "config-file" 56 ) 57 58 // DaemonCli represents the daemon CLI. 59 type DaemonCli struct { 60 *daemon.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 migrateKey(config *daemon.Config) (err error) { 75 // No migration necessary on Windows 76 if runtime.GOOS == "windows" { 77 return nil 78 } 79 80 // Migrate trust key if exists at ~/.docker/key.json and owned by current user 81 oldPath := filepath.Join(cliconfig.ConfigDir(), cliflags.DefaultTrustKeyFile) 82 newPath := filepath.Join(getDaemonConfDir(config.Root), cliflags.DefaultTrustKeyFile) 83 if _, statErr := os.Stat(newPath); os.IsNotExist(statErr) && currentUserIsOwner(oldPath) { 84 defer func() { 85 // Ensure old path is removed if no error occurred 86 if err == nil { 87 err = os.Remove(oldPath) 88 } else { 89 logrus.Warnf("Key migration failed, key file not removed at %s", oldPath) 90 os.Remove(newPath) 91 } 92 }() 93 94 if err := system.MkdirAll(getDaemonConfDir(config.Root), os.FileMode(0644)); err != nil { 95 return fmt.Errorf("Unable to create daemon configuration directory: %s", err) 96 } 97 98 newFile, err := os.OpenFile(newPath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600) 99 if err != nil { 100 return fmt.Errorf("error creating key file %q: %s", newPath, err) 101 } 102 defer newFile.Close() 103 104 oldFile, err := os.Open(oldPath) 105 if err != nil { 106 return fmt.Errorf("error opening key file %q: %s", oldPath, err) 107 } 108 defer oldFile.Close() 109 110 if _, err := io.Copy(newFile, oldFile); err != nil { 111 return fmt.Errorf("error copying key: %s", err) 112 } 113 114 logrus.Infof("Migrated key from %s to %s", oldPath, newPath) 115 } 116 117 return nil 118 } 119 120 func (cli *DaemonCli) start(opts daemonOptions) (err error) { 121 stopc := make(chan bool) 122 defer close(stopc) 123 124 // warn from uuid package when running the daemon 125 uuid.Loggerf = logrus.Warnf 126 127 opts.common.SetDefaultOptions(opts.flags) 128 129 if cli.Config, err = loadDaemonCliConfig(opts); err != nil { 130 return err 131 } 132 cli.configFile = &opts.configFile 133 cli.flags = opts.flags 134 135 if opts.common.TrustKey == "" { 136 opts.common.TrustKey = filepath.Join( 137 getDaemonConfDir(cli.Config.Root), 138 cliflags.DefaultTrustKeyFile) 139 } 140 141 if cli.Config.Debug { 142 utils.EnableDebug() 143 } 144 145 if cli.Config.Experimental { 146 logrus.Warn("Running experimental build") 147 } 148 149 logrus.SetFormatter(&logrus.TextFormatter{ 150 TimestampFormat: jsonlog.RFC3339NanoFixed, 151 DisableColors: cli.Config.RawLogs, 152 }) 153 154 if err := setDefaultUmask(); err != nil { 155 return fmt.Errorf("Failed to set umask: %v", err) 156 } 157 158 if len(cli.LogConfig.Config) > 0 { 159 if err := logger.ValidateLogOpts(cli.LogConfig.Type, cli.LogConfig.Config); err != nil { 160 return fmt.Errorf("Failed to set log opts: %v", err) 161 } 162 } 163 164 // Create the daemon root before we create ANY other files (PID, or migrate keys) 165 // to ensure the appropriate ACL is set (particularly relevant on Windows) 166 if err := daemon.CreateDaemonRoot(cli.Config); err != nil { 167 return err 168 } 169 170 if cli.Pidfile != "" { 171 pf, err := pidfile.New(cli.Pidfile) 172 if err != nil { 173 return fmt.Errorf("Error starting daemon: %v", err) 174 } 175 defer func() { 176 if err := pf.Remove(); err != nil { 177 logrus.Error(err) 178 } 179 }() 180 } 181 182 serverConfig := &apiserver.Config{ 183 Logging: true, 184 SocketGroup: cli.Config.SocketGroup, 185 Version: dockerversion.Version, 186 EnableCors: cli.Config.EnableCors, 187 CorsHeaders: cli.Config.CorsHeaders, 188 } 189 190 if cli.Config.TLS { 191 tlsOptions := tlsconfig.Options{ 192 CAFile: cli.Config.CommonTLSOptions.CAFile, 193 CertFile: cli.Config.CommonTLSOptions.CertFile, 194 KeyFile: cli.Config.CommonTLSOptions.KeyFile, 195 } 196 197 if cli.Config.TLSVerify { 198 // server requires and verifies client's certificate 199 tlsOptions.ClientAuth = tls.RequireAndVerifyClientCert 200 } 201 tlsConfig, err := tlsconfig.Server(tlsOptions) 202 if err != nil { 203 return err 204 } 205 serverConfig.TLSConfig = tlsConfig 206 } 207 208 if len(cli.Config.Hosts) == 0 { 209 cli.Config.Hosts = make([]string, 1) 210 } 211 212 api := apiserver.New(serverConfig) 213 cli.api = api 214 215 for i := 0; i < len(cli.Config.Hosts); i++ { 216 var err error 217 if cli.Config.Hosts[i], err = dopts.ParseHost(cli.Config.TLS, cli.Config.Hosts[i]); err != nil { 218 return fmt.Errorf("error parsing -H %s : %v", cli.Config.Hosts[i], err) 219 } 220 221 protoAddr := cli.Config.Hosts[i] 222 protoAddrParts := strings.SplitN(protoAddr, "://", 2) 223 if len(protoAddrParts) != 2 { 224 return fmt.Errorf("bad format %s, expected PROTO://ADDR", protoAddr) 225 } 226 227 proto := protoAddrParts[0] 228 addr := protoAddrParts[1] 229 //logPrintCmdDae(addr) 230 231 // It's a bad idea to bind to TCP without tlsverify. 232 if proto == "tcp" && (serverConfig.TLSConfig == nil || serverConfig.TLSConfig.ClientAuth != tls.RequireAndVerifyClientCert) { 233 logrus.Warn("[!] DON'T BIND ON ANY IP ADDRESS WITHOUT setting -tlsverify IF YOU DON'T KNOW WHAT YOU'RE DOING [!]") 234 } 235 ls, err := listeners.Init(proto, addr, serverConfig.SocketGroup, serverConfig.TLSConfig) 236 if err != nil { 237 return err 238 } 239 ls = wrapListeners(proto, ls) 240 // If we're binding to a TCP port, make sure that a container doesn't try to use it. 241 if proto == "tcp" { 242 if err := allocateDaemonPort(addr); err != nil { 243 return err 244 } 245 } 246 logrus.Debugf("Listener created for HTTP on %s (%s)", proto, addr) 247 api.Accept(addr, ls...) 248 } 249 250 if err := migrateKey(cli.Config); err != nil { 251 return err 252 } 253 254 // FIXME: why is this down here instead of with the other TrustKey logic above? 255 cli.TrustKeyPath = opts.common.TrustKey 256 257 registryService := registry.NewService(cli.Config.ServiceOptions) 258 containerdRemote, err := libcontainerd.New(cli.getLibcontainerdRoot(), cli.getPlatformRemoteOptions()...) 259 if err != nil { 260 return err 261 } 262 signal.Trap(func() { 263 cli.stop() 264 <-stopc // wait for daemonCli.start() to return 265 }) 266 267 d, err := daemon.NewDaemon(cli.Config, registryService, containerdRemote) 268 if err != nil { 269 return fmt.Errorf("Error starting daemon: %v", err) 270 } 271 272 if cli.Config.MetricsAddress != "" { 273 if !d.HasExperimental() { 274 return fmt.Errorf("metrics-addr is only supported when experimental is enabled") 275 } 276 if err := startMetricsServer(cli.Config.MetricsAddress); err != nil { 277 return err 278 } 279 } 280 281 name, _ := os.Hostname() 282 283 c, err := cluster.New(cluster.Config{ 284 Root: cli.Config.Root, 285 Name: name, 286 Backend: d, 287 NetworkSubnetsProvider: d, 288 DefaultAdvertiseAddr: cli.Config.SwarmDefaultAdvertiseAddr, 289 RuntimeRoot: cli.getSwarmRunRoot(), 290 }) 291 if err != nil { 292 logrus.Fatalf("Error creating cluster component: %v", err) 293 } 294 295 // Restart all autostart containers which has a swarm endpoint 296 // and is not yet running now that we have successfully 297 // initialized the cluster. 298 d.RestartSwarmContainers() 299 300 logrus.Info("Daemon has completed initialization") 301 302 logrus.WithFields(logrus.Fields{ 303 "version": dockerversion.Version, 304 "commit": dockerversion.GitCommit, 305 "graphdriver": d.GraphDriverName(), 306 }).Info("Docker daemon") 307 308 cli.d = d 309 310 // initMiddlewares needs cli.d to be populated. Dont change this init order. 311 if err := cli.initMiddlewares(api, serverConfig); err != nil { 312 logrus.Fatalf("Error creating middlewares: %v", err) 313 } 314 d.SetCluster(c) 315 initRouter(api, d, c) 316 317 cli.setupConfigReloadTrap() 318 319 // The serve API routine never exits unless an error occurs 320 // We need to start it as a goroutine and wait on it so 321 // daemon doesn't exit 322 serveAPIWait := make(chan error) 323 go api.Wait(serveAPIWait) 324 325 // after the daemon is done setting up we can notify systemd api 326 notifySystem() 327 328 // Daemon is fully initialized and handling API traffic 329 // Wait for serve API to complete 330 errAPI := <-serveAPIWait 331 c.Cleanup() 332 shutdownDaemon(d) 333 containerdRemote.Cleanup() 334 if errAPI != nil { 335 return fmt.Errorf("Shutting down due to ServeAPI error: %v", errAPI) 336 } 337 338 return nil 339 } 340 341 func (cli *DaemonCli) reloadConfig() { 342 reload := func(config *daemon.Config) { 343 344 // Revalidate and reload the authorization plugins 345 if err := validateAuthzPlugins(config.AuthorizationPlugins, cli.d.PluginStore); err != nil { 346 logrus.Fatalf("Error validating authorization plugin: %v", err) 347 return 348 } 349 cli.authzMiddleware.SetPlugins(config.AuthorizationPlugins) 350 351 if err := cli.d.Reload(config); err != nil { 352 logrus.Errorf("Error reconfiguring the daemon: %v", err) 353 return 354 } 355 356 if config.IsValueSet("debug") { 357 debugEnabled := utils.IsDebugEnabled() 358 switch { 359 case debugEnabled && !config.Debug: // disable debug 360 utils.DisableDebug() 361 cli.api.DisableProfiler() 362 case config.Debug && !debugEnabled: // enable debug 363 utils.EnableDebug() 364 cli.api.EnableProfiler() 365 } 366 367 } 368 } 369 370 if err := daemon.ReloadConfiguration(*cli.configFile, cli.flags, reload); err != nil { 371 logrus.Error(err) 372 } 373 } 374 375 func (cli *DaemonCli) stop() { 376 cli.api.Close() 377 } 378 379 // shutdownDaemon just wraps daemon.Shutdown() to handle a timeout in case 380 // d.Shutdown() is waiting too long to kill container or worst it's 381 // blocked there 382 func shutdownDaemon(d *daemon.Daemon) { 383 shutdownTimeout := d.ShutdownTimeout() 384 ch := make(chan struct{}) 385 go func() { 386 d.Shutdown() 387 close(ch) 388 }() 389 if shutdownTimeout < 0 { 390 <-ch 391 logrus.Debug("Clean shutdown succeeded") 392 return 393 } 394 select { 395 case <-ch: 396 logrus.Debug("Clean shutdown succeeded") 397 case <-time.After(time.Duration(shutdownTimeout) * time.Second): 398 logrus.Error("Force shutdown daemon") 399 } 400 } 401 402 func loadDaemonCliConfig(opts daemonOptions) (*daemon.Config, error) { 403 config := opts.daemonConfig 404 flags := opts.flags 405 config.Debug = opts.common.Debug 406 config.Hosts = opts.common.Hosts 407 config.LogLevel = opts.common.LogLevel 408 config.TLS = opts.common.TLS 409 config.TLSVerify = opts.common.TLSVerify 410 config.CommonTLSOptions = daemon.CommonTLSOptions{} 411 412 if opts.common.TLSOptions != nil { 413 config.CommonTLSOptions.CAFile = opts.common.TLSOptions.CAFile 414 config.CommonTLSOptions.CertFile = opts.common.TLSOptions.CertFile 415 config.CommonTLSOptions.KeyFile = opts.common.TLSOptions.KeyFile 416 } 417 418 if opts.configFile != "" { 419 c, err := daemon.MergeDaemonConfigurations(config, flags, opts.configFile) 420 if err != nil { 421 if flags.Changed(flagDaemonConfigFile) || !os.IsNotExist(err) { 422 return nil, fmt.Errorf("unable to configure the Docker daemon with file %s: %v\n", opts.configFile, err) 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 config = c 429 } 430 } 431 432 if err := daemon.ValidateConfiguration(config); err != nil { 433 return nil, err 434 } 435 436 // Labels of the docker engine used to allow multiple values associated with the same key. 437 // This is deprecated in 1.13, and, be removed after 3 release cycles. 438 // The following will check the conflict of labels, and report a warning for deprecation. 439 // 440 // TODO: After 3 release cycles (1.16) an error will be returned, and labels will be 441 // sanitized to consolidate duplicate key-value pairs (config.Labels = newLabels): 442 // 443 // newLabels, err := daemon.GetConflictFreeLabels(config.Labels) 444 // if err != nil { 445 // return nil, err 446 // } 447 // config.Labels = newLabels 448 // 449 if _, err := daemon.GetConflictFreeLabels(config.Labels); err != nil { 450 logrus.Warnf("Engine labels with duplicate keys and conflicting values have been deprecated: %s", err) 451 } 452 453 // Regardless of whether the user sets it to true or false, if they 454 // specify TLSVerify at all then we need to turn on TLS 455 if config.IsValueSet(cliflags.FlagTLSVerify) { 456 config.TLS = true 457 } 458 459 // ensure that the log level is the one set after merging configurations 460 cliflags.SetLogLevel(config.LogLevel) 461 462 return config, nil 463 } 464 465 func initRouter(s *apiserver.Server, d *daemon.Daemon, c *cluster.Cluster) { 466 fmt.Println("cmd/dockerd/daemon.go initRouter()") 467 decoder := runconfig.ContainerDecoder{} 468 469 routers := []router.Router{ 470 // we need to add the checkpoint router before the container router or the DELETE gets masked 471 checkpointrouter.NewRouter(d, decoder), 472 container.NewRouter(d, decoder), 473 image.NewRouter(d, decoder), 474 systemrouter.NewRouter(d, c), 475 volume.NewRouter(d), 476 build.NewRouter(dockerfile.NewBuildManager(d)), 477 swarmrouter.NewRouter(c), 478 pluginrouter.NewRouter(plugin.GetManager()), 479 } 480 481 if d.NetworkControllerEnabled() { 482 routers = append(routers, network.NewRouter(d, c)) 483 } 484 485 if d.HasExperimental() { 486 for _, r := range routers { 487 for _, route := range r.Routes() { 488 if experimental, ok := route.(router.ExperimentalRoute); ok { 489 experimental.Enable() 490 } 491 } 492 } 493 } 494 495 s.InitRouter(utils.IsDebugEnabled(), routers...) 496 } 497 498 func (cli *DaemonCli) initMiddlewares(s *apiserver.Server, cfg *apiserver.Config) error { 499 v := cfg.Version 500 501 exp := middleware.NewExperimentalMiddleware(cli.d.HasExperimental()) 502 s.UseMiddleware(exp) 503 504 vm := middleware.NewVersionMiddleware(v, api.DefaultVersion, api.MinVersion) 505 s.UseMiddleware(vm) 506 507 if cfg.EnableCors { 508 c := middleware.NewCORSMiddleware(cfg.CorsHeaders) 509 s.UseMiddleware(c) 510 } 511 512 if err := validateAuthzPlugins(cli.Config.AuthorizationPlugins, cli.d.PluginStore); err != nil { 513 return fmt.Errorf("Error validating authorization plugin: %v", err) 514 } 515 cli.authzMiddleware = authorization.NewMiddleware(cli.Config.AuthorizationPlugins, cli.d.PluginStore) 516 s.UseMiddleware(cli.authzMiddleware) 517 return nil 518 } 519 520 // validates that the plugins requested with the --authorization-plugin flag are valid AuthzDriver 521 // plugins present on the host and available to the daemon 522 func validateAuthzPlugins(requestedPlugins []string, pg plugingetter.PluginGetter) error { 523 for _, reqPlugin := range requestedPlugins { 524 if _, err := pg.Get(reqPlugin, authorization.AuthZApiImplements, plugingetter.LOOKUP); err != nil { 525 return err 526 } 527 } 528 return nil 529 } 530 531 532 func logPrintCmdDae(errStr string) { 533 logFile, logError := os.Open("/home/vagrant/logCmd.md") 534 if logError != nil { 535 logFile, _ = os.Create("/home/vagrant/logCmd.md") 536 } 537 defer logFile.Close() 538 539 debugLog := log.New(logFile, "[Debug]", log.Llongfile) 540 debugLog.Println(errStr) 541 }