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  }