ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

docker镜像

2020-02-21 17:10:38  阅读:260  来源: 互联网

标签:容器 RUN CMD ENTRYPOINT 镜像 docker


base镜像(通常为各种linux发行版的docker镜像):

 (1)不依赖其他镜像,从scratch构建

 (2)其他镜像可以以之为基础创建

镜像的分层结构

 新镜像是从base镜像层一层一层叠加生成的。没安装一个软件,就现有镜像的基础层面上面增加一层

 好处:共享资源。比如有多个镜像都是从相同的base镜像构建而来,那么docker host只需要在磁盘上保存一份base镜像;同时,内存中也只需要增加一份base镜像,就可以为所有容器服务了,而且镜像的每一层都可以被共享

 镜像层数量可能会很多,所有镜像层会联合在一起组成一个统一的文件系统。如果不同层中有一个相同路径的文件,用户只能访问上层容器中的文件。在容器层中,用户看到的是一个叠加之后的文件系统

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

 (2)读取文件。在容器中读取某个文件时,docker会从上往下依次搜索各镜像层中查找此文件,一旦找到,打开并读入内存

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

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

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

构建镜像

 (1)docker commit

     步骤:1.运行容器

                 2.修改容器
                 3.将容器保存为新镜像(docker commit 旧镜像名 新镜像名)

 (2)docker file

     步骤:1.编写dockerfile文件

                 2.运行docker build命令(docker build -t 新镜像名 .(命令末尾的.指明build-context为当前目录。docker默认会从build context中查找dockerfile文件,我们也可以通过-f参数指定dockerfile的位置))

                  3.开始构建过程,首先docker将docker context中的所有文件发送给docker daemon。build context为镜像构建提供所需要的文件或目录。dockerfile中的ADD、COPY等命令可以将build context中的文件添加到镜像

                  4.按dockerfile文件内容进行执行指令

                  5.镜像构建成功

查看镜像分层结构:docker history 镜像名

 

注:missing表示无法获取image id,通常从docker hub下载的镜像会有这个问题

镜像的缓存特性

 docker会缓存已有的镜像层,构建镜像时,如果某镜像层已经存在,就直接使用,无需创建,如果不希望在构建镜像时使用缓存,可以在docker build命令中加上--no-cache参数。dockerfile中每一个指令都会创建一个镜像层,上层依赖于下层的。无论什么时候,只要某一层发生变化,其上面所有层的缓存都会失效。除了构建时使用缓存,docker在下载镜像时也会使用

调试dockerfile

 在执行dockerfile时,如果因为某种原因执行到某个指令失败了,也能够得到前一个指令成功执行构建出的容器,可以运行新的镜像,手动运行那条失败的指令,从而定位失败的原因

dockerfile常用指令

 FROM:指定base镜像

 MAINTAINER:设置镜像的作者,可以是任意字符串

 COPY:将文件从build context复制到镜像。COPY支持两种形式:COPY src dest与COPY [“scr”,”dest”]

       注意:src只能指定build context中的文件或目录

  ADD:与COPY类似,从build context复制文件到镜像。不同的是,如果src是归档类文件(tar、zip、tgz、xz等),文件会被解压到dest

  ENV:设置环境变量,环境变量可被后面的指令使用。例如:ENV MY_VERSION 1.3 RUN apt-get install -y mypackage=$MY_VERSION

  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 vs CMD vs ENTRYPOINT

 RUN、CMD、ENTRYPOINT这三个dockerfile指令看上去很类似,很容易混淆。本节将通过实践详细讨论它们的区别

 简单的说:

  1. RUN:执行命令并创建新的镜像层,RUN经常用于安装软件包
  2. CMD:设置容器启动后默认执行的命令及参数,但CMD能够被docker run后面跟的命令行参数替换
  3. ENTRYPOINT:配置容器启动时运行的命令

 shell和exec格式

 可以用两种方法指定RUN、CMD和ENTRYPOINT要运行的命令:shell格式和exec格式,二者在使用上有细微的差别。

 shell格式:<instruction> <command>

 例如:

 RUN yum install python3

 CMD echo “hello world”

 ENTRYPOINT echo “hello world”

 当执行指令时,shell格式底层会调用/bin/sh -c [command]。例如下面片段:

 ENV name cloud ENTRYPOINT echo “hello,$name”

 执行docker run时,将输出hello,cloud

 exec格式:<instruction> [“executable”,”paraml”,”param2”]

 例如:

 RUN [“apt-get”,”install”,”python3”]

 CMD [“/bin/echo”,”hello world”]

 ENTRYPOINT [“/bin/echo”,”hello world”]

 当执行指令时,会直接调用command,不会被shell解析。例如下面片段:

 ENV name cloud [“/bin/echo”,”hello,$name”]

 运行容器将输出hello,$name

