本文源码基于docker20.10.8。文中机器安装的docker代码版本为docker20.10.0。
本文的计算机环境是centos-8。因此,不介绍Windows平台的docker。
docker源码地址
参考文献
1. docker的初始化——by lovenashbest-简书
Docker - NewDaemon源码分析——by ETIN-知乎
docker 源码分析NewDaemon 函数——by arwen_spy-博客园
Config.Root /var/lib/docker
Config.ExecRoot /var/run/docker
Config.Pidfile /var/run/docker.pid
imageRoot /var/lib/docker/image/文件系统(linux为overlay2)/
代码位置:/moby/cmd/:
func main() {if reexec.Init() {return}// initial log formatting; this setting is updated after the daemon configuration is loaded.logrus.SetFormatter(&logrus.TextFormatter{TimestampFormat: jsonmessage.RFC3339NanoFixed,FullTimestamp: true,})// Set terminal emulation based on platform as required._, stdout, stderr := term.StdStreams()initLogging(stdout, stderr)onError := func(err error) {fmt.Fprintf(stderr, "%sn", err)os.Exit(1)}cmd, err := newDaemonCommand()if err != nil {onError(err)}cmd.SetOutput(stdout)if err := cmd.Execute(); err != nil {onError(err)}
}
首先判断reexec.Init()方法的返回值,如果是真,则直接退出运行,否则继续执行。由于在docker运行之前,没有任何initializer注册,所以这段代码执行的返回值为假。
随后调用newDaemonCommand()函数,启动Daemon。
代码路径:/moby/cmd/
func newDaemonCommand() (*cobra.Command, error) {opts := newDaemonOptions(config.New())cmd := &cobra.Command{Use: "dockerd [OPTIONS]",Short: "A self-sufficient runtime for containers.",SilenceUsage: true,SilenceErrors: true,Args: cli.NoArgs,RunE: func(cmd *cobra.Command, args []string) error {opts.flags = cmd.Flags()return runDaemon(opts)},DisableFlagsInUseLine: true,Version: fmt.Sprintf("%s, build %s", dockerversion.Version, dockerversion.GitCommit),}cli.SetupRootCommand(cmd)flags := cmd.Flags()flags.BoolP("version", "v", false, "Print version information and quit")defaultDaemonConfigFile, err := getDefaultDaemonConfigFile()if err != nil {return nil, err}flags.StringVar(&figFile, "config-file", defaultDaemonConfigFile, "Daemon configuration file")opts.InstallFlags(flags)if err := installConfigFlags(opts.daemonConfig, flags); err != nil {return nil, err}installServiceFlags(flags)return cmd, nil
}
首先调用newDaemonOptions()创建flag参数。
然后调用runDaemon()函数。
Windows平台,代码路径:/moby/cmd/dockerd/
func runDaemon(opts *daemonOptions) error {daemonCli := NewDaemonCli()// On Windows, this may be launching as a service or with an option to// register the service.stop, runAsService, err := initService(daemonCli)if err != nil {logrus.Fatal(err)}if stop {return nil}// Windows specific settings as these are not defaulted.figFile == "" {figFile = filepath.Join(opts.daemonConfig.Root, `configdaemon.json`)}if runAsService {// If Windows SCM manages the service - no need for PID filesopts.daemonConfig.Pidfile = ""} else if opts.daemonConfig.Pidfile == "" {opts.daemonConfig.Pidfile = filepath.Join(opts.daemonConfig.Root, "docker.pid")}err = daemonCli.start(opts)notifyShutdown(err)return err
}
代码路径:/moby/cmd/dockerd/
func runDaemon(opts *daemonOptions) error {daemonCli := NewDaemonCli()return daemonCli.start(opts)
}
代码路径:/moby/cmd/
首先调用NewDaemonCli()申请了一个结构体实例。
// NewDaemonCli returns a daemon CLI
func NewDaemonCli() *DaemonCli {return &DaemonCli{}
}
随后调用start()函数。
代码路径:/moby/cmd/
func (cli *DaemonCli) start(opts *daemonOptions) (err error) {opts.SetDefaultOptions(opts.flags) //TLS加密配置loadDaemonCliConfig(opts) //配置docker信息configureDaemonLogs(cli.Config) //日志等级配置setDefaultUmask() //设置umask默认权限0022,对应文件目录权限为0755->即用户具有读/写/执行权限,组用户和其它用户具有读写权限;// Create the daemon root before we create ANY other files (PID, or migrate keys)// to ensure the appropriate ACL is set (particularly relevant on Windows)daemon.CreateDaemonRoot(cli.Config) //创建root路径system.MkdirAll(cli.Config.ExecRoot, 0700)// 创建exec进去的路径pf, err := pidfile.New(cli.Pidfile) //process IDif cli.Config.IsRootless() {// Set sticky bit if XDG_RUNTIME_DIR is set && the file is actually under XDG_RUNTIME_DIRStickRuntimeDirContents(potentiallyUnderRuntimeDir)//设置XDR_runtime路径newAPIServerConfig(cli) //设置APIserver配置apiserver.New(serverConfig) //创建一个apiserver对象loadListeners(cli, serverConfig) //配置监听hosts//默认的host// tcp://127.0.0.1:2376 TLS// tcp://127:0.0.1:2375 HTTP(没有使用)// unix://runtime目录/var/run/docker.sock linux如果不使用TLS,使用这个,需要获取runtime目录。// unix:///var/run/docker.sock Windows如果不使用TLS,则使用这个context.WithCancel(context.Background()) //cli.initContainerD(ctx) //初始化containerddefer waitForContainerDShutdown(10 * time.Second) //退出以后,10s时间内没有响应则强制结束。// Notify that the API is active, but before daemon is set up.preNotifySystem() //函数空?pluginStore := plugin.NewStore() //创建plugin仓库。插件仓库cli.initMiddlewares(cli.api, serverConfig, pluginStore)////docker-experimental//docker version//配置为每个请求添加的cors头。//authorization middleware//重点!!!daemon.NewDaemon(ctx, cli.Config, pluginStore) //通过config, registry, containerd, pluginStore来真正创建了daemond.StoreHosts(hosts) //127.0.0.1:2376等一系列。//把定义的host map数据结构中的value值设置为true,表示开始监听。// validate after NewDaemon has restored enabled plugins. Don't change order.validateAuthzPlugins(cli.Config.AuthorizationPlugins, pluginStore)//cli.d = dcli.startMetricsServer(cli.Config.MetricsAddress) //metrics地址//对应daemon.json文件中的key值为:"metrics-addr"//需要在experiment模式下才能使用。//不懂这个地址是用来干什么的。createAndStartCluster(cli, d) //创建并开始cluster//swarm// Restart all autostart containers which has a swarm endpoint// and is not yet running now that we have successfully// initialized the cluster.d.RestartSwarmContainers() //重启swarm容器。//重新启动所有具有swarm端点并且在我们成功初始化集群后尚未运行的autostart容器。newRouterOptions(cli.Config, d) //配置router//不懂initRouter(routerOptions) //初始化router//不懂// ProcessClusterNotifications gets changes from store and add them to event listgo d.ProcessClusterNotifications(ctx, c.GetWatchStream())//处理cluster集群信号。//ProcessClusterNotifications从存储中获取更改并将其添加到事件列表中cli.setupConfigReloadTrap() //SIGHUP信号的时候,reload config。// The serve API routine never exits unless an error occurs// We need to start it as a goroutine and wait on it so// daemon doesn't exitserveAPIWait := make(chan error)go cli.api.Wait(serveAPIWait) //API server 开始监听// after the daemon is done setting up we can notify systemd apinotifySystem() //空函数?// Daemon is fully initialized and handling API traffic// Wait for serve API to completeerrAPI := <-serveAPIWaitc.Cleanup()shutdownDaemon(d)// Stop notification processing and any background processescancel()if errAPI != nil {return errors.Wrap(errAPI, "shutting down due to ServeAPI error")}logrus.Info("Daemon shutdown complete")return nil
}
在start()函数里,首先在函数loadDaemonCliConfig()中,(在此之前会调用config包,在该包中会调用func installConfigFlags()函数。),读取cli客户端发出来的设置信息,其中包括docker运行时所使用的的root目录(getDaemonConfDir()函数),root用户默认是/etc/docker。随后调用CreateDaemonRoot(),将docker运行时所使用的root目录设置为/etc/docker。
随后调用NewDaemon()函数创建daemon实例。
代码路径:moby/:Line:738
调用位置:
注意事项:
- daemon在与containerd的通信过程采用grpc。
// NewDaemon sets up everything for the daemon to be able to service
// requests from the webserver.
func NewDaemon(ctx context.Context, config *config.Config, pluginStore *plugin.Store) (daemon *Daemon, err error) {setDefaultMtu(config) //设置默认的MTU。默认Mtu为1500registry.NewService(config.ServiceOptions) //生成registry Service实例。// Ensure that we have a correct root key limit for launching containers.ModifyRootKeyLimit() //和能启动的容器数量有关//ModifyRootKeyLimit检查根密钥限制是否设置为至少1000000,并将其与分配给密钥的maxbytes一起以25:1的倍率更改为该限制。//不懂// Ensure we have compatible and valid configuration optionsverifyDaemonSettings(config) //配置信息校验// Do we have a disabled network?isBridgeNetworkDisabled(config) //判断网桥是否禁用// Setup f//如果未指定,setupResolvConf将设置相应的f文件。//当systemd resolved运行时,默认的/f指向localhost。在本例中,获取位于不同路径中的备用配置文件,以便容器可以使用它。//在所有其他情况下,返回默认值。setupResolvConf(config) //设置f配置文件位置,默认是/f// Verify the platform is supported as a daemonif !platformSupported { //检查系统是否支持 - platformSupported 为系统常量。在代码中为常量truereturn nil, errSystemNotSupported}// Validate platform-specific requirementsif err := checkSystem(); err != nil { //系统平台校验,内核版本是否满足要求//docker 1.11以上不再支持3.4以下的内核版本。return nil, err}setupRemappedRoot(config) //将容器内的用户映射为宿主机上的普通用户。idMapping.RootPair() //创建根uid,gid//上面两个语句完成映射。没看懂源码setupDaemonProcess(config) // daemon进程其他设置:设置OOM Killer和MayDetachMounts// set up the tmpDir to use a canonical pathprepareTempDir(config.Root, rootIDs) //准备临时文件夹//prepareTempDir准备并返回用于临时文件的默认目录。如果它不存在,则创建它。如果存在,则删除其内容。fileutils.ReadSymlinkedDirectory(tmp) //给tmp临时文件夹创建一个符号链接。//ReadSymlinkedDirectory返回符号链接的目标目录。//符号链接的目标可能不是文件。if runtime.GOOS == "windows" {if _, err := os.Stat(realTmp); err != nil && os.IsNotExist(err) {if err := system.MkdirAll(realTmp, 0700); err != nil {return nil, fmt.Errorf("Unable to create the TempDir (%s): %s", realTmp, err)}}os.Setenv("TEMP", realTmp)os.Setenv("TMP", realTmp)} else {os.Setenv("TMPDIR", realTmp)}d := &Daemon{configStore: config,PluginStore: pluginStore,startupDone: make(chan struct{}),}// Ensure the daemon is properly shutdown if there is a failure during// initializationdefer func() {if err != nil {if err := d.Shutdown(); err != nil {logrus.Error(err)}}}()if err := d.setGenericResources(config); err != nil {return nil, err}// set up SIGUSR1 handler on Unix-like systems, or a Win32 global event// on Windows to dump Go routine stacksstackDumpDir := config.Rootif execRoot := config.GetExecRoot(); execRoot != "" {stackDumpDir = execRoot}//Root directory for execution state files//execRoot是执行状态文件的根目录d.setupDumpStackTrap(stackDumpDir) //配置docker的goroutine堆栈输出目录。注册SIGUSR1信号。//在这个函数内注册的USR1信号,所以可以使用在命令行使用 kill -s USR1 $(pidof dockerd)来调取docker运行堆栈信息。//如果execRoot不为空,则在execRoot目录下。(默认execRoot是/var/run/docker)//如果execRoot为空,则在Root目录下。(默认Root是/var/lib/docker)d.setupSeccompProfile() //设置linux内核的Seccomp,用于限制系统调用//没懂// Set the default isolation mode (only applicable on Windows)d.setDefaultIsolation()//设置默认隔离模式,仅windows下使用configureMaxThreads(config) //linux下面设置最大线程 /proc/sys/kernel/threads-max// ensureDefaultAppArmorProfile does nothing if apparmor is disabledensureDefaultAppArmorProfile() //代码中直接return nil?// 如果linux内核支持安全模块AppArmor(AppArmor允许系统管理员将每个程序与一个安全配置文件关联,从而限制程序的功能。//简单的说,AppArmor是与SELinux类似的一个访问控制系统,通过它你可以指定程序可以读、写或运行哪些文件,是否可以打开网络端口等。),则判定是否加载,如加载则设置默认的profiledaemonRepo := filepath.Join(config.Root, "containers")idtools.MkdirAllAndChown(daemonRepo, 0700, rootIDs)//创建/var/lib/docker/containers// Create the directory where we'll store the runtime scripts (i.e. in// order to support runtimeArgs)daemonRuntimes := filepath.Join(config.Root, "runtimes")system.MkdirAll(daemonRuntimes, 0700) //创建/var/lib/docker/runtimes//创建存储运行时脚本的目录(即为了支持runtimeArgs)d.loadRuntimes() //初始化runtime//windows系统中创建credentialspecs目录if runtime.GOOS == "windows" {if err := system.MkdirAll(filepath.Join(config.Root, "credentialspecs"), 0); err != nil {return nil, err}}// On Windows we don't support the environment variable, or a user supplied graphdriver// as Windows has no choice in terms of which graphdrivers to use. It's a case of// running Windows containers on Windows - windowsfilter, running Linux containers on Windows,// lcow. Unix platforms however run a single graphdriver for all containers, and it can// be set through an environment variable, a daemon start parameter, or chosen through// initialization of the layerstore through driver priority order for aphDrivers = make(map[string]string)layerStores := make(map[string]layer.Store)if runtime.GOOS == "windows" {d.graphDrivers[runtime.GOOS] = "windowsfilter"//判断windows是否支持LCOW容器if system.LCOWSupported() {d.graphDrivers["linux"] = "lcow"}} else { //linuxdriverName := os.Getenv("DOCKER_DRIVER")//设置graphdriverif driverName == "" {driverName = config.GraphDriver} else {logrus.Infof("Setting the storage driver from the $DOCKER_DRIVER environment variable (%s)", driverName)}d.graphDrivers[runtime.GOOS] = driverName // May still be empty. Layerstore init determines instead.}d.RegistryService = registryServicelogger.RegisterPluginGetter(d.PluginStore) //插件仓库//不懂d.listenMetricsSock() //监听metrics.sock//位置在 execRoot/metrics.sock// 详见: mount.Mount(sockPath, pluginSockPath, "none", "bind,ro")registerMetricsPluginCallback(d.PluginStore, metricsSockPath)// 没看懂//以下为grpcgopts := []grpc.DialOption{grpc.WithInsecure(),grpc.WithBackoffMaxDelay(3 * time.Second),grpc.WithDialer(dialer.Dialer),// TODO(stevvooe): We may need to allow configuration of this on pc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(defaults.DefaultMaxRecvMsgSize)),grpc.WithDefaultCallOptions(grpc.MaxCallSendMsgSize(defaults.DefaultMaxSendMsgSize)),}//创建containerdCliif config.ContainerdAddr != "" {d.containerdCli, err = containerd.New(config.ContainerdAddr, containerd.WithDefaultNamespace(config.ContainerdNamespace), containerd.WithDialOpts(gopts), containerd.WithTimeout(60*time.Second))if err != nil {return nil, errors.Wrapf(err, "failed to dial %q", config.ContainerdAddr)}}//创建pluginExeccreatePluginExec := func(m *plugin.Manager) (plugin.Executor, error) {var pluginCli *containerd.Client// Windows is not currently using containerd, keep the// client as nilif config.ContainerdAddr != "" {pluginCli, err = containerd.New(config.ContainerdAddr, containerd.WithDefaultNamespace(config.ContainerdPluginNamespace), containerd.WithDialOpts(gopts), containerd.WithTimeout(60*time.Second))if err != nil {return nil, errors.Wrapf(err, "failed to dial %q", config.ContainerdAddr)}}return pluginexec.New(ctx, getPluginExecRoot(config.Root), pluginCli, config.ContainerdPluginNamespace, m)}//创建插件管理器// Plugin system initialization should happen before restore. Do not change order.d.pluginManager, err = plugin.NewManager(plugin.ManagerConfig{Root: filepath.Join(config.Root, "plugins"),ExecRoot: getPluginExecRoot(config.Root),Store: d.PluginStore,CreateExecutor: createPluginExec,RegistryService: registryService,LiveRestoreEnabled: config.LiveRestoreEnabled,LogPluginEvent: d.LogPluginEvent, // todo: make privateAuthzMiddleware: config.AuthzMiddleware,})d.setupDefaultLogConfig() //设置默认日志信息//下面一大段都是在创建graphDrivers//首先,从config中读取GraphDriver。默认配置文件中,GraphDriver为空,GraphOptions也为空。//其次,如果是空,则从环境变量DOCKER_DRIVER中读取grapDriver。//最后,如果用户没有配置环境变量的DOCKER_DRIVER。则遍历系统的优先级存储系统//linux中,priority = "btrfs,zfs,overlay2,aufs,overlay,devicemapper,vfs"//windows中,priority = "windowsfilter"//以上内容在newstoreFromOptions中的New函数中实现的。//从driverStore创建layerStore。for operatingSystem, gd := aphDrivers {layerStores[operatingSystem], err = layer.NewStoreFromOptions(layer.StoreOptions{Root: config.Root,MetadataStorePathTemplate: filepath.Join(config.Root, "image", "%s", "layerdb"),GraphDriver: gd,GraphDriverOptions: config.GraphOptions,IDMapping: idMapping,PluginGetter: d.PluginStore,ExperimentalEnabled: config.Experimental,OS: operatingSystem,})if err != nil {return nil, err}// As layerstore initialization may set aphDrivers[operatingSystem] = layerStores[operatingSystem].DriverName()}//不懂为什么是overlay2而不是btrfs。// Configure and validate the kernels security support. Note this is a Linux/FreeBSD// operation only, so it is safe to pass *just* the runtime figureKernelSecuritySupport(config, d.graphDrivers[runtime.GOOS])//配置并验证内核安全支持。注意,这只是一个Linux/FreeBSD操作,因此传递*只是*运行时OS graphdriver是安全的。//创建image根目录。/var/lib/docker/imageimageRoot := filepath.Join(config.Root, "image", d.graphDrivers[runtime.GOOS])//创建imagedb目录。/var/lib/docker/image/imagedb//imagedb目录是镜像数据库//.NewFSStoreBackend(filepath.Join(imageRoot, "imagedb")) //创建仓库后端的文件系统lgrMap := make(map[string]image.LayerGetReleaser)for os, ls := range layerStores {lgrMap[os] = ls}//在 imagedb 目录下新建两个目录,content/sha256和metadata/sha256,存储镜像内容和镜像元数据image.NewImageStore(ifs, lgrMap) //创建镜像仓库实例//配置Volume, local.New 创建目录 /var/lib/docker/volumes// Configure the volumes drivervolumesservice.NewVolumeService(config.Root, d.PluginStore, rootIDs, d) //创建volume drive实例//1.创建pluginstore实例。//2.创建/var/lib/docker/volumes//3.创建/var/lib/docker/volumes/metadata.db(使用go.etcd.io/bbolt库操作的db)这个是volumeStore。//4.返回volumeService实例。包含volumeStore和Store。volumeStore结构体中也有Store结构体。//LoadOrCreateTrustKey尝试在给定路径加载libtrust密钥,否则将生成一个新路径//TODO:这应该更多地使用libtrust.LoadOrCreateTrustKey,这可能需要重构或将此函数移动到libtrust中loadOrCreateTrustKey(config.TrustKeyPath)//加载或者创建key,/etc/docker/key.json//创建trustdir,/var/lib/docker/trusttrustDir := filepath.Join(config.Root, "trust")system.MkdirAll(trustDir, 0700)// We have a single tag/reference store for the daemon globally. However, it's// stored under the graphdriver. On host platforms which only support a single// container OS, but multiple selectable graphdrivers, this means depending on which// graphdriver is chosen, the global reference store is under there. For// platforms which support multiple container operating systems, this is slightly// more problematic as where does the global ref store get located? Fortunately,// for Windows, which is currently the only daemon supporting multiple container// operating systems, the list of graphdrivers available isn't user configurable.// For backwards compatibility, we just put it under the windowsfilter// directory regardless.filepath.Join(imageRoot, `repositories.json`) //创建refstore。位置。/var/lib/docker/image/overlay2/repositories.json//NewReferenceStore创建一个新的引用存储,绑定到一个文件路径,其中引用集以JSON格式序列化。refstore.NewReferenceStore(refStoreLocation) //创建一个新的引用存储,绑定到一个文件路径上。//创建TagStore。用于管理存储镜像的仓库列表,Repositories记录了镜像仓库的映射,referencesByIDCache记录了镜像ID和镜像全名的映射//我们为守护进程全局提供了一个标记/引用存储。//然而,它储存在graphdriver下面。在只支持单个容器操作系统,但支持多个可选graphdriver的主机平台上,这意味着根据选择的graphdriver,全局参考存储在其中。//对于支持多个容器操作系统的平台,这稍微有点问题,因为全局ref存储在哪里?//幸运的是,对于目前唯一支持多容器操作系统的守护进程Windows,可用的GraphDriver列表不是用户可配置的。//为了向后兼容,我们只是将其放在windowsfilter目录下。// NewFSMetadataStore creates a new filesystem-based metadata store.dmetadata.NewFSMetadataStore(filepath.Join(imageRoot, "distribution"))//NewFSMetadataStore创建一个新的基于文件系统的元数据存储。//返回的是文件位置。文件位置在/var/lib/image/overlay2/distribution// Discovery is only enabled when the daemon is launched with an address to advertise. When// initialized, the daemon is registered and we can store the discovery backend as it's read-onlyd.initDiscovery(config) //创建discoveryWatcher实例//与cluster相关。需要cluster的advertiseaddress、clusterOpts和clusterStoure//只有在使用要公布的地址启动守护进程时,才会启用发现。初始化后,将注册守护进程,我们可以将发现后端存储为只读。//不懂sysInfo := sysinfo.New(false) //获取系统信息。存储在sysInfo结构体中//获取系统信息, 包括cgroup、网络配置(网桥/iptables)和linux安全(AppArmor/Seccomp)等// Check if Devices cgroup is mounted, it is hard requirement for container security,// on Linux.//New返回一个新的SysInfo,使用文件系统检测内核支持哪些功能。//如果'quiet'为'false',则每当发生错误或存在错误配置时,日志中将打印警告。//确保linux系统下,支持Cgroupif runtime.GOOS == "linux" && !sysInfo.CgroupDevicesEnabled {return nil, errors.New("Devices cgroup isn't mounted")}//以下大段内容均为赋值和初始化结构体。d.ID = trustKey.PublicKey().KeyID()d.repository = ainers = container.NewMemoryStore()ainersReplica, err = container.NewViewDB(); err != nil {return nil, Commands = exec.NewStore()d.idIndex = truncindex.NewTruncIndex([]string{})d.statsCollector = d.newStatsCollector(1 * time.Second)d.EventsService = events.New()d.root = config.Rootd.idMapping = idMappingd.seccompEnabled = sysInfo.Seccompd.apparmorEnabled = sysInfo.AppArmord.linkIndex = newLinkIndex()// TODO: imageStore, distributionMetadataStore, and ReferenceStore are only// used above to run migration. They could be initialized in ImageService// if migration is called from daemon/images. layerStore might move as well.d.imageService = images.NewImageService(images.ImageServiceConfig{ContainerStore: d.containers,DistributionMetadataStore: distributionMetadataStore,EventsService: d.EventsService,ImageStore: imageStore,LayerStores: layerStores,MaxConcurrentDownloads: *config.MaxConcurrentDownloads,MaxConcurrentUploads: *config.MaxConcurrentUploads,ReferenceStore: rs,RegistryService: registryService,TrustKey: trustKey,})CommandGC() //新建协程清理容器不需要的命令//每5分钟清理一次。d.containerd, err = libcontainerd.NewClient(ctx, d.containerdCli, filepath.Join(config.ExecRoot, "containerd"), config.ContainerdNamespace, d)//创建和daemon相关的容器客户端libcontainerd//重点!!!//起一个新协程来监听事件。//目前看到的事件有://Create,Start,Exit,OOM,ExecAdded,ExecStarted,Paused,Resumned//与GRPC通信获取的event// 从 /var/lib/docker/containers 读取所有目录,下面的文件夹的名字就是容器的id,//存入 containers map[string]*container.Container 信息并注册如 daemon 结构体中。//包括 start remove 操作 containers注册容器。注册信息都在内存中,启动daemon时需要重新进行注册d.restore()close(d.startupDone)// FIXME: this method never returns an errorinfo, _ := d.SystemInfo() //daemon运行的主机的配置信息。engineInfo.WithValues( //配置信息dockerversion.Version,dockerversion.GitCommit,info.Architecture,info.Driver,info.KernelVersion,info.OperatingSystem,info.OSType,info.OSVersion,info.ID,).Set(1)engineCpus.Set(float64(info.NCPU))engineMemory.Set(float64(info.MemTotal))gd := ""for os, driver := aphDrivers {if len(gd) > 0 {gd += ", "}gd += driverif aphDrivers) > 1 {gd = fmt.Sprintf("%s (%s)", gd, os)}}logrus.WithFields(logrus.Fields{"version": dockerversion.Version,"commit": dockerversion.GitCommit,"graphdriver(s)": gd,}).Info("Docker daemon")return d, nil
}
github/containerd/:Line-79:New()
调用位置:docker/docker/:Line-926ainerdCli, err = containerd.New
docker/docker/:Line-207:restore()
调用位置:docker/docker/:Line-1063store()
docker/docker/volume/
调用位置:docker/docker/:Line-972:volumesservice.NewVolumeService()
本文发布于:2024-02-02 15:16:35,感谢您对本站的认可!
本文链接:https://www.4u4v.net/it/170685819644650.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |