一、Docker镜像是什么?

  操作系统分为内核用户空间。在Linux中,内核启动后会挂载 root 文件系统为其提供用户空间支持。

  docker镜像就相当于一个 root文件系统。比如:官方镜像ubuntu:18.04就包含了一套Ubuntu最小系统的root文件系统。

  虽然docker镜像相当于一个root文件系统,但它是一个特殊的文件系统,不仅提供容器运行时所需的程序、库、资源、配置等文件,还包含运行时准备的一些配置参数(如:匿名卷、环境变量、用户等)。

二、分层存储与镜像构建

  Docker设计时充分利用 Union FS 的技术,将其设计为分层存储的架构。镜像只是一个虚拟的概念,并不是一个类似ISO的打包文件,是由多层文件系统联合组成。

1、UnionFS

  联合文件系统(Union File System):2004年由纽约州立大学石溪分校开发,它可以把多个目录(也叫分支)内容联合挂载到同一个目录下,而目录的物理位置是分开的。UnionFS允许只读和可读写目录并存,就是说可同时删除和增加内容。

  Linux各发行版实现的UnionFS各不相同,因此Docker在Linux发行版中使用的也不同。可以通过docker info 来查看docker使用的是哪一种UnionFS。目前Dokcer支持如下几种storage driver 如下所示:

  

详见:Docker之几种storage-driver比较

2、镜像构建

  镜像构建时会一层层构建,前一层是后一层的基础。
  每一层构建完就不再发生改变,后一层上的任何改变只发生在自己这一层。
  由于这个特性,操作删除前一层文件,并没有真的删除前一层的文件,而是紧紧在当前层标记该文件删除。在容器运行时不会看到该文件,但改文件会一直跟随镜像。
  因此构建镜像时,需要格外小心,每一层尽量只包含该层需要添加的东西,任何额外的东西在该层构建结束前清除掉。

三、使用镜像

1、获取镜像

  从docker镜像仓库获取镜像的命令是 docker pull 。命令格式如下所示:

$ docker pull [选项] [Docker Registry 地址[:端口号]/仓库名[:标签]]
# Dokcer镜像仓库地址:格式一般是<域名/IP>[:端口号],默认地址是 Docker Hub
# 仓库名:两段式名称,<用户名>/<软件名>,对Docker Hub,如果不给出用户名,默认为 library,也就是官方镜像。

  获取ubuntu镜像示例:

[root@kwephicprc03547 yum.repos.d]# docker pull ubuntu:18.04
18.04: Pulling from library/ubuntu
9ef5b901d87c: Pull complete # 层id
3daad4f91066: Pull complete
7e9f0564ef6f: Pull complete
fc001299f620: Pull complete
Digest: sha256:7a47ccc3bbe8a451b500d2b53104868b46d60ee8f5b35a24b41a86077c650210 # 镜像完整的sha256摘要
Status: Downloaded newer image for ubuntu:18.04

  注意:

  (1)由于镜像名称为ubuntu:18.04,一次获取官方镜像 library/ubuntu仓库中标签为 18.04 的镜像。
  (2)由于镜像是由多层存储构成,因此下载也是一层层下载。
  (3)下载过程中显示了每一层id的前12位。
  (4)下载完成输出完整sha256摘要以保证下载一致性。
  (5)层ID和sha256下载并不都一致,因为官方一直在维护,处理BUG或版本更新。

2、列出镜像

  想列出已经下载下来的镜像,可以使用 docker images 或者 docker image ls 命令。

[root@kwephicprc03547 yum.repos.d]# docker images
#仓库名 标签 镜像ID 创建时间 所占用的空间
REPOSITORY TAG IMAGE ID CREATED SIZE
euler latest da5bac89d64d days ago .15GB
ubuntu 18.04 21e0cf71370f weeks ago .9MB
hello-world latest de6f0c40d4e5 weeks ago .75kB
centos/aarch64 latest b1b73535f567 months ago 236MB
[root@kwephicprc03547 yum.repos.d]# docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
euler latest da5bac89d64d days ago .15GB
ubuntu 18.04 21e0cf71370f weeks ago .9MB
hello-world latest de6f0c40d4e5 weeks ago .75kB
centos/aarch64 latest b1b73535f567 months ago 236MB

  注意:镜像ID才是镜像的唯一标识,一个镜像可以对应多个标签

