docker 源码分析NewDaemon 函数
NewDaemon函数是Daemon初始化时的重要函数,该函数做好了daemon处理消息的准备
setDefaultMtu(config) // 设置默认MTU 1500
ModifyRootKeyLimit() // "/proc/sys/kernel/keys/root_maxkeys" key权限不足的话修改权限
verifyDaemonSettings(config) // 检查配置是否正确,不正确退出
config.DisableBridge = isBridgeNetworkDisabled(config) // conf.BridgeConfig.Iface == config.DisableNetworkBridge
if !platformSupported { // 系统是否支持
return nil, errSystemNotSupported
}
checkSystem() // 检查系统版本等信息
uidMaps, gidMaps, err := setupRemappedRoot(config) // pkg/idtools/idtools.go 根据username、groupname创建两个map
rootUID, rootGID, err := idtools.GetRootUIDGID(uidMaps, gidMaps) // pkg/idtools/idtools.go 创建根uid、gid
setupDaemonProcess(config) // linux 设置 /proc/self/oom_score_adj
tmp, err := tempDir(config.Root, rootUID, rootGID) // 创建tmp文件夹
realTmp, err := fileutils.ReadSymlinkedDirectory(tmp) // pkg/fileutils/fileutils.go 给tmp创建一个symlink
os.Setenv("TMPDIR", realTmp)
d := &Daemon{configStore: config} //创建个daem 实例
defer func() { // 函数退出时 daemon 关闭
if err != nil {
if err := d.Shutdown(); err != nil {
logrus.Error(err)
}
}
}()
d.setupSeccompProfile() // 需要的话创建 seccompProfile
d.setDefaultIsolation() // 只是windows使用,决定 isolation mode
configureMaxThreads(config) // linux 下面设置最大线程 /proc/sys/kernel/threads-max
ensureDefaultAppArmorProfile() // 如果使能 AppArmor ,则加载
daemonRepo := filepath.Join(config.Root, "containers") // 创建一个containers的目录
if err := idtools.MkdirAllAs(daemonRepo, 0700, rootUID, rootGID); err != nil && !os.IsExist(err) {
return nil, err
}
if runtime.GOOS == "windows" { // windows创建credentialspecs的目录
if err := system.MkdirAll(filepath.Join(config.Root, "credentialspecs"), 0); err != nil && !os.IsExist(err) {
return nil, err
}
}
driverName := os.Getenv("DOCKER_DRIVER") // 取环境变量设置值,未设置取配置
if driverName == "" {
driverName = config.GraphDriver
}
d.RegistryService = registryService
d.PluginStore = plugin.NewStore(config.Root) // todo: remove
// Plugin system initialization should happen before restore. Do not change order.
d.pluginManager, err = plugin.NewManager(plugin.ManagerConfig{ // plugin/manager.go 创建plugin manager 实例
Root: filepath.Join(config.Root, "plugins"),
ExecRoot: getPluginExecRoot(config.Root),
Store: d.PluginStore,
Executor: containerdRemote,
RegistryService: registryService,
LiveRestoreEnabled: config.LiveRestoreEnabled,
LogPluginEvent: d.LogPluginEvent, // todo: make private
})
d.layerStore, err = layer.NewStoreFromOptions(layer.StoreOptions{ // lay/layer_store.go 创建graphDriver实例,从driver创建layer仓库的实例
StorePath: config.Root,
MetadataStorePathTemplate: filepath.Join(config.Root, "image", "%s", "layerdb"),
GraphDriver: driverName,
GraphDriverOptions: config.GraphOptions,
UIDMaps: uidMaps,
GIDMaps: gidMaps,
PluginGetter: d.PluginStore,
ExperimentalEnabled: config.Experimental,
})
graphDriver := d.layerStore.DriverName() // 取layer里面的graphDriver
imageRoot := filepath.Join(config.Root, "image", graphDriver)
configureKernelSecuritySupport(config, graphDriver) // linux内核安全支持的配置
d.downloadManager = xfer.NewLayerDownloadManager(d.layerStore, *config.MaxConcurrentDownloads) // distribution/xfer/download.go 创建层下载管理实例
d.uploadManager = xfer.NewLayerUploadManager(*config.MaxConcurrentUploads) // distribution/xfer/upload.go 创建层上传管理实例
ifs, err := image.NewFSStoreBackend(filepath.Join(imageRoot, "imagedb")) // image/fs.go 创建仓库后端的文件系统
d.imageStore, err = image.NewImageStore(ifs, d.layerStore) // image/store.go 创建镜像仓库实例
volStore, err := d.configureVolumes(rootUID, rootGID) // 创建 volumes driver实例
trustKey, err := api.LoadOrCreateTrustKey(config.TrustKeyPath) // api/common.go 按照路径加载libtrust key ,没有就新建一个
trustDir := filepath.Join(config.Root, "trust")
system.MkdirAll(trustDir, 0700)
distributionMetadataStore, err := dmetadata.NewFSMetadataStore(filepath.Join(imageRoot, "distribution")) // distribution/metadata/metadata.go 按照路径创建一个基于文件系统的元数据仓库实例
eventsService := events.New() // daemon/events/events.go 创建event服务实例
referenceStore, err := refstore.NewReferenceStore(filepath.Join(imageRoot, "repositories.json")) // reference/store.go 按照路径创建 reference仓库实例
v1.Migrate(config.Root, graphDriver, d.layerStore, d.imageStore, referenceStore, distributionMetadataStore) // migrate/v1/migrate.go 迁移metadata
d.initDiscovery(config) // 创建 discoveryWatcher 实例
sysInfo := sysinfo.New(false) // 获取系统信息,linux 不支持cgroup则返回
if runtime.GOOS == "linux" && !sysInfo.CgroupDevicesEnabled {
return nil, errors.New("Devices cgroup isn't mounted")
}
d.ID = trustKey.PublicKey().KeyID() // 赋值
d.repository = daemonRepo
d.containers = container.NewMemoryStore()
d.execCommands = exec.NewStore()
d.referenceStore = referenceStore
d.distributionMetadataStore = distributionMetadataStore
d.trustKey = trustKey
d.idIndex = truncindex.NewTruncIndex([]string{})
d.statsCollector = d.newStatsCollector(1 * time.Second)
d.defaultLogConfig = containertypes.LogConfig{
Type: config.LogConfig.Type,
Config: config.LogConfig.Config,
}
d.EventsService = eventsService
d.volumes = volStore
d.root = config.Root
d.uidMaps = uidMaps
d.gidMaps = gidMaps
d.seccompEnabled = sysInfo.Seccomp
d.apparmorEnabled = sysInfo.AppArmor
d.nameIndex = registrar.NewRegistrar()
d.linkIndex = newLinkIndex()
d.containerdRemote = containerdRemote
go d.execCommandGC() // 新建协程清理容器不需要的命令
d.containerd, err = containerdRemote.Client(d) // 创建和daemon相关的容器客户端 libcontainerd
d.restore() // restart container
// FIXME: this method never returns an error
info, _ := d.SystemInfo() // 获取host server系统信息
engineVersion.WithValues(
dockerversion.Version,
dockerversion.GitCommit,
info.Architecture,
info.Driver,
info.KernelVersion,
info.OperatingSystem,
).Set(1)
engineCpus.Set(float64(info.NCPU))
engineMemory.Set(float64(info.MemTotal))
// set up SIGUSR1 handler on Unix-like systems, or a Win32 global event
// on Windows to dump Go routine stacks
stackDumpDir := config.Root
if execRoot := config.GetExecRoot(); execRoot != "" {
stackDumpDir = execRoot
}
d.setupDumpStackTrap(stackDumpDir) // 创建处理系统信号的通道和协程