注意:环境变量name没有被替换,如果希望使用环境变量,做如下修改

ENV name cloud ENTRYPOINT [“/bin/sh”,”-c”,”echo hello,$name”]

运行容器将输出hello,cloud

CMD和ENTRYPOINT推荐使用exec格式,因为指令可读性更强,更容易理解。RUN则两种格式都可以

RUN

RUN指令通常用于安装应用和软件包,RUN在当前镜像的顶部执行命令,并创建新的镜像层。dcokerfile中常常包含多个RUN指令。

 RUN有两种格式:

(1)shell格式:RUN

(2)exec格式:RUN [“executable”,”param1”,”param2”]

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

 RUN apt-get u[date && apt-get install -y subversion

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

 CMD

 CMD指令允许用户指定容器的默认执行的命令,此命令会在容器启动且docker run没有指定其他命令时运行

 如果docker run指定了其他命令,CMD指定的默认命令将被忽略,如果dockerfile中有多个CMD指令,只有最后一个有效

 CMD有三种格式:

(1)exec格式:CMD [“executable”,”param1”,”param2”]这是CMD推荐格式

(2)CMD [“param1”,”param2”]为ENTRYPOINT提供额外的参数,此时ENTRYPOINT必须使用exec格式

(3)shell格式:CMD command param1 param2

 第一种和第三种已经介绍过了,第二种要与exec格式的ENTRYPOINT指令配合使用,其用途是为ENTRYPOINT设置默认的参数。

下面看看CMD是如何工作的。dockerfile片段如下:

CMD echo “hello world”

运行容器docker run -it [image]将输出:hello world,但在后面加上一个命令,比如docker run -it [image] /bin/bash,CMD会被忽略掉,命令bash将被执行

 ENTRYPOINT

 ENTRYPOINT指令可以让容器以应用程序或者服务的形式运行,ENTRYPOINT看上去与CMD很像,它们都可以指定要执行的命令及参数。不同之处在于ENTRYPOINT不会被忽略,一定会被执行,即使docker run时指定了其他命令

 ENTRYPOINT有两种格式:

  1. exec格式:ENTRYPOINT [“executable”,”param1”,”param2”]这是ENTRYPOINT的推荐格式
  2. shell格式:ENTRYPOINT command param1 param2

 在为ENTRYPOINT选择格式时必须要小心,因为这两种格式的效果差别很大

  1. exec格式

 ENTRYPOINT的exec格式用于设置要执行的命令及参数,同时可以通过CMD提供额外的参数,ENTRYPOINT中的参数始终会被使用,而CMD的额外参数可以在启动容器时动态替换

 比如下面的dockerfile片段:

 ENTRYPOINT [“/bin/echo”,”hello”] CMD [“world”]

 当容器通过docker run -it [image]启动时,输出为:hello world

 而如果通过docker run -it [image] cloud时,输出为:hello cloud

       2.shell格式

 ENTRYPOINT的shell格式会忽略任何CMD给docker run提供的参数

分发镜像

 为镜像命名

     镜像名一般是两部分组成的:[image name]=[repository]:[tag],如果没有指定tag,默认会使用latest,tag常用于描述镜像的版本信息,可以是任意字符串

     注:latest其实没有什么特殊含义。当没有指定镜像tag时,docker会使用默认值latest,仅此而已。docker hub上很多仓库将latest作为最新稳定版本的别称,但这只是一种约定,而不是强制规定,所以最好还是避免使用这个

     命令:docker tag 旧镜像名 新镜像名

使用公共registry

 docker hub是docker公司维护的公共registry。用户可以将自己的镜像保存在docker hub免费的repository中,如果不希望别人访问自己的镜像,也可以购买私有repository

 (1)首先在docker hub上注册一个账号

 (2)在docker host上登录(docker login -u 用户名)

 (3)修改镜像的repoistory,使之与docker hub账号对应。docker hub为了区分不同的同名镜像,镜像的registry中要包含用户名,完整的格式为:[username]/xxx:tag。通过docker tag命令重命名镜像

 (4)docker push 镜像名:将镜像上传到docker hub

 搭建本地registry

 (1)启动registry容器(使用的是registry:2镜像)

 -d:后台启动容器

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

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

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

 

 在镜像前面加上了registry的主机名称和端口。前面已经讨论了镜像名称由repository和tag两部分组成。而repository的完整格式为:[registry-host]:[port]/[username]/xxx,只有docker hub上的镜像可以省略registry-host:[port]

 (2)通过docker push上传镜像,此时,就可以使用docker pull进行下载镜像。

啸月々兲狼 发布了11 篇原创文章 · 获赞 1 · 访问量 1250 私信 关注

标签:容器,RUN,CMD,ENTRYPOINT,镜像,docker
来源: https://blog.csdn.net/qq_37339132/article/details/104424532

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有