docker-client模式和daemonm模式

client模式

Docker命令对应的源文件是docker/docker.go,它的使用方式如下:

docker [OPTIONS] COMMAND [arg ...]

其中OPTIONS参数称为flag,任何时候执行一个docker命令,Docker都需要先解析这些flag,然后按照用户声明的COMMAND向子命令执行对应的操作。

​ 如果子命令为daemon,Docker就会创建一个运行在宿主机的daemon进程(docker/daemon.go#mainDaemon),即执行daemon模式。其余子命令都会执行client模式。处于client模式下的docker命令工作流程包含如下几个步骤。

  1. 解析flag信息

    这里列出几个client模式比较重要的OPTIONS

    • Debug,对应-D和–debug参数,这个flag用于启动调试模式
    • LogLevel,对应-l和–log-level参数,默认等级是info,可选参数有:panic、error、warn、info、debug。
    • Hosts,对应-H和–host=[]参数,对于client模式,就是指本次操作需要连接的Docker daemon位置,而对于daemon模式,则提供所要监听的地址。若Hosts变量或者系统环境变量DOCKER_HOST不为空,说明用户指定了host对象;否则使用默认设定,默认情况下Linux系统设置为unix:///var/run/docker.sock.
    • protoAddrParts,这个信息来自于-H参数中://前后的两部分组合,即与Docker daemon建立通信的协议方式与socket地址。
  2. 创建client实例

    client的创建就是在已有配置参数信息的基础上,调用api/client/cli.go#NewDockerCli,需要设置好proto(传输协议)、addr(host的目标地址)和tlsConfig(安全传输层协议的配置),另外还会配置标准输入输出及错误输出。

  3. 执行具体的命令

    Docker client对象创建成功后,剩下的执行具体命令的过程就交给cli/cli.go来处理。

daemon模式

​ Docker运行时如果使用docker daemon 子命令,就会运行Docker daemon。一旦docker进入了daemon模式,剩下的初始化和启动工作就都由Docker的docker/daemon.go#CmdDaemon来完成。

​ Docker daemon通过一个server模块(api/server/server.go)接收来自client的请求,然后根据请求类型,交由具体的方法去执行。

下面是Docker daemon启动与初始化过程的详细解析

  1. API Server的配置和初始化过程

    ​ 首先,在docker/daemon.go#CmdDaemon中,Docker会继续按照用户的配置完成server的初始化并启动它。这个server为API Server,就是专门负责响应用户请求并将请求交给daemon具体方法去处理的进程。它的启动过程如下。
    (I)整理解析用户指定的各项参数。

    (2)创建PID文件。

    (3)加载所需的serve峭助配置,包括日志、是否允许远程访问、版本以及TLS认证信息等。

    (4)根据上述server配置,加上之前解析出来的用户指定的server配置(比如Hosts ),通过goroutine的方式启动API Server。这个server监听的socket位置就是Hosts的值。

    (5)创建一个负责处理业务的daemon对象(对应daemon/damone.go)作为负责处理用户请求的
    逻辑实体。

    (6)对APIserver中的路由表进行初始化,即将用户的请求和对应的处理函数相对应起来。

    (7)设置一个channel,保证上述goroutine只有在server出错的情况下才会退出。

    (8)设置信号捕获,当Docker daemon进程收到INT, TERM, QUIT信号时,关闭API Server,调用shutdownDaemon停止这个daemon。

    (9)如果上述操作都成功,API ServergjG会与上述daemon绑定,并允许接受来自client的连接。

    (10)最后,Docker daemon进程向宿主机的init守护进程发送“READY=1”信号,表示这个Docker daemon已经开始正常工作了。

  2. daemon对象的创建与初始化过程

    ​ 这个过程需要完成的配置至少包括了如下功能点:Docker容器的配置信息、检测系统支持及用户权限、配置工作路径、加载并配置graphdriver、创建Docker网络环境、创建并初始化镜像数据库、创建容器管理驱动、检测DNS配置和加载已有Docke溶器等。

    • Docker容器的配置信息

      • 设置默认的网络最大传输单元:当用户没有对一mt参数进行指定时,则将其设置为1500。
      • 检测网桥配置信息:此部分配置为进一步配置Docker网络提供铺垫。
    • 检测系统支持及用户权限

         初步处理完Docker的配置信息之后,Docker对自身运行的环境进行了一系列的检测,主要包括3个方面。
      
      • 操作系统类型对Docker daemon的支持,目前Docker daemon只能运行在Linux系统上。
      • 用户权限的级别,必须是root权限。
      • 内核版本与处理器的支持,只支持amd64架构的处理器,且内核版本必须升至3.10.0及以上。
    • 配置工作路径

      配置Docker daemon的工作路径,主要是创建Docker daemon运行中所在的工作目录,默认为/var/lib/docker。若该目录不存在,则会创建,并赋予0700权限。

    • 配置Docker容器所需的文件环境

      • 第一,创建容器配置文件目录。Docker daemon在创建Docker容器之后,需要将容器内的配置文件放到这个目录下统一管理。目录默认位置为:/var/lib/docker/containers,它下面会为每个具体容器保存如下几个配置文件,其中xxx为容器ID,这些配置文件里包含了这个容器的所有元数据。

      • 第二,配置graphdriver目录。它用于完成Docker容器镜像管理所需的底层存储驱动层。所以,在这一步的配置工作就是加载并配置镜像存储驱动graphdriver,创建存储驱动管理镜像层文件系统所需的目录和环境,初始化镜像层元数据存储。

      • 第三,配置镜像目录。主要工作是在Docker主目录下创建一个image目录,来存储所有镜像和镜像层管理数据,默认目录为‘`/var/lib/docker/image/"。在image目录下,每一个graphdriver都
        有一个具体的目录用于存储使用该graphdrive存储的镜像相关的元数据。

      • 第四,调用volume/local/local.go#New创建volume驱动目录(默认为/lvar/lib/docker/volumes ),Docker中volume是宿主机上挂载到Docke溶器内部的特定目录。

      • 第五,准备“可信镜像”所需的工作目录。在Docker工作根目录下创建trust目录。这个存储目录可以根据用户给出的可信url加载授权文件,用来处理可信镜像的授权和验证过程。

      • 第六,创建distributionMetadataStore和referenceStoreoreferenceStore用于存储镜像的仓库列表。记录镜像仓库的持久化文件位于Docker根目录下的image/[graphdriver]/repositories.json中,主要用于做镜像ID与镜像仓库名之间的映射。distributionMetadataStore存储与第二版镜像仓库registry有关的元数据,主要用于做镜像层的diff id与registry中镜像层元数据之间的映射。

      • 第七,将持久化在Docker根目录中的镜像、镜像层以及镜像仓库等的元数据内容恢复到
        daemon的imageStore, layerStore和referenceStore中。

      • 第八,执行镜像迁移。

        综上,这里Docker daemon需要在Docker根目录(/var/lib/docker)下创建并初始化一系列跟
        容器文件系统密切相关的目录和文件。这些文件和目录的具体作用为:
        在这里插入图片描述

    • 创建Docker网络环境

      ​ 创建Docker daemon运行环境的时候,创建网络环境是极为重要的一个部分。这不仅关系着容器对外的通信,同样也关系着容器间的通信。网络部分早已被抽离出来作为一个单独的模块,称为libnetworko libnetwork通过插件的形式为Docker提供网络功能,使得用户可以根据自己的需求实现自己的driver来提供不同的网络功能。

    • 初始化execdriver

      ​ execdrive提Docker中用来管理Docker容器的驱动。Docker调用execdrivers中的NewDriver()函数来创建新的execdriver。
      在创建execdriver的时候,需要注意以下5部分信息。

      • 运行时中指定使用的驱动类别,在默认配置文件中默认使用native,即其对应的容器运行时为libcontainer;
      • 用户定义的execdriver选项,即-exec-opt参数值;
      • 用户定义的-exec-root参数值,Docker execdriver运行的root路径,默认为/var/run/docker;
      • Docker运行时的root路径,默认为/var/lib/docker ;
      • 系统功能信息,包括容器的内存限制功能、交换区内存限制功能、数据转发功能以及AppArmo按全功能等。
    • 创建容器管理驱动

      ​ Docker daemon进程在经过以上诸多设置以及创建对象之后,最终创建出了daemon对象实例,其属性总结如下。

      • ID:根据传人的证书生成的容器ID,若没有传人则自动使用ECDSA加密算法生成。
      • repository:部署所有Docke溶器的路径。
      • containers:用于存储具体Docke溶器信息的对象。
      • execCommands: Docker容器所执行的命令。
      • referenceStore:存储Docker像仓库名和镜像D的映射。
      • distributionMetadata5tore:v2版registry相关的元数据存储。
      • trustKey:可信任证书。
      • idIndex:用于通过简短有效的字符串前缀定位唯一的镜像。
      • sysInfo: Docker所在宿主机的系统信息。
      • configStore: Docker}h需要的配置信息。
      • execDriver: Docker容器执行驱动,默认为native类型。
      • statsCollector:收集容器网络及cgroup状态信息。
      • defaultLogConfig:提供日志的默认配置信息。
      • registryService:镜像存储服务相关信息。
      • EventsService:事件服务相关信息。
      • volumes: volume所使用的驱动,默认为local类型。
      • root : Docker运行的工作根目录。
      • uidMaps: uid的对应图。
      • gidMaps: gid的对应图。
      • seccompEnabled:是否使用seccomputeo
      • nameIndex:记录键和其名字的对应关系。
      • linkIndex:容器的link目录.记录容器的link关系。
    • 恢复已有的Docker容器

      ​ 当Docker daemon启动时,会去查看在daemon.repository也就是在/var/lib/docker/containers中

      的内容。若有已经存在的Docker容器,则将相应信息收集并进行维护,同时重启restart policy为always的容器。

猜你喜欢

转载自blog.csdn.net/fy_long/article/details/88425823