Docker 对 container 的使用基本是建立在 LXC 基础之上,然而 LXC 存在的问题是难以移动,难以通过标准化的模板去制作、重建、复制和移动 container。

在以 VM 为基础的虚拟化中,有 image 和 snapshot 可以用于 VM 的复制、重建以及移动的功能。

想要通过 container 来实现快速的大规模部署和更新,这些功能不可或缺。

在 Docker 0.7 中引入了 Storage Driver(储存驱动), 现在已经支持 AUFS、Btrfs、Device Mapper、OverlayFS、ZFS、VFS。

一、储存驱动

https://docs.docker.com/storage/storagedriver/select-storage-driver/

1.Union FileSystem

简称 Union FS(联合文件系统),储存驱动的一种。

一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下。

特性:一次同时加载多个文件系统,但从外面看起来,只能看到一个文件系统,联合加载会把各层文件系统叠加起来,这样最终的文件系统会包含所有底层的文件和目录。

2.Overlay2

Overlay2 是一种 Union FS,支持为每一个成员目录(AKA branch)设定 readonly、readwrite 和 whiteout-able 权限。

通常 Union FS 有两个用途:

  • 不借助 LVM, RAID 将多个 disk 和挂载到一个目录下。
  • 将一个 readonly 的 branch 和一个 writeable 的 branch 联合在一起,Live CD 正是基于此,可以允许在 OS image 不变的基础上允许用户在其上进行一些写操作。

Docker 在 Overlay2 上构建的 container image 也正是如此。

OverlayFS 将单个 Linux 主机上的两个目录分层,并将它们显示为单个目录。这些目录称为层,统一过程称为联合安装。

Overlay2 原生支持多达 128 OverlayFS 层。

下图显示了 Docker镜像 和 Docker容器 的分层方式。图像层是 lowerdir,容器层是 upperdir。统一视图通过一个被称为 merged 容器挂载点的目录公开。

二、Linux 系统启动

典型的 Linux 启动到运行需要两个FS - bootfs + rootfs (从功能角度而非文件系统角度)

bootfs(boot file system):

主要包含 bootloader 和 kernel,bootloader 主要是引导加载 kernel,当 kernel 被加载到内存中后,bootfs 就被 umount 了,此时内存的使用权已由 bootfs 转交给 kernel。

rootfs (root file system) :

在 bootfs 之上。包含的就是典型 Linux 系统中的 /dev、/proc、/bin、/etc 等标准目录和文件。

由此可见对于不同的 linux 发行版,bootfs 基本是一致的,rootfs 会有差别,,因此不同的发行版可以公用 bootfs。如下图:

三、Docker image 结构

典型的 Linux 在启动后,首先将 rootfs 置为 readonly,进行一系列检查, 然后将其切换为 "readwrite" 供用户使用。

在 Docker 中,起初也是将 rootfs 以 readonly 方式加载并检查,然而接下来利用 union mount 将一个 readwrite 文件系统挂载在 readonly 的 rootfs 之上,并且允许再次将下层的 file system 设定为 readonly,并且向上叠加。

这样一组 readonly 和一个 writeable 的结构构成一个 container 的运行目录,每一个被称作一个 Layer。如下图:

得益于 AUFS 的特性,每一个对 readonly 层文件或目录的修改都只会存在于上层的 writeable 层中。

这样,由于不存在竞争, 多个 container 可以共享 readonly 的 layer。

所以 docker 将 readonly 的层称作 image,对于 container 而言整个 rootfs 都是 read-write 的,但事实上所有的修改都写入最上层的 writeable 层中。

image 不保存用户状态,可以用于模板、重建和复制。

某个镜像:

基于该镜像创建的容器:

上层的 image 依赖下层的 image,因此 docker 中把下层的 image 称作父 image,没有父 image 的 image 称作 base image。

因此想要从一个 image 启动一个 container,docker 会先加载其父 image 直到 base image,用户的进程运行在 writeable 的 layer 中。

所有 parent image 中的数据信息以及 ID、网络和 lxc 管理的资源限制等具体 container 的配置,构成一个 docker 概念上的 container。如下图:

Docker image 采用分层结构的好处

共享资源,节省存储空间:有多个镜像都从相同的 base 镜像构建而来,那么宿主机只需在磁盘上保存一份 base 镜像,同时内存中也只需加载一份 base 镜像,就可以为所有容器服务了。而且镜像的每一层都可以被共享。

快速部署:如果要部署多个 container,base image 可以避免多次拷贝。

内存更省:因为多个 container 共享 base image,以及 OS 的 disk 缓存机制,多个 container 中的进程命中缓存内容的几率大大增加。

升级更方便:相比于 copy-on-write 类型的文件系统,base-image 也是可以挂载为可 writeable 的,可以通过更新 base image 而一次性更新其之上的 container。

允许在不更改 base-image 的同时修改其目录中的文件,所有写操作都发生在最上层的 writeable 层中。

四、Docker 镜像 commit

docker commit 提交容器副本使之成为一个新的镜像

# docker commit -m=“提交的描述信息” -a=“作者” 容器ID 要创建的目标镜像名:[标签名]

