docker client和daemom
client 模式
docker命令对应的源文件是docker/docker.go,
docker [options] command [arg...]
其中options参数为flag,任何时候执行一个命令docker命令都需要先解析flag,然后按照用户生命的command向指定的子命令执行对应的操作
如果子命令为daemom,docker都会创建一个运行在宿主机上的daemom进程,即执行daemom模式。其余子命令都会执行client模式。处于client模式命令工作流程包含几个步骤
1.解析flag信息
docker命令支持大量的option,或者说flag,列出对于client模式下的docker比较重要的一些flag
Debug,对应-D和--debug参数,他将向系统中添加DEBUG环境变量且赋值为1,并把日志显示级别调为DEBUG级,这个flag用于启动调试模式
LogLevel,对应-l和--log-level 参数。默认等级为info,即只输出普通的操作信息。用户可以指定的日志等级现在有panic、fatal、error、warn、info、DEBUG这几种
hosts,对应-h和--hosts=[]参数,对于client模式,就是指本次操作需要连接的docker daemom位置,而对于daemom模式,则提供所要监听的地址,若host变量或者系统环境变量DOCKER_HOST不为空,说明用户指定了host对象;否则使用默认设置,默认情况下Linux系统设置为unix:///var/run/docker.sock
protAddrParts,这个参数来自-H参数中://前后的两部分的组合,即与docker daemom建立通信的协议方式与socke地址
2创建client实例
client的创建就是在已有配置参数信息的基础上,调用api/client/cli.go#NewDockerCli,需要设置好proto(传输协议)、addr(host的目标地址)和tlsConfig(安全传输层协议的配置),另外还会配置标准输入输出及错误输出
3执行具体的命令
Docker client 对象创建成功后,剩下的执行具体命令的过程就交给cli/cli.go来处理
从命令到映射的方法
cli主要通过反射机制,从用户输入的命令(如run)得到匹配的执行方法(CmdRun),这就是所谓“约定大于配置”的方法命名规范。
同时,cli会根据参数列表的长度判断是否用于多级docker命令支持,然后根据找到的执行方法,把剩下的参数传入并执行。若参数传入的方法不正确或者错误,则返回docker的帮助并退出
每一个类似api/client/commnds.go#CmdRun 的方法都剥离出来作为一个单独的文件存在。docker run 这个命令的执行过程,就需要寻找api/client/run.go这个文件
执行对应的方法,发起请求
1.解析传入的参数,并针对参数进行配置处理
2.获取与Docker daemon通信所需要的认证配置信息
3.根据命令业务类型,给Docker daemon发送POST、GET等请求
4.读取来自Docker daemon
daemom 模式
一旦进入daemom模式,剩下的初始化工作都由docker的docker/daemon.go#CmdDaemon来完成;docker daemon通过一个server模块(api/server/server.go)接收来自client的请求,然后根据请求的类型,交由具体方法执行,因此daemom首先要启动并初始化这个server,另一方面启动server后。docker 进程需要初始化一个daemon对象(daemon/daemon.go)来负责处理server的请求。
docker daemon 初始化启动过程
API server的配置和初始化过程
启动过程
(1)整理解析用户指定的各项参数
(2)创建PID文件
(3)加载所需的server辅助配置,包括日志、是否允许远程访问、版本以及TLS认证信等。
(4)根据上述server配置,加上之前解析出来的用户指定的server配置(比如Host),通过goro-utine的方式启动API server。这个server监听的socket位置就是Host的值
(5)创建一个负责处理业务的daemon对象(对应daemon/daemon.go)作为负责处理用户请求的逻辑实体
(6)对APIserver中的路由表进行初始化,即将用户的请求和对应的处理函数相对应起来。
(7)设置一个channel,保证上述goroutine只是在server出错的情况才会退出
(8)设置信号捕获,docker daemon进程收到INT、TERM、QUIT信号时,关闭API server,用shutdowndaemon停止这个daemon
(9)如果上面流程完成后,API server就会与daemon绑定,并接受client的连接。
(10)最后,docker daemon进程向宿主机的init守护进程发送“READY=1”信号,表示docker daemon已经开始工作
关闭过程
(1)创建并设置一个channel,使用select监听数据。在正确完成关闭daemon工作后将channel关闭,标识该工作的完成;否则在超时15秒后报错
(2)调用daemon/daemon.go#Shoutdown方法执行如下工作
遍历所有运行中的容器,先用SIGTERM软杀死容器进程,如果10秒不能完成,则使用SIGKILL强制杀死
如果netController被初始化过,调用#libnetwork/controler.go#GC 方法进行垃圾回收
结束运行中的镜像驱动程序
在docker1.6版本以前的早期和以前所有版本,server的启动和初始化使用了一种复杂的job机制(API server即被看作一种job),并且依赖于一个专门的docker Engine来管理和运行这些job。1.7版本,这个设计在整个社区的推动下呗重构,上述说的是新的server初始化过程,该server会通过与daemon对象绑定来接受并处理完成具体的请求(类似于一个API接受器绑定了一个业务逻辑处理器)
daemon对象的创建与初始化
对象创建过程至少包括功能有:docker容器配置信息、检测系统支持及用户权限、配置工作路径、加载并配置graphdriver、创建docker网络环境、创建并初始化镜像数据库、创建容器管理驱动、检测DNS配置和加载已有Docker容器等。
docker 容器配置信息
容器配置信息的主要功能有:提供用户自由配置的docker容器的可选功能,使得docker容器运行更贴近用户期待的运行场景;设置默认的网络最大传输单元:当用户没有对-mut参数进行指定是,将其设置为1500.否则,沿用用户指定参数值 ;检测网桥配置信息:此部分配置为进一步配置docker网络提供铺垫
检测系统支持及用户权限
初步处理完docker的配置信息后,docker自身运行的环境进行一系列检测,主要包括3个方面
* 操作系统类型对docker daemon的支持,目前docker daemon只能运行在Linux上
* 用户权限的级别,必须是root权限
* 内核版本与处理器支持,只支持amd64架构的处理,且内核版本必须升至3.10.0及以是上。
配置daemon工作路径
配置docker daemon的工作路径,主要是创建Docker daemon 运行中所在的工作目录,默认为/var/lib/docker.若该目录不存在,则会创建,并赋予0700权限
配置docker容器所需的文件环境
这一步docker daemon会在docker工作目录/var/lib/docker 下面初始化一些重要的目录文件,来构建docker容器工作所需的文件系统环境
这一,创建容器配置文件目录。docker daemon在出创建docker容器之后,需要将容器内的配置文件放到这个目录下统一管理。目录默认位置:/var/lib/docker/containers,它下面会为每个具体容器保存如下几个配置文件,其中xxx为容器ID
[root@mast ~]# ls /var/lib/docker/containers/4d5464672680c97ed061b73e7d8336741b2971c2fb5a81fa5ac2ec8fac096cf9/
4d5464672680c97ed061b73e7d8336741b2971c2fb5a81fa5ac2ec8fac096cf9-json.log checkpoints config.v2.json hostconfig.json hostname hosts mounts resolv.conf resolv.conf.hash
第二,配置graphdriver目录。它用于完成docker容器镜像管理所需的底层存储驱动层,所以在这一步的配置工作就是加载并配置镜像存储驱动graphdriver,创建存在驱动镜像管理层文件系统所需的目录和环境,初始化镜像层元数据存储。创建graphdriver时,首先会从环境变量DOCKER_DRIVER中读用户指定的驱动,若为空,则开始遍历优先级数组选择一个graphdriver,在Linux环境下,优先级从高到低依次为aufs、btrfs、zfs、devicemapper、overlay和vfs。 不同操作系统下,优先级列表的内容和顺序都会不同,而且随着内核的发展以及驱动的完善,会继续发生变化。
需要注意,目前vfs在docker中时用来管理volume的,并不作为镜像存储使用。另外,由于目前在overlay文件系统上运行的docker容器不兼容SELinux,因此当config中配置信息需要启动SELinux并且driver的类型为overlay时,该过程就会报错
当识别出对应的driver后,docker执行这个driver对应的初始化方法(位于daemon/graphdriver/aufs/aufs,go),这个初始化的主要工作包括:尝试加载内核aufs模块来确定docker主机支持aufs,发送statfs系统调用获取当前docker主目录(/var/lib/docker)的文件系统信息,确定aufs是否支持该文件系统;创建aufs驱动根目录(默认:/var/lib/docker/aufs)并将该目录配置为私有挂载,在根目录下创建mnt、diff和layers目录作aufs驱动的工作环境,工作完成后,graphdriver的配置工作就完成。
第三,配置镜像目录。主要工作是在docker主目录下创建一个image目录,来存储所有镜像和镜像层管理数据,默认目录“/var/lib/docker/image”.在image目录下,每一graphdriver都有一个具体的目录用于存储使用该graphdriver存储的镜像相关的元数据
根据上一步graphdriver的选择情况(以aufs为例)创建image/aufs/layerdb/目录作为镜像层元数据存储目录,并创建MetadataStore用来管理元数据。根据graphdriver与元数据存储结构创建layerStore,用来管理所有的镜像和容器层,将逻辑镜像层的操作映射到物理存储驱动层graphdriver的操作,创建用于registry的镜像上传下载的uploadManager和downloadMannger
创建image/aufs/imagedb/目录用于存储镜像的元数据,根据layerStore创建imageStore,用来管理镜像的元数据。
第四,调用volume/local/local.go#New创建volume驱动目录(默认为/var/lib/docker/volumes),docker中volume是宿主机上挂载到docker容器内的特定目录。volume目录下有一个metadata.db 数据库文件用于存储volume相关的元数据,其余以volume ID 命名的文件夹用于存储具体的volume内容。默认的volume驱动是local,用户也可以通过插件的形式使用其他volume驱动来存储
第五,准备“可信镜像”所需的工作目录。docker工作根目录下创建trust目录。这个存储目录可以根据用户给出的可信URL加载授权文件,用来处理可信镜像的授权和验证过程。
第六,创建distributionMetadataStore和referenceStore。referenceStore用于存储镜像仓库列表。记录镜像仓库的持久化文件位于docker根目录下的image/[graphdriver]/repositories.json中,主要记录镜像ID与镜像仓库之间的映射。distributionMetadataStore存储与第二版镜像仓库registry有关的元数据,主要用于做镜像层的diff_id与registry中镜像层元数据之间的映射
第七,将持久化在Docker根目录中的镜像、镜像层以及镜像仓库等的元数据内容恢复到daemon的imageStore、layerStore和reference中
第八,执行镜像迁移,docker1.10版本以后,镜像管理部分使用了基于内容寻址存储。在第一次启动daemon时,为了将老版本的graph镜像管理迁移到新的镜像管理体系中,这里会根据docker根目录中是否存在graph文件夹,如果存在就会读取graph中的老版本镜像信息,计算校验和并将镜像数据写入到新版本的imageStore和layerStore中,注意的是,迁移镜像中计算校验和是一项非常占CPU的工作,并且在未完成镜像迁移时,docker daemon是不会响应任何请求的,所有如果你本地的老版本镜像和容器比较多时,或者是在对服务器负载和响应比较敏感的线上环境尝试,docker版本升级,那就要注意妥善安排时间,docker提供了迁移工具让用户在老版本daemon运行的时候进行镜像迁移
这里docker daemon需要在docker根目录(/var/lib/docker)下创建并初始化一系列容器文件系统密切相关的目录和文件。
创建docker network
创建docker daemon运行环境的时候,创建网络环境是极为重要的一部分。这不仅关系着容器对外通信,同样也关乎着容器之间的通信。网络部分早已被抽离出来作为一个单独的模块,称为libnetwork,libnetwork通过插件的形式为docker提供网络功能,使得用户可以根据自己需求实现自己的dirver来提供不同的网络功能。截止docker1.10版本,libnetwork实现了host、null、birdge和overlay的驱动。其中,birdge driver 为默认驱动,和之前版本中的docker网络功能是基本等价的,需要注意的是,同之前的docker网络一样,bridge driver并不提供跨主机通信的能力,overlay driver则是用于多主机环境
初始化execdriver
execdriver是docker中用来管理容器的驱动,docker会调用execdrivers中NewDriver()函数来创建新的execdriver
在创建execdriver的时候,需要注意一下5部分信息
运行时中指定使用的驱动类型,在默认配置文件中默认使用native,即其对应的容器运行时为libcontainer;
用户定义的execdirver选项,即-exec-opt参数值
用户定义的-exec-root参数值,docker execdriver运行的root路径,默认为/var/run/docker;
docker 运行时的root路径,默认为/var/lib//docker
系统功能的信息,包括容器的内存限制功能,交换分区内存限制功能、数据转发功能以及AppArel安全功能等;AppArel通过host主机是否存在/sys/kernel/security/apparmor来判断是否加入AppArel配置
最后,如果选择netive作为这个execdriver的驱动实现,上述driver的创建过程就会新建一个libcontainer,这个libcontainer会在后面创建和启动Linux容器时发挥作用
daemon对象诞生
docker daemon进程在经过以上诸多设置以及创建对象之后,最终创建出了daemon对象实例
ID | 根据传入的证书生成的容器ID,若没有传入则自动使用ECDSA算法生成 |
repository | 部署所有docker容器的路径 |
containers | 用于存储具体的docker容器信息的对象 |
execCommands | docker容器所执行的命令 |
referenceStore | 存储docker镜像仓库名和镜像ID的映射 |
distributionMetadataStore | v2版registry相关的元数据存储 |
trustkey | 可信任证书 |
IDInfo | 用于通过简短有效的字符串前缀定位唯一的镜像 |
sysInfo | docker所在宿主机的系统信息 |
configStore | docker所需配置信息 |
execDriver | docker 容器执行驱动,默认native类型 |
statsCollector | 收集容器网络以及cgroups的信息 |
dafaultLogConfig |
提供日志的默认配置信息 |
registryService | 镜像存储服务相关信息 |
EvenetsServer | 事件服务相关信息 |
volume |
volume所使用的驱动,默认为local |
root | docker运行的工作根目录 |
uidMaps | uid的对应图 |
gidMaps | gid的对应图 |
seccompEnabled | 是否使用seccompute |
nameIndex | 记录建和其名字的对应关系 |
linkIndex | 容器的link目录,记录容器的link关系 |
恢复已有的docker容器
当docker daemon启动时,会去查看在daemon.repository也就是在/var/lib/docker/containers中的内容。若有已经存在的docker容器,则将相应信息收集并进行维护,同时重启restart policy 为always的容器
docker daemon的启动看起来非常复杂,这是docker在演进的过程中不断增加功能点造成的,但不管今后docker的功能点增加多少,docker daemon进程的启动都将遵循3步
(1)首先创建一个API server,它工作在用户通过-H指定socket
(2)然后docker使用NewDaemon方法创建一个daemon对象来保存信息和处理业务逻辑
(3)最后将上述API server和daemon对象绑定起来,接受并处理client的请求
只不过,NewDaemon方法的长度会不断增加而已
从client到daemon
发起请求
(1)docker run命令开始运行,用户端的docker进入client模式
(2)经过初始化,新建出了一个client
(3)上述client通过反射机制找到了CmdRun方法
CmdRun在解析过程用户提供的容器参数等一系列操作后,最终发出了这样两个请求:
“POST”,“/containers/create?”+containerValues //创建容器
“POST” ,“/containers/”+createResponse.ID+"/start" //启动容器
至此,client 任务结束
创建容器
在这一步docker daemon并不需要创建一个真正的Linux容器,它只需要理解用户通过client提交的POST表单,然后使用这些参数在daemon中新建一个container对象出来即可,这个container实体就是container/container_unix.go,其中的commonContainer字段定义在平台为主。
启动容器
这个时候daemon这边的重点来了。API server接受到start请求后告诉docker daemon进行container启动容器操作,这个过程daemon/start.go
此时,由于container所需的各项参数,如NetworkSetings、ImageID等,都已经在容器过程中赋好了值,docker daemon会在start.go 中直接执行daemon.ContainerStart,就能够宿主机上创建对应的容器了;创建容器过程是docker daemon,containerMonitor将daemon设置为自己的supervisor。所以经过一系列调用后。daemon.ContainerStart 实际上执行的操作是
即告诉daemon进程,请使用container相关的信息作参数,执行对应的execdriver的Run方法
最后一步
“万事俱备,只欠东风”。在docker daemon已经完成所有的准备工作,最后下达了执行Run操作的命令后,跟系统打交道的任务都交给ExecDriver.Run来完成;execdriver是docker的重要组成部分,它封装了对namespace、cgroups等所有对OS资源操作的方法,而在docker中。execdriver的默认实现(native)就是libcontainer了,到这一步。docker daemon只需要提供三大参数,接下来等着返回结果
* commandv:该容器需要的所有配置信息集合
* pipes:用于将容器stdin、stdout、stderr重定向到daemon
* startCallback():回调方法
docker client和daemom的更多相关文章
- Docker Client (another java docker client api)
前一篇提到了docker-java,这里介绍另一个docker client 库,Docker Client 版本兼容 兼容17.03.1~ce - 17.12.1~ce (点 [here][1]查看 ...
- Docker源码分析(二):Docker Client创建与命令执行
1. 前言 如今,Docker作为业界领先的轻量级虚拟化容器管理引擎,给全球开发者提供了一种新颖.便捷的软件集成测试与部署之道.在团队开发软件时,Docker可以提供可复用的运行环境.灵活的资源配置. ...
- 【Docker】使用Docker Client和Docker Go SDK为容器分配GPU资源
目录 背景 使用 Docker Client 调用 GPU 依赖安装 安装 Docker 安装 NVIDIA Container Toolkit¶ --gpus 用法 使用 Docker Go SDK ...
- docker 源码分析 二(基于1.8.2版本),docker client与daemon交互
(2) 那我们通过docker客户端发送一个命令,docker是怎样接收到并处理的呢,我们就举个例子来看一下,比如docker pull 命令: 我们回到 docker/docker.go 中,在上一 ...
- [Docker] Docker Client in Action
Pull the docker image: docker pull hello-world Show all the images: docker images Remove the image: ...
- Docker集群实验环境布署--swarm【6 配置上层Nginx代理,让任意Docker client访问得到高可用的管理API】
10.40.42.10上,也就是对应的VRRP中的10.40.42.1和2上,配置nginx tcp代理 # cat 4000_manager.venic.com_10.40.100.141-14 ...
- docker报Error response from daemon: client is newer than server (client API version: 1.24, server API version: 1.19)
docker version Client: Version: 17.05.0-ce API version: 1.24 (downgraded from 1.29) Go version: go1. ...
- docker 框架概述
docker的框架 docker 使用传统的client-server架构模式,用户端通过docker client 与docker daemon 建立通信,并将请求发送给后者,而docker后端时 ...
- docker学习(3) 容器的启动过程
这一节我们来稍微了解下docker原理性的东西 docker run -i -t ubuntu /bin/bash 输入上面这行命令,启动一个ubuntu容器时,到底发生了什么? 大致过程可以用下图描 ...
随机推荐
- 嵌入式Linux学习方法——给那些彷徨者(上)
要想学好嵌入式Linux,首先要解决两个重要问题: 1. 学什么? 2. 怎么学? 首先解决第一个问题. 嵌入式Linux的系统架构包括软件和硬件两个部分,如下图: 再来看看一个成熟的嵌入式产品的开发 ...
- Code-NFine:变量修改
ylbtech-Code-NFine:Cookie变量修改 1. NFine.Code返回顶部 1.Operator 1.1.OperatorProvider.cs /**************** ...
- git只clone仓库中指定子目录
基于sparse clone变通方法 [root@vm_test backup]# mkdir devops[root@vm_test backup]# cd devops/[root@vm_test ...
- J2ee的SSM和SSH的小结
1.介绍SSM框架: SSM是指由Spring.SpringMVC.Mybatis三个开源框架整合的开发框架. a).Spring是一个轻量级的容器框架,核心是控制反转(IoC)和面向切面(AOP). ...
- codforces 1C Ancient Berland Circus(几何)
题意 给出正多边形上三个点的坐标,求正多边形的最小面积 分析 先用三边长求出外接圆半径(海伦公式),再求出三边长对应的角度,再求出三个角度的gcd,最后答案即为\(S*2π/gcd\),S为gcd对应 ...
- UVALive 6833【模拟】
题意: 算从左往右的值,先乘后加的值,数的范围<=9= =,然后根据满足的条件输出字符. 思路: 从左往右就是直接来了,先做乘法就是乘法两边的数字靠向右边那个,且左边那个为0,然后所有值一加就好 ...
- 安装elasticsearch-head
直接安装chrome插件,用npm老出错,shit 再说吧 使用插件连接的时候反而没有出错,后续如果出错 , 可以配置 elasticsearch下config下的y 在新的电脑上使用发现格式不对,比 ...
- Win10各个版本免费激活密钥
专业版:W269N-WFGWX-YVC9B-4J6C9-T83GX 企业版:NPPR9-FWDCX-D2C8J-H872K-2YT43 家庭版:TX9XD-98N7V-6WMQ6-BX7FG-H8 ...
- Codeforces Round #418 (Div. 2) C
Description Nadeko's birthday is approaching! As she decorated the room for the party, a long garlan ...
- AtCoder Beginner Contest 057 ABCD题
A - Remaining Time Time limit : 2sec / Memory limit : 256MB Score : 100 points Problem Statement Dol ...