windghoul / ContainerCamp

2 stars 1 forks source link

Docker的秘密武器-镜像 #4

Closed mlycore closed 5 years ago

mlycore commented 6 years ago

起初大家都认为Docker不过是新瓶装旧酒,Namespace和CGroups并不是新鲜的东西,所以并未给予太多关注,然而Docker却以迅雷不及掩耳之势席卷了整个云计算市场,引起了一股全球范围的容器化浪潮。究其原因正是Docker的秘密武器——镜像。所以这次的问题是:

  1. Docker镜像是什么?它与Docker容器是什么关系?
  2. 编写自己的Dockerfile,把自己的程序做成镜像并运行。
  3. 为什么Docker镜像如此重要?
  4. Docker镜像的技术点。
donggua2333 commented 6 years ago

1 Docker镜像是什么?它与Docker容器是什么关系?

镜像是 包含一系列必要的文件的根文件系统image

容器运行起来之后,需要使用的配置文件,比如软件仓库源文件/etc/apt/source.list 。容器运行时创建的文件也可以通过 docker export 命令保存起来。通过镜像,我们可以完整的保存容器的运行环境

2 编写自己的Dockerfile,把自己的程序做成镜像并运行

2.1 Dockerfile

dockerfile是一系列命令的集合,包含ADD ,COPY, RUN,CMD等。每执行一条命令,就会生成一个新的镜像层。每一条指令都会在上一条指令生成的镜像上运行

run命令会在当前镜像层上运行 [command]指定的命令,并将执行结果commit到新的镜像层。因此类似 下面的指令是不会产生我们想要的结果的。

RUN cd /tmp
RUN ls .

我们必须要基于一个初始的镜像层来构建镜像。使用指令FROM 指定一个初始镜像。

下面我们来写一个Dockerfile。在这个dockerfile中我们指定初始的镜像是ubuntu:18.04,然后将同级目录中的cpfile复制到 /tmp目录中,并且运行 ls 命令,然后指定容器运行的第一条指令为/bin/sh。

FROM ubuntu:18.04
COPY ./cpfile /tmp
RUN ls /tmp
CMD /bin/sh

2.2 docker build

使用docker build 命令来构建一个镜像。参数 -t 指定镜像的tag,-f 指定dockerfile的路径。在构建镜像时,我们还需要指定镜像的上下文。那么什么是镜像的上下文呢?

还记得我们在使用COPY命令时的情景吗,上下文就是我们要拷贝的文件的父目录。在使用docker build 命令时,会将上下文中的所有文件发送给docker daemon。

使用如下命令,构建镜像:

   docker build -t Lily -f ./Dockerfile . (指定上下文为当前目录)

docker_build

使用docker history命令可以看到每个镜像层,如下图所示: docker_history

可以看到cpfile成功的复制到了/tmp目录: docker_run_lily

4 为什么Docker镜像如此重要?

docker镜像是容器快速部署的关键,通过将容器打包成镜像,我们可以将之前的应用的运行环境完整的复制下来,直接运行即可。

5. Docker镜像的技术点

那么如果我们要删除镜像层的某个文件怎么办呢?先强调一点,虽然镜像是分层的,但是对于容器来说,每一层的文件都是可见的,每一层不是完全隔离的关系。

删除镜像层的文件时,我们并不可能真正的删除该文件,而是在容器层生成一个同名的whiteout文件,该文件实际上是一个字符设备文件。当上层发现一个whiteout文件时,就不会再往下层去查找该文件。

mlycore commented 6 years ago

@DennisWong 第一个回答的赞!思路清晰赞!第4点要再想想哦

naomiyang commented 6 years ago

1.Docker镜像是什么,与Docker容器的关系

Docker镜像是一个只读的 Docker容器模板,含有启动 Docker容器所需的文件系统结构及其内容,因此是启动一个 Docker容器的基础。镜像不包含任何动态数据,其内容在构建之后也不会被改变。 Docker镜像是Docker容器运行的基础,没有Docker镜像,就不可能有Docker容器。Docker容器实际上就是一个或者多个进程,而容器的父进程就是Docker守护进程。Docker守护进程手握Docker镜像的json文件,为容器配置相应的环境,并真正运行Docker镜像所指定的进程,完成Docker容器的真正创建。

2.编写Dockerfile,并运行自己的应用

  1. 建立文件夹 mkdir mydocker cd mydocker
  2. 下载Tomcat的镜像作为基础镜像,docker pull hub.c.163.com/library/tomcat:latest 下载jpress开源项目,下载地址为 ,下载后将jpress移动到mydocker目录下,并重命名为jpress.war
    1. 编写Dockerfile
      FROM hub.c.163.com/library/tomcat
      MAINTAINER yang225217
      COPY jpress.war /usr/local/tomcat/webapps
    2. 编译jpress docker build -t jpress .
    3. 运行编译好的jpress docker run -d -p 8888:8080 jpress 来启动Tomcat
    4. 访问localhost:8888发现Tomcat已经启动,然后访问localhost:8888/jpress。

3.Docker镜像很重要

“容器镜像将会成为未来软件的主流发布方式”。Docker公司创新性地提出了使用多个增量rootfs联合挂载一个完整rootfs的方案,也就是容器镜像中的“层”的概念,通过镜像分层的设计,以Docker镜像为核心,来自不同公司、不同团队的技术人员被紧密联系在了一起。而且,由于容器镜像的操作是增量式的,这样每次镜像拉取、推送的内容,比原来多个完整的操作系统的大小要小得多。而共享层的存在,可以使得这些镜像需要的总空间也比每个镜像的总和要小。一旦这个镜像被发布,那么你在全世界的任何一个地方下载这个镜像,得到的内容都完全一致,可以完全复现这个镜像制作者当初的完整环境。可以说,镜像的发明打通了“开发——测试——部署”流程的每一个环节。

4.Docker镜像的技术点

  1. 镜像分层。Docker镜像在设计的时候,引入了层的概念,用户制作镜像的每一步操作都会生成一个层。当需要修改容器镜像内的某个文件时,只对处于最上方的读写层进行变动,不覆盖下层已有文件系统的内容。
  2. 联合文件系统(UnionFS)主要的功能是将多个不同位置的目录联合挂载到同一个目录下。将挂载点的原目录与被挂载内容进行整合,使得最终可见的文件系统将会包含整合之后的各层的文件和目录。
  3. 写时复制(copy-on-write)在多个容器之间共享镜像,每个容器在启动的时候并不需要单独复制一份镜像文件,而是将所有的镜像层以只读的方式挂载到一个挂载点,再在上面覆盖一个可读写的容器层。在未更改文件内容时,所有的容器共享同一份数据,只有在Docker容器运行的过程中文件系统发生变化时,才会把变化的文件内容写到可读写层,并隐藏只读层中的老版本文件。
mlycore commented 6 years ago

@naomiyang 提到了Docker镜像打通“开发-测试-部署”流水线这个很重要,👍,这个地方有个理论依据是“不可变基础设施”,你可以查查这个然后分享一下 😄

donggua2333 commented 6 years ago

@mlycore 好的,我下来再了解一下。