镜像的分层结构:

实际上,Docker Hub 中 99% 的镜像都是通过在 base 镜像中安装和配置需要的软件构建出来的。比如我们现在构建一个新的镜像,Dockerfile 如下:

① 新镜像不再是从 scratch 开始,而是直接在 Debian base 镜像上构建。
② 安装 emacs 编辑器。
③ 安装 apache2。
④ 容器启动时运行 bash。

构建过程如下图所示:

可以看到,新镜像是从 base 镜像一层一层叠加生成的。每安装一个软件,就在现有镜像的基础上增加一层。

问什么 Docker 镜像要采用这种分层结构呢?

最大的一个好处就是 - 共享资源

比如:有多个镜像都从相同的 base 镜像构建而来,那么 Docker Host 只需在磁盘上保存一份 base 镜像;同时内存中也只需加载一份 base 镜像,就可以为所有容器服务了。而且镜像的每一层都可以被共享,我们将在后面更深入地讨论这个特性。

这时可能就有人会问了:如果多个容器共享一份基础镜像,当某个容器修改了基础镜像的内容,比如 /etc 下的文件,这时其他容器的 /etc 是否也会被修改?

答案是不会!
修改会被限制在单个容器内。因为容器的Copy-on-Write特性

可写的容器层

当容器启动时,一个新的可写层被加载到镜像的顶部。
这一层通常被称作“容器层”,“容器层”之下的都叫“镜像层”。

所有对容器的改动 - 无论添加、删除、还是修改文件都只会发生在容器层中。

    1. 添加文件
      在容器中创建文件时,新文件被添加到容器层中。

    2. 读取文件 在容器中读取某个文件时,Docker 会从上往下依次在各镜像层中查找此文件。一旦找到,立即将其复制到容器层,然后打开并读入内存。

    3. 修改文件 在容器中修改已存在的文件时,Docker 会从上往下依次在各镜像层中查找此文件。一旦找到,立即将其复制到容器层,然后修改之。

    4. 删除文件 在容器中删除文件时,Docker 也是从上往下依次在镜像层中查找此文件。找到后,会在容器层中记录下此删除操作。

只有当需要修改时才复制一份数据,这种特性被称作 Copy-on-Write。可见,容器层保存的是镜像变化的部分,不会对镜像本身进行任何修改。

这样就解释了我们前面提出的问题:容器层记录对镜像的修改,所有镜像层都是只读的,不会被容器修改,所以镜像可以被多个容器共享

如何构建镜像

使用现成镜像的好处除了省去自己做镜像的工作量外,更重要的是可以利用前人的经验。特别是使用那些官方镜像,因为 Docker 的工程师知道如何更好的在容器中运行软件。

当然,某些情况下我们也不得不自己构建镜像,比如:

  1. 找不到现成的镜像,比如自己开发的应用程序。

  2. 需要在镜像中加入特定的功能,比如官方镜像几乎都不提供 ssh。

所以本节我们将介绍构建镜像的方法。同时分析构建的过程也能够加深我们对前面镜像分层结构的理解。

Docker 提供了两种构建镜像的方法:

  1. docker commit 命令

  2. Dockerfile 构建文件

Docker官方推荐使用Dockerfile构建镜像。

镜像缓存

Docker 会缓存已有镜像的镜像层,构建新镜像时,如果某镜像层已经存在,就直接使用,无需重新创建。

Dockerfile 中每一个指令都会创建一个镜像层,上层是依赖于下层的。无论什么时候,只要某一层发生变化,其上面所有层的缓存都会失效。

也就是说,如果我们改变 Dockerfile 指令的执行顺序,或者修改或添加指令,都会使缓存失效。

DockerFile

Dockerfile指令说明

指令

说明

用法

FROM

指定base镜像

两种用法:

1.FROM <image>

指定基础image为该image的最后修改的版本

2.FROM <image>:<tag>

指定基础image为该image的一个tag版本。

MAINTAINER

设置镜像的作者,用于将image的制作者相关的信息写入到image中

MAINTAINER <name>

RUN

在容器中运行制定的命令,

一般用于装软件

两种格式:

1.RUN <command> (the command is run in a shell - `/bin/sh -c`)

2.RUN ["executable", "param1", "param2" ... ]  (exec form)

CMD

(设置container启动时执行的操作)

三种方式

  1. CMD ["executable","param1","param2"]   2.CMD command param1 param2 (as a shell)