# 下载镜像
docker pull tomcat
# 启动镜像
docker run -d -p : tomcat
# 查看容器ID
docker ps -a
# 进入容器
docker exec -it a41c393cfa45 /bin/bash
# 删除 tomcat
rm -rf /usr/local/tomcat/webapps/*
# 退出容器
exit
# 生成新镜像
docker commit -m=“没有webapps的tomcat镜像” -a=“jhxxb” a41c393cfa45 jhxxb/tomcat-del:1.0
# 查看生成的新镜像
docker images # 运行新镜像(需要指定版本,默认为 latest)
docker run -d -p 8080:8080 jhxxb/tomcat-del:1.0

可以看到新镜像的 webapps 目录下没有文件


http://tiewei.github.io/cloud/Docker-Getting-Start/

https://docs.docker.com/storage/storagedriver/overlayfs-driver/#how-the-overlay2-driver-works

Docker Image的更多相关文章

  1. docker——容器安装tomcat

    写在前面: 继续docker的学习,学习了docker的基本常用命令之后,我在docker上安装jdk,tomcat两个基本的java web工具,这里对操作流程记录一下. 软件准备: 1.jdk-7 ...

  2. Docker笔记一:基于Docker容器构建并运行 nginx + php + mysql ( mariadb ) 服务环境

    首先为什么要自己编写Dockerfile来构建 nginx.php.mariadb这三个镜像呢?一是希望更深入了解Dockerfile的使用,也就能初步了解docker镜像是如何被构建的:二是希望将来 ...

  3. Docker 第一篇--初识docker

    已经多年不写博客, 看完<晓松奇谈>最后一期猛然觉醒, 决定仔细梳理下自己这几年的知识脉络. 既然决定写, 那么首先就从最近2年热门的开源项目Docker开始.Docker 这两年在国内很 ...

  4. 在docker中运行ASP.NET Core Web API应用程序(附AWS Windows Server 2016 widt Container实战案例)

    环境准备 1.亚马逊EC2 Windows Server 2016 with Container 2.Visual Studio 2015 Enterprise(Profresianal要装Updat ...

  5. docker for mac 学习记录

    docker基本命令 docker run -d -p 80:80 --name webserver nginx 运行容器并起别名 docker ps 展示目前启动的容器 docker ps -a 展 ...

  6. scrapy爬虫docker部署

    spider_docker 接我上篇博客,为爬虫引用创建container,包括的模块:scrapy, mongo, celery, rabbitmq,连接https://github.com/Liu ...

  7. [原][Docker]特性与原理解析

    Docker特性与原理解析 文章假设你已经熟悉了Docker的基本命令和基本知识 首先看看Docker提供了哪些特性: 交互式Shell:Docker可以分配一个虚拟终端并关联到任何容器的标准输入上, ...

  8. 开发者的利器:Docker 理解与使用

    困扰写代码的机器难免会被我们安装上各种各样的开发工具.语言运行环境和引用库等一大堆的东西,长久以来不仅机器乱七八糟,而且有些相同的软件还有可能会安装不同的版本,这样又会导致一个项目正常运行了,却不小心 ...

  9. 使用python自动生成docker nginx反向代理配置

    由于在测试环境上用docker部署了多个应用,而且他们的端口有的相同,有的又不相同,数量也比较多,在使用jenkins发版本的时候,不好配置,于是想要写一个脚本,能在docker 容器创建.停止的时候 ...

  10. 微服务与Docker介绍

    什么是微服务 微服务应用的一个最大的优点是,它们往往比传统的应用程序更有效地利用计算资源.这是因为它们通过扩展组件来处理功能瓶颈问题.这样一来,开发人员只需要为额外的组件部署计算资源,而不需要部署一个 ...

随机推荐

  1. JavaScript中的setTimeout、setInterval和随机函数制作简易抽奖小程序

    几乎所有计算机语言有都内置随机函数.当然这种随机,人们习惯称为伪随机数发生器,产生的是一个[0,1)之间的一个小数.再通过简单算术运算生成一个符合需求的整数.JS中通用公式通常为parseInt(Ma ...

  2. 【ASE高级软件工程】第一次结对作业

    问题定义 具体规则见:讲义.大致规则如下: N个同学(N通常大于10),每人写一个0~100之间的有理数 (不包括0或100),交给裁判,裁判算出所有数字的平均值,然后乘以0.618(所谓黄金分割常数 ...

  3. 如何从零搭建hexo个人博客网站

    https://www.jianshu.com/p/adf65cbad393?utm_source=oschina-app   准备工作 github账号 node.js 环境搭建 git使用 mar ...

  4. 13_Hive优化

    Hive优化 要点:优化时,把hive sql当做map reduce程序来读,会有意想不到的惊喜. 理解hadoop的核心能力,是hive优化的根本. 长期观察hadoop处理数据的过程,有几个显著 ...

  5. 08_Hive中的各种Join操作

    1.关于hive中的各种join Hive中有许多的Join操作,例如:LEFT.RIGHT和FULL OUTER JOIN,INNER JOIN,LEFT SEMI JOIN等: 1.1.准备两组数 ...

  6. 05_Hive分区总结

    2.1.创建分区表并将本地文件的数据加载到分区表: 使用下面的命令来创建一个带分区的表 通过partitioned by(country string)关键字声明该表是分区表,且分区字段不能为crea ...

  7. wiki页面文本挖掘

    import os,sysimport sysfrom bs4 import BeautifulSoupimport urllib.request# reload(sys)# sys.setdefau ...

  8. Webpack v4.8.3 快速入门指南

    一.进入 https://webpack.docschina.org/ 官方文档,点击 "文档" 进入 文档页面,文档中包含  “概念,配置,API,指南,LOADERS,插件&q ...

  9. shell字符串处理

    一.字符串切片: ${#var}:返回字符串变量var的长度${var:offset}:返回字符串变量var中从第offset个字符后(不包括第offset个字符)的字符开始,到最后的部分,offse ...

  10. 【洛谷P2485】计算器

    BSGS模板题 代码如下 #include <bits/stdc++.h> using namespace std; typedef long long LL; LL fpow(LL a, ...