【Docker】镜像分层存储与镜像精简
Linux操作系统###
Linux操作系统由内核空间和用户空间组成。
内核空间是kernel,用户空间是rootfs, 不同Linux发行版的区别主要是rootfs.比如 Ubuntu 14.04 使用 upstart 管理服务,apt 管理软件包;而 CentOS 7 使用 systemd 和 yum。这些都是用户空间上的区别,Linux kernel 差别不大。
所以 Docker 可以同时支持多种 Linux 镜像,模拟出多种操作系统环境。
分层存储###
因为镜像包含操作系统完整的 root 文件系统,其体积往往是庞大的,因此在 Docker 设计时,就充分利用 Union FS 的技术,将其设计为分层存储的架构。所以严格来说,镜像并非是像一个 ISO 那样的打包文件,镜像只是一个虚拟的概念,其实际体现并非由一个文件组成,而是由一组文件系统组成,或者说,由多层文件系统联合组成。
镜像构建时,会一层层构建,前一层是后一层的基础。每一层构建完就不会再发生改变,后一层上的任何改变只发生在自己这一层。比如,删除前一层文件的操作,实际不是真的删除前一层的文件,而是仅在当前层标记为该文件已删除。在最终容器运行的时候,虽然不会看到这个文件,但是实际上该文件会一直跟随镜像。因此,在构建镜像的时候,需要额外小心,每一层尽量只包含该层需要添加的东西,任何额外的东西应该在该层构建结束前清理掉。
分层存储的特征还使得镜像的复用、定制变的更为容易。甚至可以用之前构建好的镜像作为基础层,然后进一步添加新的层,以定制自己所需的内容,构建新的镜像。
docker镜像原理###
docker镜像在构建的时候利用了aufs文件系统的挂载原理,对文件系统进行构建。
首先,存在一个 docker 容器在启动时其内部进程可见的文件系统视角,或者称为docker 容器的根目录rootfs。目录下含有 docker 容器所需要的系统文件、工具、容器文件等。(只读属性)
接着,在特定的镜像中存在每一个镜像独有的文件系统(读写属性),以ubuntu镜像为例,如下图:
在docker实际应用中,镜像相当于只读层,而容器则相当去上图中的可写层。已构建的镜像会设置成只读模式,read-write写操作是在read-only上的一种增量操作,固不影响read-only层。
无论是unbuntu这种OS系统,还是mysql,mongo这种具体应用。docker利用的aufs文件系统在文件系统挂载时对镜像进行复用。
所以我们假设 docker build 构建出来的镜像名分别为 image 1 和 image 2,由于两个 Dockerfile 均基于ubuntu:14.04,因此,image 1 和 image 2 这两个镜像均复用了镜像 ubuntu:14.04。 假设 RUN apt-get update 修改的文件系统内容为 20 MB,最终本地三个镜像的大小关系应该如下 :
ubuntu:14.04: 200 MB
image 1:200 MB(ubuntu:14.04 的大小)+ 20 MB = 220 MB
image 2:200 MB(ubuntu:14.04 的大小)+ 100 MB = 300 MB
如果仅仅是单纯的累加三个镜像的大小,那结果应该是:200 + 220 + 300 = 720 MB,但是由于镜像复用的存在,实际占用的磁盘空间大小是:200 + 20 + 100 + 320 MB,足足节省了 400 MB 的磁盘空间。在此,足以证明镜像复用的巨大好处。
由此可以说明docker images 列表下镜像大小之和并非是镜像实际硬盘消耗.
镜像的精简优化###
1.优化基础镜像####
基础镜像选择时,选择合适的较小的镜像,常用的 Linux 系统镜像一般有 Ubuntu、CentOs、Alpine···等
2.串联 Dockerfile 指令####
在 Dockerfile 中, 每一条指令都会创建一个镜像层,继而会增加整体镜像的大小。当前层作出的操作修改不会影响上一层。
-用&&串联指令(一般是RUN指令)
-安装完软件记得clean
具体实例如下:
创建自定义Dockerfile:
FROM ubuntu:14.04
#基础源镜像
MAINTAINER ailala
#描述镜像的创建者,名称和邮箱
WORKDIR /home
RUN dd if=/dev/zero of=50M.file bs=1M count=50
#创建大小为50M的测试文件
RUN rm -rf 50M.file
#删除该文件
用该文件生成镜像,执行创建镜像命令:
docker build -t test:A .
查看生成镜像信息:
可以看到生成的镜像test:A大小为240M,接下来我们将dockerfile命令进行串联,从而减少层,具体操作如下:
修改Dockerfile文件,将RUN指令通过&&合并到一起:
FROM ubuntu:14.04
#基础源镜像
MAINTAINER ailala
#描述镜像的创建者,名称和邮箱
WORKDIR /home
RUN dd if=/dev/zero of=50M.file bs=1M count=50 && rm -rf 50M.file
#创建文件,同时在改层删除该文件
以此创建新镜像,具体操作与以前相同,镜像名为test:A,同样查看docker images如下:
到此可见同样命令,通过run命令串联,镜像大小缩减了240M-188M=52M
注:
其实我们可以发现,前面例子中的dockerfile中只是简单执行了创建文件,然后删除该文件的操作,文件创建后再删除。常规我们一般会认为这种操作实际没有占用存储空间,这里就是docker 镜像的不同之处,由上文我们可以得知,dockerfile创建每条指令都是一个layers层,之后layers层的操作不会影响上一层,也就是说即使我们在该RUN层进行rm -rf 50M.file删除操作,也只是在本层中起作用,而上一层创建的文件依然保留,不会受到影响。所有尽可能将操作指令合并到同一个RUN层中,从而达到精简镜像的目的。
【Docker】镜像分层存储与镜像精简的更多相关文章
- docker文件系统分层存储原理
一,前言 众所周知,docker镜像技术的基础是联合文件系统(UnionFS),其文件系统是分层的,那它的分层机制是什么样的呢?共分为几种层呢?又是怎么工作的呢? 目前docker支持的联合文件系统有 ...
- 专业分析docker的分层存储技术
话不在多,指明要点! 联合挂载是用于将多个镜像层的文件系统挂载到一个挂载点来实现一个统一文件系统视图的途径, 是下层存储驱动(aufs.overlay等) 实现分层合并的方式. 所以严格来说,联合挂载 ...
- docker基础属性简介包含镜像 容器 registry服务等概念及关系
Docker 镜像 我们都知道,操作系统分为内核和用户空间.对于 Linux 而言,内核启动后,会挂载 root 文件系统为其提供用户空间支持.而 Docker 镜像(Image),就相当于是一个 r ...
- Docker这些none:none的镜像,难道就不配拥有名字吗
1 前言 欢迎访问南瓜慢说 www.pkslow.com获取更多精彩文章! 搞容器开发一段时间后,想看看都有哪些镜像,执行了一下docker images -a,蒙圈了,有一堆<none> ...
- 理解Docker镜像分层
关于base镜像 base 镜像有两层含义: 不依赖其他镜像,从 scratch 构建. 其他镜像可以之为基础进行扩展. 所以,能称作 base 镜像的通常都是各种 Linux 发行版的 Docker ...
- Dockerfile 自动制作 Docker 镜像(三)—— 镜像的分层与 Dockerfile 的优化
Dockerfile 自动制作 Docker 镜像(三)-- 镜像的分层与 Dockerfile 的优化 前言 a. 本文主要为 Docker的视频教程 笔记. b. 环境为 CentOS 7.0 云 ...
- 『现学现忘』Docker基础 — 26、Docker镜像分层的理解
目录 1.分层的镜像 2.加深理解 3.特别说明 1.分层的镜像 我们可以去下载一个镜像,注意观察下载的日志输出,可以看到Docker的镜像是一层一层的在下载. 思考:为什么Docker镜像要采用这种 ...
- Docker镜像文件存储结构
docker相关文件存放在:/var/lib/docker目录下 镜像的存储结构主要分两部分,一是镜像ID之间的关联,一是镜像ID与镜像名称之间的关联,前者的结构体叫Graph,后者叫TagStore ...
- docker 私有仓库镜像的存储位置
docker 私有仓库的镜像 是存储在5739360d1030 registry "docker-registry" 3 days ago Up 28 hours 0.0.0.0: ...
随机推荐
- 1-1.go开发工具安装
(1) (2) bin:go的可执行文件 src:go的源代码 (3)安装开发工具 安装:goland-2018.1.1.exe 将.jar文件复制到工具的bin目录下 用记事本打开“goland ...
- hdu5137 枚举删点
#include<stdio.h> #include<string.h> #include<algorithm> using namespace std; ; ; ...
- ACM:树的变换,依据表达式建立表达式树
题目:输入一个表达式.建立一个表达式树. 分析:找到最后计算的运算符(它是整棵表达式树的根),然后递归处理! 在代码中.仅仅有当p==0的时候.才考虑这个运算符,由于括号中的运 ...
- idea列编辑模式
当我们想要选中一列时,在eclipse中alt+shit+a就可以选中一列了, 在网上很多的idea中列编辑的使用,但是对我的电脑却不管用,也不太清楚在哪里设置 最后无奈乱试一通,结果找到了 alt+ ...
- python的str,unicode对象的encode和decode方法, Python中字符编码的总结和对比bytes和str
python_2.x_unicode_to_str.py a = u"中文字符"; a.encode("GBK"); #打印: '\xd6\xd0\xce\xc ...
- HashSet的运用
TestHashSet.java package com.sxt.set1; /* * Set接口 唯一:元素唯一(不重复) * 无序:不是按照添加的顺序显示数据 * 采用哈希表的方式存储 * 根据哈 ...
- Navicat连接MySQL8.0版本时 建议升级连接客户端这个提示怎么办
开始->mysql 8.0 command line client ->执行下面的命令//开启mysql服务mysql.server start//进入mysqlmysql -u root ...
- 19-1 djanjo中admin的简单用法
1. 创建管理员账号 python3 manage.py createsuperuser 2. 在admin注册我们的表 在app目录下面的admin.py里面按以下语法注册 admin.site.r ...
- Libev源码分析08:Libev中的信号监视器
Libev中的信号监视器,用于监控信号的发生,因信号是异步的,所以Libev的处理方式是尽量的将异步信号同步化.异步信号的同步化方法主要有:signalfd.eventfd.pipe.sigwaiti ...
- maxCompute odps 行转列
select name ,REGEXP_REPLACE(str,"[\\[\"\\]]",'') from ( select trans_array(, ",& ...