docker源码分析(3)---镜像(1)

说明:此文章为腾讯云机器自动从本人csdn博客搬迁过来。是本人授权操作。

申明:无本人授权,不可转载本文。如有转载,本人保留追究其法律责任的权利。

龚浩华,QQ 29185807,月牙寂 道长

第一时间获取文章,可以关注本人公众号 月牙寂道长 yueyajidaozhang

1、简介

镜像无疑是docker中的一个重要角色。在分析源码之前,我们先要了解下image的一些概念。可以参考 http://www.sel.zju.edu.cn/?p=549

docker中,为了复用image,将image做成,可继承的方式。子image可以继承父image的rootfs,通过分层的方式一层一层的进行继承复用,减少镜像的大小,提高存储复用。

这里有几个概念

1、rootfs,是容器启动的时候,其所可以用到的是文件系统目录。

2、image,是一个只读的文件系统。通过继承父image的文件系统,然后union mount到一起,形成一个rootfs。

3、layer,image的各个分层就属于layer,由于所有的image中的文件系统都是只读的。所以另外再在最顶层的image上面再添加一个read-write层。整个构成容器的运行环境。

在源代码中是怎么实现这些的呢。通过graphdriver与作为中间模块,实现与底层的layer的文件系统打交道。而graph模块通过graphdriver来对image进行管理。下面我们来看源码。

2、graphdriver

源码在docker\docker\daemon.go

在mainDaemon中初始化

d, err := daemon.NewDaemon(daemonCfg, eng)

我们继续跟进

源码在docker\daemon\daemon.go

在NewDaemonFromDirectory函数中

初始化了graphdriver,初始化流程到这里。下面我们具体的去看下graphdriver源码。

2.1 driver接口

driver一共有两部分的接口

protodriver,是比较基础部分的,直接与文件存储打交道。从上面的函数名我们就能看出来提供的作用。如

Create:用于创建一个新的layer。

Remove:删除一个layer。

就不一一解释了,其英文的注释已经说明了

driver接口其实是继承了protodriver接口,另外还提供了image与父image直接的一些操作,如diff用于获取image与父image之间的差别,等就不一一介绍。

2.2 插件注册与获取

driver通过插件形式来设计的。(这个也是golang设计中,经常用到的模式)

首先在init中初始化了一个map,用于保存插件的入口。然后提供了Register函数,用于插件的注册

另外提供了一个获取插件的函数。

那我们看看是如何New的

通过环境变量DOCKER_DRIVER,driver的类型,然后查找插件列表,然后通过GetDriver获取Driver。

那我们看看docker中都提供了哪些类型的driver

有aufs,btrfs,devmapper,overlay,vfs一共五种方式的driver。

2.3 vfs

这里我们就以一个最简单的模块来做演示vfs

代码在docker\daemon\graphdriver\vfs\driver.go

首先是注册

这里通过init注册了vfs方式的driver,初始函数为Init

我们来看看这个driver的具体情况(这个比较简单比较适合于演示)

以上不做解释

这里是Create,这里其实就是一个拷贝动作。

另外vfs并没有实现Driver接口,其只实现了protoDriver接口。是通过再封装了一层来实现的Driver接口的

docker\daemon\graphdriver\fsdiff.go

这里就不再详细介绍了。

2.4 小结

graphdriver通过插件的方式,提供了多种的底层drvier。

3、image

这里的image指的是源码里面的image

代码在docker\image\image.go

先看结构体

很明显这是一个json结构体

我们看看LoadImage

通过读取json文件,然后解析获取image结构体信息。