3、镜像体积

  docker images列出镜像所标识的占用空间和在Docker Hub上看到的镜像大小是不同的。

  Docker Hub地址:https://hub.docker.com/_/ubuntu?tab=tags

  Docker Hub中显示的体积是压缩后的体积。

  在镜像下载和上传过程中镜像都是保持在压缩状态的,因此这个镜像大小关注的是网络传输中的流量。

  但是docker images列表中的镜像体积总和也并不是所有镜像的实际消耗:
  1)Docker镜像是多层存储结构,可以继承、复用,因此不同的镜像可能使用的是相同的基础镜像,从而拥有共同的层。
  2)Union FS技术下,相同的层只需要保存一份即可,因此实际镜像硬盘占用空间往往比列表镜像大小总和小很多。
  3)查看镜像、容器、数据卷所占用的空间:

$ docker system df
TYPE TOTAL ACTIVE SIZE RECLAIMABLE
Images .4MB .9MB (%)
Containers .2MB 0B (%)
Local Volumes 0B 0B
Build Cache 0B 0B

4、镜像删除

  要删除本地镜像其命令格式如下所示:

docker image rm [OPTIONS] IMAGE [IMAGE...]
docker rmi [OPTIONS] IMAGE [IMAGE...]
docker image remove [OPTIONS] IMAGE [IMAGE...] Remove one or more images
Aliases:
rm, rmi, remove
Options:
-f, --force Force removal of the image
--no-prune Do not delete untagged parents 

  删除镜像可以使用镜像短id、镜像长id、镜像名、镜像摘要。删除镜像示例如下所示:

[root@kwephicprc03547 ~]# docker rmi hello-world
Untagged: hello-world:latest
Untagged: hello-world@sha256:2557e3c07ed1e38f26e389462d03ed943586f744621577a99efb77324b0fe535
Deleted: sha256:de6f0c40d4e5d0eb8e13fa62ccbbdabad63be2753c9b61f495e7f1f486be1443
Deleted: sha256:26d82c2b34c3dedc481b7db3d84c3d1892a6a82cd97624767c4217beb382e7f8

  删除镜像时,实际上是在要求删除某个标签的镜像。删除镜像的几种情况分析:

  首先需要将满足要求的所有镜像标签取消,即Untagged信息。

  其次当镜像所有的标签都被取消,镜像失去了存在的意义,触发删除行为。从上层向基础层依次进行判断删除。

  如果取消了标签,但是这个镜像仍被其他标签指向,则不会触发删除行为。而且镜像是多层结构,如果有某些镜像依赖于当前镜像的某一层,也不会触发删除行为,直到没有任何层依赖当前层,才会真是删除当前层。

  由于容器是以镜像为基础,再加一层容器存储层,因此镜像启动的容器依然存在也是不可以删除当前镜像的。

四、docker commit理解和使用

  镜像地多层存储的,每一层在前一层的基础上进行修改;容器也是多层存储,以镜像为基础层,在其基础上加一层作为容器运行时的存储层。

  运行容器时(如果不使用卷),任何文件修改都会被记录在容器存储层里。

  docker commit命令,可以将容器的存储层保存下来成为镜像:在原镜像基础上,叠加容器存储层,构成新的镜像。

1、容器修改案例

(1)启动一个nginx容器

  用nginx镜像启动一个容器,命名为webserver,且映射80端口:

[root@kwephicprc03547 ~]# docker run --name webserver -d -p  nginx
Unable to find image 'nginx:latest'
locallylatest: Pulling from library/nginx
42367302fc78: Pull complete
a9cb25c539ce: Pull complete
07dff5c0fced: Pull complete
Digest: sha256:dd2d0ac3fff2f007d99e033b64854be0941e19a2ad51f174d9240dda20d9f534
Status: Downloaded newer image for nginx:latest
84d5102335b184f04e9f9060cafe38ac5216424e641036cc1fab2f84d9140937

  可以在浏览器直接访问该页面:

