Docker镜像

镜像的缓存特性

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

举例说明

      在前面构建的test/ubuntu镜像中添加新的内容,往里面复制一个文件

root@ubuntu:~# ls           ①

Dockerfile  testfile

root@ubuntu:~#

root@ubuntu:~# docker build -t test/ubuntu:v2 .

Sending build context to Docker daemon 32.77 kB

Step 1 : FROM ubuntu

 ---> f753707788c5

Step 2 : RUN apt-get update && apt-get install -y vim

 ---> Using cache         ②

 ---> 35ca89798937

Step 3 : COPY testfile /---> 8d02784a78f4

Removing intermediate container bf2b4040f4e9

Successfully built 8d02784a78f4

 

      对上面的步骤进行相应的说明:先确保testfile文件存在。在Dockerfile文件执行过程中,运行RUN指令时,由于之前已经运行过相同的RUN指令,这次直接使用缓存中的镜像层。最后直接执行COPY指令,其过程是启动临时容器,复制testfile文件,提交新的镜像层,再删除生成的临时容器。全部过程执行完毕,就得到了所需的在test/ubuntu镜像上直接添加一层新的镜像的test/ubuntu:v2

 

      如果构建镜像时不想使用缓存,可以在docker build命令中添加--no-cache参数

      Dockerfile中每一个指令都会创建一个镜像层,上层依赖下层。无论什么时候,只要某一层发生变化,其上面的所有层的缓存都会失效。也就是说,如果我们修改Dockerfile指令的顺序,或者修改、添加指令,都会使缓存失效

 

      比如这里修改前面的Dockerfile文件,交换一下指令的执行顺序

      从逻辑上说,这对整个镜像的构建没有什么影响,但对于docker镜像的缓存来说,这里已经改变了下层镜像的结构,而上层镜像依赖于下层镜像,当下层镜像发生变化时,原来的镜像缓存则不再生效。这里的执行过程:先执行FROM指令,在本地找到基础镜像并运行一个容器,然后在该容器中执行COPY指令,该指令执行完毕后删除生成的临时容器,最后再执行RUN指令。如果是前面的顺序,执行RUN指令时会直接用test/ubuntu镜像的缓存,但这里先是执行了COPY指令,导致下层镜像发生变化,所以这里得重新执行RUN指令,其过程与test/ubuntu的过程一样

 

调试Dockerfile

先后顾Dockerfile构建镜像的过程

      1. 从基础镜像运行一个容器

      2. 执行一条指令,对容器进行修改

      3. 执行类似docker commit的操作,生成一个新的镜像层

      4. Docker再基于刚提交的镜像运行一个新的容器

      5. 重复2-4步,直到Dockerfile中的所有指令执行完毕

      从这个过程可以看出,如果Dockerfile由于某种原因执行到某个指令失败了,我们也能够得到前一个指令成功执行构建出的镜像,这对调试很有帮助,可以运行最新的镜像来定位指令失败的原因

下面来看一个调试的例子,Dockerfile文件的内容如下 

执行docker build

Dockerfile运行到第三部时失败,我们可以利用第二步得到的镜像进行调试,方法是docker run -it启动镜像的一个容器 

      手工执行RUN命令很容易定位失败的原因,此处是因为busybox镜像中没有bash。这个例子很好的展示了Dockerfile的调试方法

 

Dockerfile常用的指令

      FROM:指定基础镜像

      MAINTAINER:说明镜像作者信息,可以是任意字符串。它不是Dockerfile的必要内容,但为了便于镜像的维护,建议写上去

      COPY:将文件从build context复制到镜像

      ADD:与COPY类似,从build context复制文件到镜像。不同的是,如果src是归档文件,文件会被自动解压到dest

      ENV:设置环境变量,环境变量可被后面的指令使用

      EXPOSE:指定容器中的进程会监听某个端口,Docker可以将该端口暴露出来

      VOLUME:将文件或目录声明为volume

      WORKDIR:为后面的RUN、CMD、ENTRYPOINT、ADD、COPY指令设置镜像中的当前工作目录

      RUN:在容器中运行指定的命令

      CMD:容器启动时运行指定的命令。Dockerfile中可以有多个CMD指令,但只有最后一个生效。CMD可被docker run之后的参数替换

      ENTRYPOINT:设置容器启动时运行的命令。Dockerfile中可以有多个ENTRYPOINT指令,但只有最后一个生效。CMD或docker run之后的参数会被当做参数传递给ENTRYPOINT

 