下面给一个示例

 {
  "Size": 0,
  "os": "linux",
  "id": "fef924a0204a00b3ec67318e2ed337b189c99ea19e2bf10ed30a13b87c5e17ab",
  "parent": "9a163e0b8d138ec700b5a5f7e62509012f7eb34b9f86cd3bbeb3d183958114a9",
  "created": "2016-02-16T22:59:37.407805421Z",
  "container": "d23509cd0189de02bef382544ebfab515f29094f3c0e2f161fa7ce09afa8974e",
  "container_config": {
  "Labels": {},
  "OnBuild": null,
  "MacAddress": "",
  "NetworkDisabled": false,
  "Entrypoint": null,
  "WorkingDir": "",
  "PublishService": "",
  "ExposedPorts": null,
  "AttachStderr": false,
  "AttachStdout": false,
  "AttachStdin": false,
  "User": "",
  "Domainname": "",
  "Hostname": "13709f13afe1",
  "Tty": false,
  "OpenStdin": false,
  "StdinOnce": false,
  "Env": null,
  "Cmd": [
  "/bin/sh",
  "-c",
  "#(nop) CMD [\"sh\"]"
  ],
  "Image": "9a163e0b8d138ec700b5a5f7e62509012f7eb34b9f86cd3bbeb3d183958114a9",
  "Volumes": null,
  "VolumeDriver": ""
  },
  "docker_version": "1.9.1",
  "config": {
  "Labels": {},
  "OnBuild": null,
  "MacAddress": "",
  "NetworkDisabled": false,
  "Entrypoint": null,
  "WorkingDir": "",
  "PublishService": "",
  "ExposedPorts": null,
  "AttachStderr": false,
  "AttachStdout": false,
  "AttachStdin": false,
  "User": "",
  "Domainname": "",
  "Hostname": "13709f13afe1",
  "Tty": false,
  "OpenStdin": false,
  "StdinOnce": false,
  "Env": null,
  "Cmd": [
  "sh"
  ],
  "Image": "9a163e0b8d138ec700b5a5f7e62509012f7eb34b9f86cd3bbeb3d183958114a9",
  "Volumes": null,
  "VolumeDriver": ""
  },
  "architecture": "amd64"
 }

以上这个是我在网上下载的一个image

下面是StoreImage

将image的信息,通过json编码保存到文件。

另外还提供了一些操作,就不一一做解读。

4、Graph

源码在docker\daemon\daemon.go

在初始化graphdriver之后,便初始化了graph

下面我们看看graph

代码在docker\graph\graph.go

主要保存了一个driver

graph目录中保存了image信息

我们看看

restore的时候,会扫描所有的目录,并将imageid给记录下来

那我们挑选几个提供的接口看看

get通过name来获取image id,然后通过imageid,来loadImage,从而获取image的信息

以上是整个create的过程,先构建image结构体,然后调用Register。

先查找是否存在,存在则直接返回。

如果不存在则将其他多余无用的重复信息删除,然后最后调用了driver进行Create。

graph还提供其他的很多操作,不再做分析了。

由于csdn博客显示不全所以分成两篇,继续请看下一篇

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

编辑于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Java帮帮-微信公众号-技术文章全总结

RabbitMQ详解解答【面试+工作】

如果安装rabbitMQ首先安装基于erlang语言支持的OTP软件,然后在下载rabbitMQ软件进行安装(安装过程都是下一步,在此不在说了)

1241
来自专栏草根专栏

用ASP.NET Core 2.0 建立规范的 REST API -- 预备知识 + 项目准备

REST 是 Representational State Transfer 的缩写. 它是一种架构的风格, 这种风格基于一套预定义的规则, 这些规则描述了网络...

8076
来自专栏Java帮帮-微信公众号-技术文章全总结

Python常见面试题【悟空教程】

1.MySQL 数据库总结 MySQL 可以建多少个数据库,理论上是没有限制的,每一个数据库可以有上亿的对象,但是一般基于硬件要求、效率问题一般不超过64个, ...

1012
来自专栏后台全栈之路

基于汇编的 C/C++ 协程 - 实现

将 libco 和 libevent 两者的功能糅合起来,所以我把我的工程,命名为 libcoevent,意为 “基于 libevent 的同步协程服务器编程框...

3731
来自专栏刘望舒

Android解析WindowManagerService(一)WMS的诞生

前言 此前我用多篇文章介绍了WindowManager,这个系列我们来介绍WindowManager的管理者WMS,首先我们先来学习WMS是如何产生的。本文源码...

3176
来自专栏NetCore

保护连接字符串

保护连接字符串 摘自MSDN 保护对数据源的访问是安全应用程序最重要的目标之一。为了帮助限制对数据源的访问,必须保护连接信息(例如用户标识、密码和数据源名称)的...

1835
来自专栏逸鹏说道

小解Redis 系列

官网:http://redis.io/ 推荐一个开源组件:StackExchange.Redis https://github.com/StackExchang...

2849
来自专栏JadePeng的技术博客

axios介绍与使用说明 axios中文文档

本周在做一个使用vuejs的前端项目,访问后端服务使用axios库,这里对照官方文档,简单记录下,也方便大家参考。 Axios 是一个基于 Promise 的 ...

1.4K9
来自专栏有趣的Python

11- vue django restful framework 打造生鲜超市 -用户登录和手机注册(下)

Vue+Django REST framework实战 搭建一个前后端分离的生鲜超市网站 Django rtf 完成 手机注册和用户登录(下) user...

5048
来自专栏抠抠空间

Linux用户管理

1570

扫码关注云+社区