关注公众号,大家可以在公众号后台回复“博客园”,免费获得作者 Java 知识体系/面试必看资料。 

镜像也是 docker 的核心组件之一,镜像时容器运行的基础,容器是镜像运行后的形态。前面我们介绍了容器的用法,今天来和大家聊聊镜像的问题。

​本文是本系列的第四篇,阅读前面文章有助于更好的理解本文:


1.Docker 入门及安装[Docker 系列-1]

2.Docker 容器基本操作[Docker 系列-2]

3.Docker 容器高级操作[Docker 系列-3]


总体来说,镜像是一个包含程序运行必要以来环境和代码的只读文件,它采用分层的文件系统,将每一层的改变以读写层的形式增加到原来的只读文件上。这有点像洋葱,一层一层的,当我们后面学习了 Dockerfile ,相信大家对于这样的架构理解将更为准确。

镜像与容器的关系

前文已经向读者介绍过容器的使用了,细心的读者可能已经发现,容器在启动或者创建时,必须指定一个镜像的名称或者 id ,其实,这时镜像所扮演的角色就是容器的模版,不同的镜像可以构造出不同的容器,同一个镜像,我们也可以通过配置不同参数来构造出不通的容器。如下命令:

  1. docker run -itd --name nginx nginx

命令中的最后一个 nginx 即表示创建该容器所需要的镜像(模版),当然这里还省略了一些信息,例如版本号等,这些我们后文会详细介绍。

镜像的体系结构

镜像的最底层是一个启动文件系统(bootfs)镜像,bootfs 的上层镜像叫做根镜像,一般来说,根镜像是一个操作系统,例如 Ubuntu、CentOS 等,用户的镜像必须构建于根镜像之上,在根镜像之上,用户可以构建出各种各样的其他镜像。
从上面的介绍读者可以看出,镜像的本质其实就是一系列文件的集合,一层套一层的结构有点类似于 Git ,也有点类似于生活中的洋葱

镜像的写时复制机制

通过 docker run 命令指定一个容器创建镜像时,实际上是在该镜像之上创建一个空的可读写的文件系统层级,可以将这个文件系统层级当成一个临时的镜像来对待,而命令中所指的模版镜像则可以称之为父镜像。父镜像的内容都是以只读的方式挂载进来的,容器会读取共享父镜像的内容,用户所做的所有修改都是在文件系统中,不会对父镜像造成任何影响。当然用户可以通过其他一些手段使修改持久化到父镜像中,这个我们后面会详细介绍到。

简而言之,镜像就是一个固定的不会变化的模版文件,容器是根据这个模版创建出来的,容器会在模版的基础上做一些修改,这些修改本身并不会影响到模版,我们还可以根据模版(镜像)创建出来更多的容器。

如果有必要,我们是可以修改模版(镜像)的。

镜像查看

用户可以通过 docker images 命令查看本地所有镜像,如下:

这里一共有五个参数,含义分别如下:

  • TAG: TAG用于区分同一仓库中的不同镜像,默认为latest。

  • IMAGE ID: IMAGE ID是镜像的一个唯一标识符。

  • CREATED: CREATED表示镜像的创建时间。

  • SIZE: SIZE表示镜像的大小。

  • REPOSITORY:仓库名称,仓库一般用来存放同一类型的镜像。仓库的名称由其创建者指定。如果没有指定则为 <none> 。一般来说,仓库名称有如下几种不同的形式:

  1. [namespace\ubuntu]:这种仓库名称由命名空间和实际的仓库名组成,中间通过 \ 隔开。当开发者在 Docker Hub 上创建一个用户时,用户名就是默认的命名空间,这个命令空间是用来区分 Docker Hub 上注册的不同用户或者组织(类似于 GitHub 上用户名的作用),如果读者想将自己的镜像上传到 Docker Hub 上供别人使用,则必须指定命名空间,否则上传会失败。

  2. [ubuntu]:这种只有仓库名,对于这种没有命名空间的仓库名,可以认为其属于顶级命名空间,该空间的仓库只用于官方的镜像,由 Docker 官方进行管理,但一般会授权给第三方进行开发维护。当然用户自己创建的镜像也可以使用这种命名方式,但是将无法上传到 Docker Hub 上共享。

  3. [hub.c.163.com/library/nginx]:这种指定 url 路径的方式,一般用于非 Docker Hub 上的镜像命名,例如一个第三方服务商提供的镜像或者开发者自己搭建的镜像中心,都可以使用这种命名方式命名。

使用 docker images 命令可以查看本地所有的镜像,如果镜像过多,可以通过通配符进行匹配,如下:

如果需要查看镜像的详细信息,也可以通过上文提到的 docker inspect 命令来查看。

镜像下载

当用户执行 docker run 命令时,就会自动去 Docker Hub 上下载相关的镜像,这个就不再重复演示,开发者也可以通过 search 命令去 Docker Hub 上搜索符合要求的镜像,如下:

其中:

  • NAME:表示镜像的名称。

  • DESCRIPTION:表示镜像的简要描述。

  • STARS:表示用户对镜像的评分,评分越高越可以放心使用。

  • OFFICIAL:是否为官方镜像。

  • AUTOMATED:是否使用了自动构建。