RUN、CMD、ENTRYPOINT的区别

      1. RUN执行命令并创建新的镜像层,RUN经常用于安装软件包

      2. CMD设置容器启动后默认执行的命令及其参数,但CMD能够被docker run后面跟的命令行参数替换

      3. ENTRYPOINT配置容器启动时运行的命令

 

RUN

      下面是使用RUN安装多个软件包的例子

RUN apt-get update && apt-get install -y \  

 wireshark\

 vim\

 wget \

 mercurial \

 subversion

      注意:apt-get update和apt-get install被放在一个RUN指令中执行,这样能够保证每次安装的是最新的包。如果apt-get install在单独的RUN中执行,则会使用apt-get update创建的镜像层,而这一层可能是很久以前的缓存了

 

CMD

此命令在容器启动且docker run没有指定其他命令时运行

      1. 如果docker run指定了其他命令,CMD指定的默认命令会被忽略

      2. 如果Dockerfile中有多个CMD指令,只有最后一个有效

下面看看CMD是如何工作的,Dockerfile片段如下

CMD echo “Hello world”

运行容器docker run -it [ image ] 将输出

Hello world

但当后面加一个命令,比如docker run -it [ image ] /bin/bash,CMD会被忽略掉,命令bash将被执行

root@10a32dc7d3d3:/#

 

ENTRYPOINT

      ENTRYPOINT指令可让容器以应用程序或者服务的形式运行

      ENTRYPOINT看上去和CMD很像,它们都可以指定要执行的命令及其参数,不同的地方在于ENTRYPOINT不会被忽略,一定会被执行,即使运行docker run时指定了其他命令

 

使用公共Registry

下面介绍如何使用Docker Hub存放镜像

1. 首先得在Docker Hub上注册一个账号(当我们在hub.docker.com上注册账号时发现不能注册,可以在用谷歌浏览器登录,并在上面安装谷歌访问助手,安装完成后并可以注册。另一种方法是直接FQ)

2. 在Docker Hub上登录 

这里用的是我自己的账号,用户名为chenjin2018,输入密码即可登录

3. 修改镜像的repository使之与Docker Hub账号匹配

Docker Hub为了区分不同用户名的同名镜像,镜像的registry中要包含用户名,完整个格式为:[username]/xxx:tag

我们通过docker tag命令重命名镜像 

4. 通过docker push将镜像上传到Docker Hub 

5. 登录hub.docker.com,在Public Repository中就可以看到上传的镜像 

如果要删除镜像,只能在Docker Hub界面上操作

6. 其他用户只需用docker pull就可以下载并使用这个镜像了

 

搭建本地的Registry

1. 启动registry容器

我们使用的镜像是registry:2

-d是以守护方式启动容器

-p将容器的5000端口映射到Host的5000端口。5000是registry服务端口

-v将容器/var/lib/registry目录映射到Host的/myregistry,用于存放镜像数据

2. 通过docker tag重命名镜像,使之与registry匹配 

我们在镜像前面加了运行registry的主机名称和端口

repositroy的完整格式:[registry-host]:[port]/[username]/xxx

只有Docker Hub上的镜像可以省略[registry-host]:[port]

3. 通过docker push上传镜像 

4. 现在已经可以通过docker pull从本地registry下载镜像了

 

Docker镜像小结

下面是镜像的常用操作子命令

      images   显示镜像列表

      history  显示镜像构建历史

      commit   从容器创建新镜像

      build    从Dockerfile中构建新镜像

      tag      给镜像打tag

      pull     从registry下载镜像

      push     将镜像上传到registry

      rmi      删除Docker host中的镜像

      search   搜索Docker Hub中的镜像

 

posted @ 2018-10-20 18:56  Chenjin2018  阅读(293)  评论(0编辑  收藏  举报