(2)修改容器nginx页面显示

  以交互终端方式进入webserver容器,执行shell命令修改index.html:

[root@kwephicprc03547 ~]# docker exec -ti webserver bash
root@84d5102335b1:/# echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html

  刷新浏览器,显示内容如下所示:

   

  修改容器文件就修改了容器的存储层,利用docker diff 命令查看具体改动:

[root@kwephicprc03547 ~]# docker diff webserver
C /usr
C /usr/share
C /usr/share/nginx
C /usr/share/nginx/html
C /usr/share/nginx/html/index.html
C /var
C /var/cache
C /var/cache/nginx
A /var/cache/nginx/fastcgi_temp
A /var/cache/nginx/proxy_temp
A /var/cache/nginx/scgi_temp
A /var/cache/nginx/uwsgi_temp
A /var/cache/nginx/client_temp
C /root
A /root/.bash_history
C /runA /run/nginx.pid

2、使用docker commit定制镜像

  docker commit语法格式:

docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]

Create a new image from a container's changes

Options:
-a, --author string Author (e.g., "John Hannibal Smith <hannibal@a-team.com>")
-c, --change list Apply Dockerfile instruction to the created image
-m, --message string Commit message
-p, --pause Pause container during commit (default true)

(1)将webserver容器保存为镜像

[root@kwephicprc03547 ~]# docker commit \
> --author 'hqs' \ # 指定修改的作者
> --message "修改欢迎页面显示" \ # 记录本次修改内容
> webserver \ # 容器名
> nginx:v2 # 仓库名:标签
sha256:c795dacab9b490ff99ee3ea2493eae7675f2c550c5f66064ddaf5a0f7dc14755

(2)查看新定制的镜像

[root@kwephicprc03547 ~]# docker image ls nginx
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx v2 c795dacab9b4 minutes ago 103MB
nginx latest 9235bd14ba8c weeks ago 103MB

再使用docker history查看镜像内历史记录:

  

3、docker commit总结

  docker diff webserver可以发现,容器中除了真正要修改的/user/share/nginx/html/index.html文件外,还有很多文件被改动或添加了。如果是安装软件、编译构建则会有大量的无关内容被添加进去,导致镜像非常臃肿

  docker commit意味着对镜像的操作是黑箱操作,生成的也是黑箱镜像。除了制作镜像人知道执行过什么发生过什么,其他人无从得知。这将导致维护非常困难

  因此定制镜像应该使用 Dockerfile 来完成。

