Docker——理解好镜像和容器的关系
关注公众号,大家可以在公众号后台回复“博客园”,免费获得作者 Java 知识体系/面试必看资料。
镜像也是 docker 的核心组件之一,镜像时容器运行的基础,容器是镜像运行后的形态。前面我们介绍了容器的用法,今天来和大家聊聊镜像的问题。
本文是本系列的第四篇,阅读前面文章有助于更好的理解本文:
总体来说,镜像是一个包含程序运行必要以来环境和代码的只读文件,它采用分层的文件系统,将每一层的改变以读写层的形式增加到原来的只读文件上。这有点像洋葱,一层一层的,当我们后面学习了 Dockerfile ,相信大家对于这样的架构理解将更为准确。
镜像与容器的关系
前文已经向读者介绍过容器的使用了,细心的读者可能已经发现,容器在启动或者创建时,必须指定一个镜像的名称或者 id ,其实,这时镜像所扮演的角色就是容器的模版,不同的镜像可以构造出不同的容器,同一个镜像,我们也可以通过配置不同参数来构造出不通的容器。如下命令:
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>
。一般来说,仓库名称有如下几种不同的形式:
[namespace\ubuntu]
:这种仓库名称由命名空间和实际的仓库名组成,中间通过\
隔开。当开发者在 Docker Hub 上创建一个用户时,用户名就是默认的命名空间,这个命令空间是用来区分 Docker Hub 上注册的不同用户或者组织(类似于 GitHub 上用户名的作用),如果读者想将自己的镜像上传到 Docker Hub 上供别人使用,则必须指定命名空间,否则上传会失败。[ubuntu]
:这种只有仓库名,对于这种没有命名空间的仓库名,可以认为其属于顶级命名空间,该空间的仓库只用于官方的镜像,由 Docker 官方进行管理,但一般会授权给第三方进行开发维护。当然用户自己创建的镜像也可以使用这种命名方式,但是将无法上传到 Docker Hub 上共享。[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。
创建容器
首先,根据本地镜像运行一个容器,如下:
命令解释:
首先执行 docker images 命令,查看本地镜像。
根据本地镜像中的 nginx 镜像,创建一个名为 nginx 的容器,并启动。
将宿主机中一个名为 index.html 的文件拷贝到容器中。
访问容器,发现改变已经生效。
接下来再重新创建一个容器,名为 nginx2.
访问 nginx2 ,发现 nginx2 中默认的页面还是 nginx 的默认页面,并未发生改变。
commint 创建本地镜像
接下来,根据刚刚创建的第一个容器,创建一个本地镜像,如下:
命令解释:
参数 -m 是对创建的该镜像的一个简单描述。
--author 表示该镜像的作者。
ce1fe32739402 表示创建镜像所依据的容器的 id。
sang/nginx 则表示仓库名,sang 是名称空间,nginx 是镜像名。
v1 表示仓库的 tag。
创建完成后,通过 docker images 命令就可以查看到刚刚创建的镜像。
通过刚刚创建的镜像运行一个容器,访问该容器,发现 nginx 默认的首页已经发生改变。
这是我们通过 commint 方式创建本地镜像的方式,但是 commit 方式存在一些问题,比如不够透明化,无法重复,体积较大,为了解决这些问题,可以考虑使用 Dockerfile ,实际上,主流方案也是 Dockerfile。
Dockerfile
Dockerfile 就是一个普通的文本文件,其内包含了一条条的指令,每一条指令都会构建一层。先来看一个简单的例子。
首先在一个空白目录下创建一个名为 Dockerfile 的文件,内容如下:
命令解释:
FROM nginx 表示该镜像的构建,以已有的 nginx 镜像为基础,在该镜像的基础上构建。
MAINTAINER 指令用来声明创建镜像的作者信息以及邮箱信息,这个命令不是必须的。
RUN 指令用来修改镜像,算是使用比较频繁的一个指令了,该指令可以用来安装程序、安装库以及配置应用程序等,一个 RUN 指令执行会在当前镜像的基础上创建一个新的镜像层,接下来的指令将在这个新的镜像层上执行,RUN 语句有两种不同的形式:shell 格式和 exec 格式。本案例采用的 shell 格式,shell 格式就像 linux 命令一样,exec 格式则是一个 JSON 数组,将命令放到数组中即可。在使用 RUN 命令时,适当的时候可以将多个 RUN 命令合并成一个,这样可以避免在创建镜像时创建过多的层。
COPY 语句则是将镜像上下文中的
hello.html
文件拷贝到镜像中。
文件创建完成后,执行如下命令进行构建:
命令解释:
-t 参数用来指定镜像的命名空间,仓库名以及 TAG 等信息。
最后面的
.
是指镜像构建上下文。
注意:
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——理解好镜像和容器的关系的更多相关文章
- docker简单介绍----镜像和容器管理
docker可以分为三部分:docker镜像 docker仓库 docker容器 docker镜像:一个image可以包含一个镜像,也可以理解为一个系统模板,里面安装了相关应用,也可以是纯净版的 ...
- Docker配置本地镜像与容器的存储位置
默认情况下Docker的存放位置为:/var/lib/docker 可以通过下面命令查看具体位置: sudo docker info | grep "Docker Root Dir" ...
- docker 使用:镜像和容器
docker 镜像 docker image是一个极度精简版的Linux程序运行环境,官网的java镜像包括的东西更少,除非是镜像叠加方式的如centos+java7,需要定制化build的一个安装包 ...
- docker的安装和基本的docker命令、镜像和容器的操作
1.yum 包更新到最新 yum update 2.安装需要的软件包, yum-util 提供yum-config-manager功能,另外两个是devicemapper驱动依赖的 yum insta ...
- docker 启动 centos 镜像,容器会自动退出
docker启动centos镜像有两种版本可以解决自动退出的问题: 方式一: docker run -d -it [image-ID] /bin/sh 方式二: 在启动脚本里面增加一个执行进程: 1. ...
- 【docker】关于docker 中 镜像、容器的关系理解
例如,使用docker 拉取下来一个要用的镜像es docker pull elasticsearch:5.6.9 此时es的镜像存在与服务器上 docker images 对于你运行镜像为一个容器的 ...
- Docker删除全部镜像和容器
杀死所有正在运行的容器 docker kill $(docker ps -a -q) 删除所有已经停止的容器 docker rm $(docker ps -a -q) 删除所有未打 dangling ...
- Docker - 使用 Jenkins 镜像创建容器,并搭建 Python + Pytest +Allure 的自动化测试环境
如果你还想从头学起 Docker,可以看看这个系列的文章哦! https://www.cnblogs.com/poloyy/category/1870863.html 安装 Docker 直接参考我这 ...
- docker安装mysql镜像和容器
下拉镜像 docker pull mysql/mysql-server:5.5 后面的mysql标签是版本号,是可选择的,有: 5.5 5.6 5.7 8.0 创建mysql5.5的容器 docker ...
随机推荐
- .NetCore中三种注入方式的思考
该篇内容由个人博客点击跳转同步更新!转载请注明出处! .NetCore彻底诠释了"万物皆可注入"这句话的含义,在.NetCore中到处可见注入的使用.因此core中也提供了三种注入 ...
- 试题--创建三个进程/线程,依次输出 A、B、C
这是一道机试题,大概的预期执行结果如下图所示 最近刚好在学习linux编程,便使用多线程及多进程分别实现了一遍,其中多线程较为简单,使用0/1信号量在线程间实现生产者/消费者即可:多进程则稍微复杂一些 ...
- CDH 5.15.2 离线安装
一.前置准备 1. 基础信息 1.1 机器 机器名 服务 hadoop1 主节点 hadoop2 data.task hadoop3 data.task 1.2 服务版本 服务 版本 cdh 5.15 ...
- C#中的委托和事件(下篇)
上次以鸿门宴的例子写了一篇博文,旨在帮助C#初学者迈过委托和事件这道坎,能够用最快的速度掌握如何使用它们.如果觉得意犹未尽,或者仍然不知如何在实际应用中使用它们,那么,这篇窗体篇,将在Winform场 ...
- 数字IC前后端设计中的时序收敛(二)--Setup违反的修复方法
本文转自:自己的微信公众号<数字集成电路设计及EDA教程> 里面主要讲解数字IC前端.后端.DFT.低功耗设计以及验证等相关知识,并且讲解了其中用到的各种EDA工具的教程. 考虑到微信公众 ...
- python3+pyQt5+QtDesignner实现窗口化猜数字游戏
描述:使用QtDesignner设计界面,pyQt5+python3实现主体方法制作的猜数字游戏. 游戏规则:先选择游戏等级:初级.中级.高级.魔鬼级,选择完游戏等级后点击“确定”,然后后台会自动生成 ...
- OpenCV多版本切换和配置--opencv 安装与卸载、添加 opencv_contrib modules 以及 OpenCv 多版本切换
1. 查看安装Opencv的版本.以及libs和cflags $ pkg-config --modversion opencv $ pkg-config --cflags opencv // 编译链接 ...
- Java编程思想:为什么要使用内部类
public class Test { public static void main(String[] args) { Callbacks.test(); } } /* 为什么需要内部类: 1.可以 ...
- PG利用Multicorn访问CSV外部数据源
Multicorn 是一个 PostgreSQL 9.1+ 的扩展模块,用于简化外部数据封装开发,允许开发者使用 Python 编程语言开发. Install Multicorn Requiremen ...
- Excel催化剂开源第36波-图片Exif信息提取,速度超快,信息超全
Excel催化剂在文件处理方面,功能做到极致,但其实很大功劳都是引用一些开源社区的轮子库,不敢独占好处,此篇给大家分享下抓取图片的Exif信息的好用的轮子. 此篇对应的Excel催化剂功能实现:第83 ...