在执行 docker run 命令时再去下载,速度会有点慢,如果希望该命令能够快速执行,可以在执行之前,先利用 docker pull 命令将镜像先下载下来,然后再运行。

运行命令如下:

镜像删除

镜像可以通过 docker rmi 命令进行删除,参数为镜像的id或者镜像名,参数可以有多个,多个参数之间用空格隔开。如下:

有的时候,无法删除一个镜像,大部分原因是因为该镜像被一个容器所依赖,此时需要先删除容器,然后就可以删除镜像了,删除容器的命令可以参考本系列前面的文章。

通过前面文章的阅读,读者已经了解到所谓的容器实际上是在父镜像的基础上创建了一个可读写的文件层级,所有的修改操作都在这个文件层级上进行,而父镜像并未受影响,如果读者需要根据这种修改创建一个新的本地镜像,有两种不同的方式,先来看第一种方式:commit。

创建容器

首先,根据本地镜像运行一个容器,如下:

命令解释:

  1. 首先执行 docker images 命令,查看本地镜像。

  2. 根据本地镜像中的 nginx 镜像,创建一个名为 nginx 的容器,并启动。

  3. 将宿主机中一个名为 index.html 的文件拷贝到容器中。

  4. 访问容器,发现改变已经生效。

  5. 接下来再重新创建一个容器,名为 nginx2.

  6. 访问 nginx2 ,发现 nginx2 中默认的页面还是 nginx 的默认页面,并未发生改变。

commint 创建本地镜像

接下来,根据刚刚创建的第一个容器,创建一个本地镜像,如下:

命令解释:

  1. 参数 -m 是对创建的该镜像的一个简单描述。

  2. --author 表示该镜像的作者。

  3. ce1fe32739402 表示创建镜像所依据的容器的 id。

  4. sang/nginx 则表示仓库名,sang 是名称空间,nginx 是镜像名。

  5. v1 表示仓库的 tag。

  6. 创建完成后,通过 docker images 命令就可以查看到刚刚创建的镜像。

  7. 通过刚刚创建的镜像运行一个容器,访问该容器,发现 nginx 默认的首页已经发生改变。

这是我们通过 commint 方式创建本地镜像的方式,但是 commit 方式存在一些问题,比如不够透明化,无法重复,体积较大,为了解决这些问题,可以考虑使用 Dockerfile ,实际上,主流方案也是 Dockerfile。

Dockerfile

Dockerfile 就是一个普通的文本文件,其内包含了一条条的指令,每一条指令都会构建一层。先来看一个简单的例子。

首先在一个空白目录下创建一个名为 Dockerfile 的文件,内容如下:

命令解释:

  1. FROM nginx 表示该镜像的构建,以已有的 nginx 镜像为基础,在该镜像的基础上构建。

  2. MAINTAINER 指令用来声明创建镜像的作者信息以及邮箱信息,这个命令不是必须的。

  3. RUN 指令用来修改镜像,算是使用比较频繁的一个指令了,该指令可以用来安装程序、安装库以及配置应用程序等,一个 RUN 指令执行会在当前镜像的基础上创建一个新的镜像层,接下来的指令将在这个新的镜像层上执行,RUN 语句有两种不同的形式:shell 格式和 exec 格式。本案例采用的 shell 格式,shell 格式就像 linux 命令一样,exec 格式则是一个 JSON 数组,将命令放到数组中即可。在使用 RUN 命令时,适当的时候可以将多个 RUN 命令合并成一个,这样可以避免在创建镜像时创建过多的层。

  4. COPY 语句则是将镜像上下文中的 hello.html 文件拷贝到镜像中。

文件创建完成后,执行如下命令进行构建:

命令解释:

  1. -t 参数用来指定镜像的命名空间,仓库名以及 TAG 等信息。

  2. 最后面的 . 是指镜像构建上下文。

注意

Docker 采用了 C/S 架构,分为 Docker 客户端(Docker 可执行程序)与 Docker 守护进程,Docker 客户端通过命令行和 API 的形式与 Docker 守护进程进行通信,Docker 守护进程则提供 Docker 服务。因此,我们操作的各种 docker 命令实际上都是由 docker 客户端发送到 docker 守护进程上去执行。我们在构建一个镜像时,不可避免的需要将一些本地文件拷贝到镜像中,例如上文提到的 COPY 命令,用户在构建镜像时,需要指定构建镜像的上下文路径(即前文的 . ), docker build 在获得这个路径之后,会将路径下的所有内容打包,然后上传给 Docker 引擎。

镜像构建成功后,可以通过 docker images 命令查看,如下:

然后创建容器并启动,就可以看到之前的内容都生效了。

总结

本文主要向大家介绍了 Docker 中镜像的基本操作,操作其实并不难,关键是理解好镜像和容器的关系,以及镜像洋葱式的文件结构。

