docker源码解析(一)dockerd服务的启动

阅读: 评论:0

docker源码解析(一)dockerd服务的启动

docker源码解析(一)dockerd服务的启动

docker源码解析(一)

  • 部分参数默认值
  • main函数入口
  • newDaemonCommand()函数
  • runDaemon()函数
    • Windows平台
    • linux平台
  • daemonCli.start()函数
  • newDaemon()函数
  • containerd.New()
  • volumesservice.NewVolumeService()

本文源码基于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)/

main函数入口

代码位置:/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。

newDaemonCommand()函数

代码路径:/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()函数。

runDaemon()函数

Windows平台

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
}

linux平台

代码路径:/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()函数。

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实例。

newDaemon()函数

代码路径:moby/:Line:738
调用位置:

注意事项:

  1. 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
}

containerd.New()

github/containerd/:Line-79:New()
调用位置:docker/docker/:Line-926&#ainerdCli, err = containerd.New

docker/docker/:Line-207:restore()
调用位置:docker/docker/:Line-1063&#store()

volumesservice.NewVolumeService()

docker/docker/volume/
调用位置:docker/docker/:Line-972:volumesservice.NewVolumeService()

本文发布于:2024-02-02 15:16:35,感谢您对本站的认可!

本文链接:https://www.4u4v.net/it/170685819644650.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:源码   docker   dockerd
留言与评论(共有 0 条评论)
   
验证码:

Copyright ©2019-2022 Comsenz Inc.Powered by ©

网站地图1 网站地图2 网站地图3 网站地图4 网站地图5 网站地图6 网站地图7 网站地图8 网站地图9 网站地图10 网站地图11 网站地图12 网站地图13 网站地图14 网站地图15 网站地图16 网站地图17 网站地图18 网站地图19 网站地图20 网站地图21 网站地图22/a> 网站地图23