第三种方式:当指定了ENTRYPOINT,那么使用下面的格式

CMD ["param1","param2"] (as default parameters to ENTRYPOINT)

ENTRYPOINT指定的是一个可执行的脚本或者程序的路径,该指定的脚本或者程序将会以param1和param2作为参数执行。所以如果CMD指令使用上面的形式,那么Dockerfile中必须要有配套的ENTRYPOINT。

ENTRYPOINT

配置容器启动后执行的命令,并且不可被 docker run 提供的参数覆盖。

每个 Dockerfile 中只能有一个 ENTRYPOINT,当指定多个时,只有最后一个起效。

ENTRYPOINT ["executable", "param1", "param2"] (like an exec, the preferred form)

ENTRYPOINT command param1 param2 (as a shell)

该指令的使用分为两种情况,一种是独自使用,另一种和CMD指令配合使用。

当独自使用时,如果你还使用了CMD命令且CMD是一个完整的可执行的命令,那么CMD指令和ENTRYPOINT会互相覆盖只有最后一个CMD或者ENTRYPOINT有效。

# CMD指令将不会被执行,只有ENTRYPOINT指令被执行

CMD echo “Hello, World!”

ENTRYPOINT ls -l

另一种用法和CMD指令配合使用来指定ENTRYPOINT的默认参数,这时CMD指令不是一个完整的可执行命令,仅仅是参数部分;ENTRYPOINT指令只能使用JSON方式指定执行命令,而不能指定参数。

FROM ubuntu

CMD ["-l"]

ENTRYPOINT ["/usr/bin/ls"]

EXPOSE

设置指令,该指令会将容器中的端口映射成宿主机器中的某个端口。当你需要访问容器的时候,可以不是用容器的IP地址而是使用宿主机器的IP地址和映射后的端口。要完成整个操作需要两个步骤,首先在Dockerfile使用EXPOSE设置需要映射的容器端口,然后在运行容器的时候指定-p选项加上EXPOSE设置的端口,这样EXPOSE设置的端口号会被随机映射成宿主机器中的一个端口号。

EXPOSE <port> [<port>...]

ENV

用于设置环境变量

设置了后,后续的RUN命令都可以使用,容器启动后,可以通过docker inspect查看这个环境变量,也可以通过在docker run --env key=value时设置或修改环境变量。

假如你安装了JAVA程序,需要设置JAVA_HOME,那么可以在Dockerfile中这样写:

ENV JAVA_HOME /path/to/java/dirent

ADD

从src复制文件到容器的dest路径

如果是一个目录,那么会将该目录下的所有文件添加到容器中,不包括目录;如果文件是可识别的压缩格式,则docker会帮忙解压缩(注意压缩格式)

ADD  <src>  <dist>

<src>是相对被构建的源目录的相对路径,可以是文件或目录的路径,也可以是一个远程的文件url;

<dist>是容器的绝对路径

VOLUMN

设置指令,使容器中的一个目录具有持久化存储数据的功能,该目录可以被容器本身使用,也可以共享给其他容器使用。我们知道容器使用的是AUFS,这种文件系统不能持久化数据,当容器关闭后,所有的更改都会丢失。当容器中的应用有持久化数据的需求时可以在Dockerfile中使用该指令。

VOLUME ["<mountpoint>"]

例:

FROM unbuntu

VOLUMN [“/tmp/data”]运行通过该Dockerfile生成image的容器,/tmp/data目录中的数据在容器关闭后,里面的数据还存在。

WORKDIR

可以多次切换(相当于cd命令),对RUN,CMD,ENTRYPOINT生效。

例:# 在 /p1/p2 下执行 vim a.txt

WORKDIR /p1 WORKDIR p2 RUN vim a.txt