docker镜像使用和总结的更多相关文章

  1. MySQL、MongoDB、Redis数据库Docker镜像制作

    MySQL.MongoDB.Redis数据库Docker镜像制作 在多台主机上进行数据库部署时,如果使用传统的MySQL的交互式的安装方式将会重复很多遍.如果做成镜像,那么我们只需要make once ...

  2. 理解Docker(2):Docker 镜像

    本系列文章将介绍Docker的有关知识: (1)Docker 安装及基本用法 (2)Docker 镜像 (3)Docker 容器的隔离性 - 使用 Linux namespace 隔离容器的运行环境 ...

  3. 如何合并两个Docker 镜像

    http://www.open-open.com/lib/view/open1437746544709.html 在你的机器上使用docker pull来从Docker Hub下载镜像. docker ...

  4. Docker镜像的管理和创建

    1. Docker镜像和Docker容器:      Docker镜像实际上是一系列的文件系统,通常的Linux系统一般是两层文件系统,bootfs和rootfs,bootfs就是bootloader ...

  5. docker 源码分析 四(基于1.8.2版本),Docker镜像的获取和存储

    前段时间一直忙些其他事情,docker源码分析的事情耽搁了,今天接着写,上一章了解了docker client 和 docker daemon(会启动一个http server)是C/S的结构,cli ...

  6. docker使用阿里云Docker镜像库加速

    官方镜像下载实在是慢,于是开通了阿里云开发者帐号, 官方帮助 阿里云Docker镜像库 阿里云容器Hub服务:http://dev.aliyun.com/search.html 来自云端的容器Hub服 ...

  7. 第四章 使用Docker镜像和仓库(二)

    第四章 使用Docker镜像和仓库(二) 回顾: 开始学习之前,我先pull下来ubuntu和fedora镜像 [#9#cloudsoar@cloudsoar-virtual-machine ~]$s ...

  8. 第四章 使用Docker镜像和仓库

    第4章 使用Docker镜像和仓库 回顾: 回顾如何使用 docker run 创建最基本的容器 $sudo docker run -i -t --name another_container_mum ...

  9. 将 ASP.NET Core 1.0 应用作为 docker 镜像发布 (Linux版)

    var appInsights=window.appInsights||function(config){ function r(config){t[config]=function(){var i= ...

  10. Docker镜像

    docker镜像123? 额,由于没有实验环境,没有亲手实践,因此理解可能有不对的地方. 反正也是学习笔记,以后再修改吧... docker的镜像跟virtualbox的镜像不一样.在虚拟机中,镜像是 ...

随机推荐

  1. python2-url编解码

    #coding:utf-8import urllibs={"username":"hhh","password":"XXXX&qu ...

  2. P4168 [Violet]蒲公英 区间众数

    $ \color{#0066ff}{ 题目描述 }$ 在乡下的小路旁种着许多蒲公英,而我们的问题正是与这些蒲公英有关. 为了简化起见,我们把所有的蒲公英看成一个长度为n的序列 \((a_1,a_2.. ...

  3. UVALive-3399-Sum of Consecutive Prime Numbers(素数筛,暴力)

    原题链接 写个素数筛暴力打表一波就AC了: #include <iostream> using namespace std; const int N = 10001; int i, j, ...

  4. 2016级算法第二次上机-E.AlvinZH的儿时梦想——运动员篇

    862-AlvinZH的儿时梦想--运动员篇 思路 难题. 应该想到,不管给出的数据如何,每一个淘汰的人不会对最终答案产生任何影响,所以每次淘汰就把人除掉就可以了,最后剩下的两个人计算它们从开始到相遇 ...

  5. python 控制台输出带颜色的文字的方法

    python_控制台输出带颜色的文字方法   在python开发的过程中,经常会遇到需要打印各种信息.海量的信息堆砌在控制台中,就会导致信息都混在一起,降低了重要信息的可读性.这时候,如果能给重要的信 ...

  6. 解决myeclipse打开.form文件报错

    症状: 打开AutoEKPMainFrm.form文件的时候出现如下问题:

  7. POJ_3368 Frequent values 【线段树+区间查询】

    一.题面 POJ3368 二.分析 仍然是一道只需要区间查询不需要区间修改的线段树题. 这题的题面比较特别,它是一组非减的数组.当需要去找一段区间内出现次数最多的数字时,这些数字必然是连续的,那么就可 ...

  8. 时间超限问题处理(c++)

    c++中 如果时间超上限 做题上: 考虑关于二进制的方法 比如说 find your present (2) 这道题 可以用异或运算 来发现不重复数 对于动态规划 状态压缩发面 方面应用更多 比如说p ...

  9. mysql出现 Unknown column 'bname' in 'where clause'和Unknown column 'bid' in 'field list'

    在用mysql数据库建表和修改数据库数据时,出现  Unknown column 'bname' in 'where clause'和Unknown column 'bid' in 'field li ...

  10. 在浏览器中输入URL后,执行的全部过程。(一次完整的http请求过程)

    整个流程如下: 域名解析 为了将消息从你的PC上传到服务器 上.需要用到1P协议.ARP协议和0SPF协议 发起TCP的3次握手 建立TCP连接后发起http请求 服务器响应htp请求 浏览器解析ht ...