Java 极客技术公众号,是由一群热爱 Java 开发的技术人组建成立,专注分享原创、高质量的 Java 文章。如果您觉得我们的文章还不错,请帮忙赞赏、在看、转发支持,鼓励我们分享出更好的文章。

 

Docker——理解好镜像和容器的关系的更多相关文章

  1. docker简单介绍----镜像和容器管理

    docker可以分为三部分:docker镜像   docker仓库  docker容器 docker镜像:一个image可以包含一个镜像,也可以理解为一个系统模板,里面安装了相关应用,也可以是纯净版的 ...

  2. Docker配置本地镜像与容器的存储位置

    默认情况下Docker的存放位置为:/var/lib/docker 可以通过下面命令查看具体位置: sudo docker info | grep "Docker Root Dir" ...

  3. docker 使用:镜像和容器

    docker 镜像 docker image是一个极度精简版的Linux程序运行环境,官网的java镜像包括的东西更少,除非是镜像叠加方式的如centos+java7,需要定制化build的一个安装包 ...

  4. docker的安装和基本的docker命令、镜像和容器的操作

    1.yum 包更新到最新 yum update 2.安装需要的软件包, yum-util 提供yum-config-manager功能,另外两个是devicemapper驱动依赖的 yum insta ...

  5. docker 启动 centos 镜像,容器会自动退出

    docker启动centos镜像有两种版本可以解决自动退出的问题: 方式一: docker run -d -it [image-ID] /bin/sh 方式二: 在启动脚本里面增加一个执行进程: 1. ...

  6. 【docker】关于docker 中 镜像、容器的关系理解

    例如,使用docker 拉取下来一个要用的镜像es docker pull elasticsearch:5.6.9 此时es的镜像存在与服务器上 docker images 对于你运行镜像为一个容器的 ...

  7. Docker删除全部镜像和容器

    杀死所有正在运行的容器 docker kill $(docker ps -a -q) 删除所有已经停止的容器 docker rm $(docker ps -a -q) 删除所有未打 dangling ...

  8. Docker - 使用 Jenkins 镜像创建容器,并搭建 Python + Pytest +Allure 的自动化测试环境

    如果你还想从头学起 Docker,可以看看这个系列的文章哦! https://www.cnblogs.com/poloyy/category/1870863.html 安装 Docker 直接参考我这 ...

  9. docker安装mysql镜像和容器

    下拉镜像 docker pull mysql/mysql-server:5.5 后面的mysql标签是版本号,是可选择的,有: 5.5 5.6 5.7 8.0 创建mysql5.5的容器 docker ...

随机推荐

  1. 安装Ruby、多版本Ruby共存、Ruby安装慢问题

    rbenv rbenv可以管理多个版本的ruby.可以分为3种范围(或者说不同生效作用域)的版本: local版:本地,针对各项目范围 global版:全局,没有shell和local版时使用glob ...

  2. Java多线程同步工具类之Semaphore

    Semaphore信号量通常做为控制线程并发个数的工具来使用,它可以用来限制同时并发访问资源的线程个数. 一.Semaphore使用 下面我们通过一个简单的例子来看下Semaphore的具体使用,我们 ...

  3. 渐进式web应用开发---service worker (二)

    阅读目录 1. 创建第一个service worker 及环境搭建 2. 使用service worker 对请求拦截 3. 从web获取内容 4. 捕获离线请求 5. 创建html响应 6. 理解 ...

  4. mongodb数据存储

    # 打开服务端 直接执行abc.bat文件,如果执行闪退可以把data文件夹里的mongod.lock文件先删除 打开cmd窗口, 输入mongo,启动客户端. 也可以通过NoSQLBooster启动 ...

  5. django基础知识之布署:

    布署 从uwsgi.nginx.静态文件三个方面处理 服务器介绍 服务器:私有服务器.公有服务器 私有服务器:公司自己购买.自己维护,只布署自己的应用,可供公司内部或外网访问 公有服务器:集成好运营环 ...

  6. 在FPS游戏中,玩家对音画同步感知的量化与评估

    前言 在游戏测试中,音画同步测试是个难点(所谓游戏音画同步:游戏中,音效与画面的同步程度),现在一般采用人工主观判断的方式测试,但这会带来2个问题: 无法准确量化,针对同一场景的多次测试结果可能会相反 ...

  7. QT知识整理

    1.connect函数的SIGNAL可以是按键.定时器.其他对象的信号.如果是其他对象的信号,对象必须要在当前类中实例化. 2.Qt数据类型转换 1)int转QStringint a=10;QStri ...

  8. 单个单选框radio 点击选中点击取消选中

    $("input:radio").click(function(){ var domName = $(this).attr('name');//获取当前单选框控件name 属性值 ...

  9. 深入理解Java的switch...case...语句

    switch...case...中条件表达式的演进 最早时,只支持int.char.byte.short这样的整型的基本类型或对应的包装类型Integer.Character.Byte.Short常量 ...

  10. C语言学习书籍推荐《C专家编程Expert C Programming Deep C Secrets》下载

    Peter Van Der Linden (作者) <C和C++经典著作 C专家编程Expert C Programming Deep C Secrets>展示了C程序员所使用的编码技巧, ...