每天学一点Docker(6)——镜像和DockerFile的更多相关文章

  1. 创建Python数据分析的Docker镜像+Docker自定义镜像commit,Dockerfile方式解析+pull,push,rmi操作

    实例解析Docker如何通过commit,Dockerfile两种方式自定义Dcoker镜像,对自定义镜像的pull,push,rmi等常用操作,通过实例创建一个Python数据分析开发环境的Dock ...

  2. 每天学一点Docker(1)

    Docker能做些什么? 1.docker能够解决虚拟机能够解决的问题 2.隔离应用依赖 3.创建应用镜像并复制 4.创建容易分发的即启即用的应用 5.docker的想法是创建软件程序可移植的轻量容器 ...

  3. 每天学一点Docker(5)——了解Docker架构

    Docker的核心组件: 1.Docker客户端 - Client 2.Docker服务器 - Docker deamon 3.Docker镜像 - Image 4.仓库 - Registry 5.D ...

  4. 每天学一点Docker(4)-深入了解容器概念

    什么是容器? 容器是一个自包含,可移植,轻量级的软件打包技术.是应用程序在任何地方几乎以相同方式运行.开发人员在开发机上创建好容器,无需任何修改就能在虚拟机,云服务器或公有云主机上运行. 容器与虚拟机 ...

  5. 每天学一点Docker(3)(制作你的第一个容器)

    今天开始制作第一个容器,其实很简单 首先你要准备这些条件: 1.一个Ubuntu系统 2.这个系统能够联网,最起码ping www.baidu.com是可以的 这些准备条件准备好了,接下来就开始做准备 ...

  6. 每天学一点Docker(2)

    容器runtime 容器runtime是容器真正运行的地方,runtime需要和操作系统kernel紧密结合,为容器提供运行环境. 比如说,java程序比作一个容器,JVM就是runtime.JVM为 ...

  7. Docker教程:镜像构建和自动镜像构建dockerfile

    http://blog.csdn.net/pipisorry/article/details/50805379 Docker透过Dockerfile来记录建立Container映象文件的每一个步骤,可 ...

  8. docker 应用-2(Dockerfile 编写以及镜像保存提交)

    我们可以从docker hub上pull别人的镜像,也可以将容器进行修改,然后commit镜像,并把镜像push到docker hub上被被人使用.但是,直接pull或者push镜像的方式太过笨重,尤 ...

  9. Docker容器学习梳理 - Dockerfile构建镜像

    在Docker的运用中,从下载镜像,启动容器,在容器中输入命令来运行程序,这些命令都是手工一条条往里输入的,无法重复利用,而且效率很低.所以就需要一 种文件或脚本,我们把想执行的操作以命令的方式写入其 ...

随机推荐

  1. spring boot与jdbcTemplate的整合案例2

    简单入门了spring boot后,接下来写写跟数据库打交道的案例.博文采用spring的jdbcTemplate工具类与数据库打交道. 下面是搭建的springbootJDBC的项目的总体架构图: ...

  2. LDA数学八卦笔记(一)Gamma函数

    Technorati Tags: LDA主题模型

  3. 剑指 offer代码解析——面试题39推断平衡二叉树

    题目:输入一颗二叉树的根结点.推断该树是不是平衡二叉树. 假设某二叉树中随意结点的左右子树的高度相差不超过1,那么它就是一棵平衡二叉树. 分析:所谓平衡二叉树就是要确保每一个结点的左子树与右子树的高度 ...

  4. 003Java语言环境搭建

    JRE,JDK JRE(Java Runtime Environment java运行环境):包括java虚拟机和java程序所需要的核心类库, 如果要运行一个开发好的java程序,计算机中只需要安装 ...

  5. selenium+python安装配置

    一.安装步骤 1.python安装 2.selenium安装     2.1. 方法一:在Windows命令行(cmd)输入pip install selenium即可自动安装selenium,安装完 ...

  6. 【quickhybrid】API规划

    前言 当一切就绪后,就要开始进行API规划,这一块是整个Hybrid框架中非常重要的内容,毕竟对于前端页面来说,只会通过JS API来调用功能. 基本上,API调用起来是否方便简洁影响着整个体验. 这 ...

  7. webpack入门(2)

    webpack入门(2) ps:每个案例都是基于前一个案例改造的 webpack入门(1) 戳这里 案例源码戳这里 十二.ProvidePlugin 自动加载模块 new webpack.Provid ...

  8. 抓包工具 fiddler

    1. 抓包软件 TCP 外挂: 1. 解包工具  2.抓包工具 HTTP 1.前后端交互过程 2.学习的作用 3.模拟网络情况 2 http client server 没有加密 https 证书 非 ...

  9. org.springframework.web.HttpMediaTypeNotAcceptableException: Could not find acceptable representation

    异常信息 org.springframework.web.HttpMediaTypeNotAcceptableException: Could not find acceptable represen ...

  10. 浅析JavaScript的字符串查找函数:indexOf和search

    语法 ①indexOf:方法可返回某个指定的字符串值在长字符串中首次出现的位置.如果被查找字符串没有找到,返回-1. indexOf 说明:该方法将从头到尾地检索字符串 stringObject,看它 ...