docker 源码分析 三(基于1.8.2版本),NewDaemon启动

本文来分析一下docker daemon的启动过程;在daemon/daemon.go文件中;

func NewDaemon(config *Config, registryService *registry.Service) (daemon *Daemon, err error) {

setDefaultMtu(config)    //设置默认的MTU,这里的默认值时1500

// Ensure we have compatible configuration options

if err := checkConfigOptions(config); err != nil {

return nil, err

}                               //检查是否出现有冲突的配置,主要有(1)config.Bridge.Iface 与 config.Bridge.IP 这两项配置不能都有,设置一个就可;

//(2) config.Bridge.EnableIPTables 与 config.Bridge.InterContainerCommunication,后者是icc,表示docker容器间是否可以互相通信,

// icc是通过iptables来实现的,即在iptables的FORWARD链中增加规则,所以不能在两者同时为false,但不清楚icc=true,但EntableIPTables为false的时候会怎么样;

// (3) 当config.Bridge.EnableIPTables为false时,config.Bridge.EnableIPMasq,ip伪装功能不能为true,和(2) 一样,因为ip伪装是通过iptables来实现的;

// Do we have a disabled network?

config.DisableBridge = isBridgeNetworkDisabled(config)   // 判断config.Bridge.Iface 与 disableNetworkBridge是否相等,犹豫Iface默认值为空,disableNetworkBridge默认值为none,所以这个config.DisableBridge  为false

// Verify the platform is supported as a daemon

if !platformSupported {

return nil, ErrSystemNotSupported

}                                //在非 linux,freebsd,windows三种os下,这个取为false;

// Validate platform-specific requirements

if err := checkSystem(); err != nil {

return nil, err

}                               //checkSystem主要验证运行docker的进程是否为root,需要root权限;还有包括验证linux kernel的版本;

// set up SIGUSR1 handler on Unix-like systems, or a Win32 global event

// on Windows to dump Go routine stacks

setupDumpStackTrap()    //  用来接收SIGUSR1信号,接收到信号后,将堆栈信息打印出来;通过标准库中signal.Notify()函数来实现;

// get the canonical path to the Docker root directory

var realRoot string

if _, err := os.Stat(config.Root); err != nil && os.IsNotExist(err) {

realRoot = config.Root

} else {

realRoot, err = fileutils.ReadSymlinkedDirectory(config.Root)

if err != nil {

return nil, fmt.Errorf("Unable to get the full path to root (%s): %s", config.Root, err)

}

}                 //获取docker运行时的根路径,后续的流程会在这个根目录下创建各种子目录,默认的是在"/var/lib/docker"路径下;

config.Root = realRoot

// Create the root directory if it doesn‘t exists

if err := system.MkdirAll(config.Root, 0700); err != nil {

return nil, err

}                //如果根路径不存在,那么建立一个;

// set up the tmpDir to use a canonical path

tmp, err := tempDir(config.Root)

if err != nil {

return nil, fmt.Errorf("Unable to get the TempDir under %s: %s", config.Root, err)

}

realTmp, err := fileutils.ReadSymlinkedDirectory(tmp)

if err != nil {

return nil, fmt.Errorf("Unable to get the full path to the TempDir (%s): %s", tmp, err)

}

os.Setenv("TMPDIR", realTmp)    //建立temp文件的存放路径,读取环境变量DOCKER_TMPDIR值,如果没有那么直接在根路径下建立tmp子目录 ,即/var/lib/docker/tmp

// Set the default driver

graphdriver.DefaultDriver = config.GraphDriver  //设立graph driver,graphdriver主要是来管理镜像,以及镜像与镜像之间关系的实现方法。

// Load storage driver

driver, err := graphdriver.New(config.Root, config.GraphOptions)

if err != nil {

return nil, fmt.Errorf("error initializing graphdriver: %v", err)

}

logrus.Debugf("Using graph driver %s", driver)

//设立graph driver,graphdriver主要是来管理镜像,以及镜像与镜像之间关系的实现方法。由于config.GraphDriver的默认值为空,所以主要的处理流程在graphdriver.New()中;

//加载的优先级的顺序为 priority = []string{"aufs","btrfs","zfs","devicemapper","overlay","vfs"},

d := &Daemon{}

d.driver = driver

// Ensure the graph driver is shutdown at a later point

defer func() {

if err != nil {

if err := d.Shutdown(); err != nil {

logrus.Error(err)

}

}

}()

// Verify logging driver type

if config.LogConfig.Type != "none" {

if _, err := logger.GetLogDriver(config.LogConfig.Type); err != nil {

return nil, fmt.Errorf("error finding the logging driver: %v", err)

}

}              //进行log driver的配置,默认的log driver 是json-file, 在deamon/logger 目录下是各种log driver,包括: fluentd,syslogd,journald, gelf等(前三种了解,gelf不太知道 https://www.graylog.org/resources/gelf/)

logrus.Debugf("Using default logging driver %s", config.LogConfig.Type)

// Configure and validate the kernels security support

if err := configureKernelSecuritySupport(config, d.driver.String()); err != nil {

return nil, err

}            //设置系统是否使用SELinux,SElinux有个问题是不能和btrfs的graphdriver一起使用;

daemonRepo := filepath.Join(config.Root, "containers")

if err := system.MkdirAll(daemonRepo, 0700); err != nil {

return nil, err            //创建容器的存储目录,在根目录下创建container子目录,/var/log/docker/container

// Migrate the container if it is aufs and aufs is enabled

if err := migrateIfDownlevel(d.driver, config.Root); err != nil {

return nil, err

}            // 将可能存在的老版本docker中image和container的存储形式迁移到新版本的docker中的存储形式;

logrus.Debug("Creating images graph")

g, err := graph.NewGraph(filepath.Join(config.Root, "graph"), d.driver)

if err != nil {

return nil, err

}           //使用driver实例化一个NewGraph对象,这个管理文件系统的镜像 以及 文件系统之间的关系;

// Configure the volumes driver

volStore, err := configureVolumes(config)

if err != nil {

return nil, err

}                                //设置数据卷driver,数据卷是docker容器之间进行数据共享的一种手段;数据卷可以是一个本机命令(通过-v 标识挂载在到容器的某个目录下)

//数据卷也可以作为数据卷容器,通过--volumes-from挂载到某个容器中;

trustKey, err := api.LoadOrCreateTrustKey(config.TrustKeyPath)

if err != nil {

return nil, err

}                          //创建key,路径在/etc/docker/key.json

trustDir := filepath.Join(config.Root, "trust")

if err := system.MkdirAll(trustDir, 0700); err != nil {

return nil, err

}

trustService, err := trust.NewStore(trustDir)

if err != nil {

return nil, fmt.Errorf("could not create trust store: %s", err)

}   // 创建trustService ,用于提供验证服务;

eventsService := events.New()

logrus.Debug("Creating repository list")

tagCfg := &graph.TagStoreConfig{

Graph:    g,

Key:      trustKey,

Registry: registryService,

Events:   eventsService,

Trust:    trustService,

}

repositories, err := graph.NewTagStore(filepath.Join(config.Root, "repositories-"+d.driver.String()), tagCfg)

if err != nil {

return nil, fmt.Errorf("Couldn‘t create Tag store repositories-%s: %s", d.driver.String(), err)

}         //TagStore是用来存储镜像的仓库列表,

if restorer, ok := d.driver.(graphdriver.ImageRestorer); ok {

if _, err := restorer.RestoreCustomImages(repositories, g); err != nil {

return nil, fmt.Errorf("Couldn‘t restore custom images: %s", err)

}

}

d.netController, err = initNetworkController(config)

if err != nil {

return nil, fmt.Errorf("Error initializing network controller: %v", err)

}    //初始化docker网络环境;

graphdbPath := filepath.Join(config.Root, "linkgraph.db")

graph, err := graphdb.NewSqliteConn(graphdbPath)

if err != nil {

return nil, err

}     //graphdb是一个图数据,纪录的是镜像与镜像之间的关系;

d.containerGraph = graph

var sysInitPath string

if config.ExecDriver == "lxc" {

initPath, err := configureSysInit(config)

if err != nil {

return nil, err

}

sysInitPath = initPath

}

sysInfo := sysinfo.New(false)

// Check if Devices cgroup is mounted, it is hard requirement for container security,

// on Linux/FreeBSD.

if runtime.GOOS != "windows" && !sysInfo.CgroupDevicesEnabled {

return nil, fmt.Errorf("Devices cgroup isn‘t mounted")

}

ed, err := execdrivers.NewDriver(config.ExecDriver, config.ExecOptions, config.ExecRoot, config.Root, sysInitPath, sysInfo)

if err != nil {

return nil, err

}   // execdriver 是使用docker容器的执行驱动,由execdriver执行容器的创建和运行等,通过调用cgroup,usernamespace等等实现;

d.ID = trustKey.PublicKey().KeyID()

d.repository = daemonRepo

d.containers = &contStore{s: make(map[string]*Container)}

d.execCommands = newExecStore()

d.graph = g

d.repositories = repositories

d.idIndex = truncindex.NewTruncIndex([]string{})

d.config = config

d.sysInitPath = sysInitPath

d.execDriver = ed

d.statsCollector = newStatsCollector(1 * time.Second)

d.defaultLogConfig = config.LogConfig

d.RegistryService = registryService

d.EventsService = eventsService

d.volumes = volStore

d.root = config.Root

go d.execCommandGC()

if err := d.restore(); err != nil {

return nil, err

}

return d, nil
}

时间: 2024-11-01 00:17:27

docker 源码分析 三(基于1.8.2版本),NewDaemon启动的相关文章

docker 源码分析 一(基于1.8.2版本),docker daemon启动过程;

最近在研究golang,也学习一下比较火的开源项目docker的源代码,国内比较出名的docker源码分析是孙宏亮大牛写的一系列文章,但是基于的docker版本有点老:索性自己就git 了一下最新的代码研读: docker是c/s的架构,分为docker client 和 docker daemon,client端发送命令,daemon端负责完成client发送过来的命令(如获取和存储镜像.管理容器等).两者之间可以通过TCP,HTTP和UNIX SOCKET来进行通信: docker的启动入口

docker 源码分析 四(基于1.8.2版本),Docker镜像的获取和存储

前段时间一直忙些其他事情,docker源码分析的事情耽搁了,今天接着写,上一章了解了docker client 和 docker daemon(会启动一个http server)是C/S的结构,client端发出的命令由docker daemon接收并处理. 我们在运行docker的时候,可能会使用到docker run命令(当然通过Dockerfile运行docker build命令也是一样的)时,如果本地没有你需要的镜像,docker daemon首先会去下载你需要的docker镜像,然后存

Docker源码分析(三):Docker Daemon启动

1 前言 Docker诞生以来,便引领了轻量级虚拟化容器领域的技术热潮.在这一潮流下,Google.IBM.Redhat等业界翘楚纷纷加入Docker阵营.虽然目前Docker仍然主要基于Linux平台,但是Microsoft却多次宣布对Docker的支持,从先前宣布的Azure支持Docker与Kubernetes,到如今宣布的下一代Windows Server原生态支持Docker.Microsoft的这一系列举措多少喻示着向Linux世界的妥协,当然这也不得不让世人对Docker的巨大影响

Docker源码分析(一):Docker架构

[编者按]在<深入浅出Docker>系列文章的基础上,InfoQ推出了<Docker源码分析>系列文章.<深入浅出Docker>系列文章更多的是从使用角度出发,帮助读者了解Docker的来龙去脉,而<Docker源码分析>系列文章通过分析解读Docker源码,来让读者了解Docker的内部实现,以更好的使用Docker.总之,我们的目标是促进Docker在国内的发展以及传播.另外,欢迎加入InfoQ Docker技术交流群,QQ群号:272489193. 1

Docker源码分析(五):Docker Server的创建

1.Docker Server简介 Docker架构中,Docker Server是Docker Daemon的重要组成部分.Docker Server最主要的功能是:接受用户通过Docker Client发送的请求,并按照相应的路由规则实现路由分发. 同时,Docker Server具备十分优秀的用户友好性,多种通信协议的支持大大降低Docker用户使用Docker的门槛.除此之外,Docker Server设计实现了详尽清晰的API接口,以供Docker用户选择使用.通信安全方面,Docke

Docker源码分析(八):Docker Container网络(下)

1.Docker Client配置容器网络模式 Docker目前支持4种网络模式,分别是bridge.host.container.none,Docker开发者可以根据自己的需求来确定最适合自己应用场景的网络模式. 从Docker Container网络创建流程图中可以看到,创建流程第一个涉及的Docker模块即为Docker Client.当然,这也十分好理解,毕竟Docker Container网络环境的创建需要由用户发起,用户根据自身对容器的需求,选择网络模式,并将其通过Docker Cl

Docker源码分析(四):Docker Daemon之NewDaemon实现

1. 前言 Docker的生态系统日趋完善,开发者群体也在日趋庞大,这让业界对Docker持续抱有极其乐观的态度.如今,对于广大开发者而言,使用Docker这项技术已然不是门槛,享受Docker带来的技术福利也不再是困难.然而,如何探寻Docker适应的场景,如何发展Docker周边的技术,以及如何弥合Docker新技术与传统物理机或VM技术的鸿沟,已经占据Docker研究者们的思考与实践. 本文为<Docker源码分析>第四篇——Docker Daemon之NewDaemon实现,力求帮助广

Docker源码分析(二):Docker Client创建与命令执行

1. 前言 如今,Docker作为业界领先的轻量级虚拟化容器管理引擎,给全球开发者提供了一种新颖.便捷的软件集成测试与部署之道.在团队开发软件时,Docker可以提供可复用的运行环境.灵活的资源配置.便捷的集成测试方法以及一键式的部署方式.可以说,Docker的优势在简化持续集成.运维部署方面体现得淋漓尽致,它完全让开发者从持续集成.运维部署方面中解放出来,把精力真正地倾注在开发上. 然而,把Docker的功能发挥到极致,并非一件易事.在深刻理解Docker架构的情况下,熟练掌握Docker C

Docker源码分析(九):Docker镜像

1.前言 回首过去的2014年,大家可以看到Docker在全球刮起了一阵又一阵的“容器风”,工业界对Docker的探索与实践更是一波高过一波.在如今的2015年以及未来,Docker似乎并不会像其他昙花一现的技术一样,在历史的舞台上热潮褪去,反而在工业界实践与评估之后,显现了前所未有的发展潜力. 究其本质,“Docker提供容器服务”这句话,相信很少有人会有异议.那么,既然Docker提供的服务属于“容器”技术,那么反观“容器”技术的本质与历史,我们又可以发现什么呢?正如前文所提到的,Docke