GVKun编程网logo

Dockerfile RUN, CMD & ENTRYPOINT

15

在本文中,您将会了解到关于DockerfileRUN,CMD&ENTRYPOINT的新资讯,并给出一些关于dockerRUNCMDENTRYPOINT区别、DockerRUNvsCMDvsENTRYP

在本文中,您将会了解到关于Dockerfile RUN, CMD & ENTRYPOINT的新资讯,并给出一些关于docker RUN CMD ENTRYPOINT 区别、Docker RUN vs CMD vs ENTRYPOINT、Docker | dockerfile构建centos镜像,以及CMD和ENTRYPOINT的区别、Docker 中的 Dockerfile 命令详解 FROM RUN COPY ADD ENTRYPOINT...的实用技巧。

本文目录一览:

Dockerfile RUN, CMD & ENTRYPOINT

Dockerfile RUN, CMD & ENTRYPOINT

在使用 Dockerfile 创建 image 时,有几条指令比较容易混淆,RUN, CMD, ENTRYPOINT.

RUN 是在 building image 时会运行的指令,在 Dockerfile 中可以写多条 RUN 指令.

CMD 和 ENTRYPOINT 则是在运行 container 时会运行的指令,都只能写一条,如果写了多条,则最后一条生效.

CMD 和 ENTRYPOINT 的区别是: 

CMD 在运行时会被 command 覆盖,ENTRYPOINT 不会被运行时的 command 覆盖,但是也可以指定.

例如 : 

Usage: docker run [OPTIONS] IMAGE [COMMAND] [ARG...]

  --entrypoint=""            Overwrite the default entrypoint of the image

 

docker run postgres:9.3.5 psql 

这里的 psql 就是 command, 将覆盖 Dockerfile 的 CMD, 但是不会覆盖 ENTRYPOINT.

如果要覆盖 ENTRYPOINT, 那么可以在 docker run 运行时输入 --entrypoint="....".

 

CMD 和 ENTRYPOINT 一般用于制作具备后台服务的 image, 例如 apache, database 等。在使用这种 image 启动 container 时,自动启动服务.

 

这几条指令的详细用法 : 

RUN

RUN has 2 forms:

  • RUN <command> (the command is run in a shell - /bin/sh -c - shell form)
  • RUN ["executable", "param1", "param2"] (exec form)

The RUN instruction will execute any commands in a new layer on top of the current image and commit the results. The resulting committed image will be used for the next step in the Dockerfile.

Layering RUN instructions and generating commits conforms to the core concepts of Docker where commits are cheap and containers can be created from any point in an image''s history, much like source control.

The exec form makes it possible to avoid shell string munging, and to RUN commands using a base image that does not contain /bin/sh.

Note: To use a different shell, other than ''/bin/sh'', use the exec form passing in the desired shell. For example, RUN ["/bin/bash", "-c", "echo hello"]

Note: The exec form is parsed as a JSON array, which means that you must use double-quotes (") around words not single-quotes ('').

Note: Unlike the shell form, the exec form does not invoke a command shell. This means that normal shell processing does not happen. For example, CMD [ "echo", "$HOME" ] will not do variable substitution on $HOME. If you want shell processing then either use the shell form or execute a shell directly, for example: CMD [ "sh", "-c", "echo", "$HOME" ].

The cache for RUN instructions isn''t invalidated automatically during the next build. The cache for an instruction like RUN apt-get dist-upgrade -y will be reused during the next build. The cache for RUNinstructions can be invalidated by using the --no-cache flag, for example docker build --no-cache.

See the Dockerfile Best Practices guide for more information.

The cache for RUN instructions can be invalidated by ADD instructions. See below for details.

Known Issues (RUN)

  • Issue 783 is about file permissions problems that can occur when using the AUFS file system. You might notice it during an attempt to rm a file, for example. The issue describes a workaround.

 

CMD

The CMD instruction has three forms:

  • CMD ["executable","param1","param2"] (exec form, this is the preferred form)
  • CMD ["param1","param2"] (as default parameters to ENTRYPOINT)
  • CMD command param1 param2 (shell form)

There can only be one CMD instruction in a Dockerfile. If you list more than one CMD then only the lastCMD will take effect.

The main purpose of a CMD is to provide defaults for an executing container. These defaults can include an executable, or they can omit the executable, in which case you must specify an ENTRYPOINTinstruction as well.

Note: If CMD is used to provide default arguments for the ENTRYPOINT instruction, both the CMD andENTRYPOINT instructions should be specified with the JSON array format.

Note: The exec form is parsed as a JSON array, which means that you must use double-quotes (") around words not single-quotes ('').

Note: Unlike the shell form, the exec form does not invoke a command shell. This means that normal shell processing does not happen. For example, CMD [ "echo", "$HOME" ] will not do variable substitution on $HOME. If you want shell processing then either use the shell form or execute a shell directly, for example: CMD [ "sh", "-c", "echo", "$HOME" ].

When used in the shell or exec formats, the CMD instruction sets the command to be executed when running the image.

If you use the shell form of the CMD, then the <command> will execute in /bin/sh -c:

FROM ubuntu
CMD echo "This is a test." | wc -

If you want to run your <command> without a shell then you must express the command as a JSON array and give the full path to the executable. This array form is the preferred format of CMD. Any additional parameters must be individually expressed as strings in the array:

FROM ubuntu
CMD ["/usr/bin/wc","--help"]

If you would like your container to run the same executable every time, then you should consider usingENTRYPOINT in combination with CMD. See ENTRYPOINT.

If the user specifies arguments to docker run then they will override the default specified in CMD.

Note: don''t confuse RUN with CMDRUN actually runs a command and commits the result; CMDdoes not execute anything at build time, but specifies the intended command for the image.

 

 

ENTRYPOINT

ENTRYPOINT has two forms:

  • ENTRYPOINT ["executable", "param1", "param2"] (exec form, the preferred form)
  • ENTRYPOINT command param1 param2 (shell form)

There can only be one ENTRYPOINT in a Dockerfile. If you have more than one ENTRYPOINT, then only the last one in the Dockerfile will have an effect.

An ENTRYPOINT helps you to configure a container that you can run as an executable. That is, when you specify an ENTRYPOINT, then the whole container runs as if it was just that executable.

Unlike the behavior of the CMD instruction, The ENTRYPOINT instruction adds an entry command that willnot be overwritten when arguments are passed to docker run. This allows arguments to be passed to the entry point, i.e. docker run <image> -d will pass the -d argument to the entry point.

You can specify parameters either in the ENTRYPOINT JSON array (as in "like an exec" above), or by using a CMD instruction. Parameters in the ENTRYPOINT instruction will not be overridden by the docker runarguments, but parameters specified via a CMD instruction will be overridden by docker run arguments.

Like a CMD, you can specify a plain string for the ENTRYPOINT and it will execute in /bin/sh -c:

FROM ubuntu
ENTRYPOINT ls -l

For example, that Dockerfile''s image will always take a directory as an input and return a directory listing. If you wanted to make this optional but default, you could use a CMD instruction:

FROM ubuntu
CMD ["-l"]
ENTRYPOINT ["ls"]

Note: The exec form is parsed as a JSON array, which means that you must use double-quotes (") around words not single-quotes ('').

Note: Unlike the shell form, the exec form does not invoke a command shell. This means that normal shell processing does not happen. For example, CMD [ "echo", "$HOME" ] will not do variable substitution on $HOME. If you want shell processing then either use the shell form or execute a shell directly, for example: CMD [ "sh", "-c", "echo", "$HOME" ].

Note: It is preferable to use the JSON array format for specifying ENTRYPOINT instructions.

docker RUN CMD ENTRYPOINT 区别

docker RUN CMD ENTRYPOINT 区别

 

原文链接: docker RUN CMD ENTRYPOINT 区别

上一篇: docker 常用命令

下一篇: Dockerfile中ENTRYPOINT 和 CMD的区别

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

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

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

 

如果在使用docker run 启动容器时使用了命令行参数,那么dockerfile 中的cmd 指令将无效:

通过ENTRYPOINT 指定的命令需要与docker run 启动容器进行搭配,将docker run 指令后面跟的内容当做参数作为ENTRYPOINT指令指定的运行命令的参数,ENTRYPOINT 指定的linux命令一般是不会被覆盖的。

 

Shell 和 Exec 格式

我们可用两种方式指定 RUN、CMD 和 ENTRYPOINT 要运行的命令:Shell 格式和 Exec 格式,二者在使用上有细微的区别。

Shell 格式

<instruction> <command>


例如:

RUN apt-get install python3  

CMD echo "Hello world"  

ENTRYPOINT echo "Hello world" 


当指令执行时,shell 格式底层会调用 /bin/sh -c <command> 。

例如下面的 Dockerfile 片段:

ENV name Cloud Man  

ENTRYPOINT echo "Hello, $name" 


执行 docker run <image> 将输出:

Hello, Cloud Man

 

Exec 格式

<instruction> ["executable", "param1", "param2", ...]

 

例如:

RUN ["apt-get", "install", "python3"]  

CMD ["/bin/echo", "Hello world"]  

ENTRYPOINT ["/bin/echo", "Hello world"]

 

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

ENV name Cloud Man  

ENTRYPOINT ["/bin/echo", "Hello, $name"]

 

运行容器将输出:

Hello, $name

 

注意环境变量“name”没有被替换。
如果希望使用环境变量,照如下修改

ENV name Cloud Man  

ENTRYPOINT ["/bin/sh", "-c", "echo Hello, $name"]

 

运行容器将输出:

Hello, Cloud Man

 

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

 

 

RUN

RUN 指令通常用于安装应用和软件包。

RUN 在当前镜像的顶部执行命令,并通过创建新的镜像层。Dockerfile 中常常包含多个 RUN 指令。

RUN 有两种格式:

  1. Shell 格式:RUN

  2. Exec 格式:RUN ["executable", "param1", "param2"]

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

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

 bzr \

 cvs \

 git \

 mercurial \

 subversion

 

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

CMD

CMD 指令允许用户指定容器的默认执行的命令。

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

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

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

CMD 有三种格式:

  1. Exec 格式:CMD ["executable","param1","param2"]
    这是 CMD 的推荐格式。

  2. CMD ["param1","param2"] 为 ENTRYPOINT 提供额外的参数,此时 ENTRYPOINT 必须使用 Exec 格式。

  3. Shell 格式:CMD command param1 param2

Exec 和 Shell 格式前面已经介绍过了。
第二种格式 CMD ["param1","param2"] 要与 Exec 格式 的 ENTRYPOINT 指令配合使用,其用途是为 ENTRYPOINT 设置默认的参数。我们将在后面讨论 ENTRYPOINT 时举例说明。

下面看看 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 时指定了其他命令。

ENTRYPOINT 有两种格式:

  1. Exec 格式:ENTRYPOINT ["executable", "param1", "param2"] 这是 ENTRYPOINT 的推荐格式。

  2. Shell 格式:ENTRYPOINT command param1 param2

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

Exec 格式

ENTRYPOINT 的 Exec 格式用于设置要执行的命令及其参数,同时可通过 CMD 提供额外的参数。

ENTRYPOINT 中的参数始终会被使用,而 CMD 的额外参数可以在容器启动时动态替换掉。

比如下面的 Dockerfile 片段:

ENTRYPOINT ["/bin/echo", "Hello"]  

CMD ["world"]

 

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

Hello world

 

而如果通过 docker run -it [image] CloudMan 启动,则输出为:

Hello CloudMan

FROM ubuntu
ENTRYPOINT ["/bin/echo", "Hello"]  
CMD ["world"]

Shell 格式

ENTRYPOINT 的 Shell 格式会忽略任何 CMD 或 docker run 提供的参数。

最佳实践

  1. 使用 RUN 指令安装应用和软件包,构建镜像。

  2. 如果 Docker 镜像的用途是运行应用程序或服务,比如运行一个 MySQL,应该优先使用 Exec 格式的 ENTRYPOINT 指令。CMD 可为 ENTRYPOINT 提供额外的默认参数,同时可利用 docker run 命令行替换默认参数。

  3. 如果想为容器设置默认的启动命令,可使用 CMD 指令。用户可在 docker run 命令行中替换此默认命令。

Docker RUN vs CMD vs ENTRYPOINT

Docker RUN vs CMD vs ENTRYPOINT

<table><tr>
<td><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150

功能咋看起来很相似的指令,开始的时候觉得两个互用没什么所谓,但其实并非如此:       CMD指令:   The main purpose of a CMD is to provide defaults for an executing container.   CMD在容器运行的时候提供一些命令及参数,用法如下:   CMD ["executable","param1","param2"] (exec form,this is the preferred form) CMD ["param1","param2"] (as default parameters to ENTRYPOINT) CMD command param1 param2 (shell form) 第一种用法:运行一个可执行的文件并提供参数。   第二种用法:为ENTRYPOINT指定参数。   第三种用法(shell form):是以”/bin/sh -c”的方法执行的命令。       如你指定:   CMD [“/bin/echo”,“this is a echo test ”]   build后运行(假设镜像名为ec):   docker run ec   就会输出: this is a echo test   是不是感觉很像开机启动项,你可以暂时这样理解。       注意点:   docker run命令如果指定了参数会把CMD里的参数覆盖: (这里说明一下,如:docker run -it ubuntu /bin/bash 命令的参数是指/bin/bash 而非 -it,-it只是docker 的参数,而不是容器的参数,以下所说参数均如此。)   同样是上面的ec镜像启动:   docker run ec /bin/bash   就不会输出:this is a echo test,因为CMD命令被”/bin/bash”覆盖了。       ENTRYPOINT     字面意思是进入点,而它的功能也恰如其意。   An ENTRYPOINT allows you to configure a container that will run as an executable.它可以让你的容器功能表现得像一个可执行程序一样。   容器功能表现得像一个可执行程序一样,这是什么意思呢?   直接给个例子好说话:   例子一:   使用下面的ENTRYPOINT构造镜像:   ENTRYPOINT ["/bin/echo"]   那么docker build出来的镜像以后的容器功能就像一个/bin/echo程序:   比如我build出来的镜像名称叫imageecho,那么我可以这样用它:   docker  run  -it  imageecho  “this is a test”   这里就会输出”this is a test”这串字符,而这个imageecho镜像对应的容器表现出来的功能就像一个echo程序一样。 你添加的参数“this is a test”会添加到ENTRYPOINT后面,就成了这样 /bin/echo “this is a test” 。现在你应该明白进入点的意思了吧。       例子二:   ENTRYPOINT ["/bin/cat"]   构造出来的镜像你可以这样运行(假设名为st):   docker run -it st /etc/fstab   这样相当: /bin/cat  /etc/fstab 这个命令的作用。运行之后就输出/etc/fstab里的内容。       ENTRYPOINT有两种写法:       写法一:ENTRYPOINT ["executable","param2"] (the preferred exec form)   写法二:ENTRYPOINT command param1 param2 (shell form)   你也可以在docker run 命令时使用–entrypoint指定(但是只能用写法一)。       下面是我把ENTRYPOINT设为[“/bin/sh -c”]时候运行的情况:   linux-oj9e:/home/lfly/project/docker # docker run -it  t2  /bin/bash root@4c8549e7ce3e:/# ps PID TTY          TIME CMD 1 ?        00:00:00  sh 9 ?        00:00:00  bash 19 ?        00:00:00  ps 可以看到PID为1的进程运行的是sh,而bash只是sh的一个子进程,/bin/bash只是作为 /bin/sh -c后面的参数。       CMD可以为ENTRYPOINT提供参数,ENTRYPOINT本身也可以包含参数,但是你可以把那些可能需要变动的参数写到CMD里而把那些不需要变动的参数写到ENTRYPOINT里面例如:   FROM  ubuntu:14.10   ENTRYPOINT  ["top","-b"]   CMD  ["-c"]   把可能需要变动的参数写到CMD里面。然后你可以在docker run里指定参数,这样CMD里的参数(这里是-c)就会被覆盖掉而ENTRYPOINT里的不被覆盖。       注意点1:   ENTRYPOINT有两种写法,第二种(shell form)会屏蔽掉docker run时后面加的命令和CMD里的参数。       注意点2:   网上有资料说ENTRYPOINT的默认值是[”/bin/sh -c”],但是笔者在试验的时候得到的结果并不是这样的。    笔者使用ENTRYPOINT [“/bin/sh -c”] 指令构造一个以/bin/sh -c为进入点的镜像,命名为sh,然后我可以这样运行:    docker  run  -it  sh  “while(ture )  do echo loop; done”    运行结果就是无限输出loop。但如果直接运行一个ubuntu:14.10镜像,情况不是这样的:   docker  run  -it  ubuntu:14.10  “while(ture )  do echo loop; done”   得到这样的错误:   linux-oj9e:/home/lfly # docker run -it ubuntu:14.10 “while(true) do echo this; done” 2014/11/16 18:07:53 Error response from daemon: Cannot start container 4bfe9c6faeec3ed465788a201a2f386cb1af35aba197dbc78b87c0d5dda1f88e: exec: “while(true) do echo this; done”: executable file not found in $PATH   可以猜想默认情况下ENTRYPOINT并不是[“/bin/sh -c”]。   而且直接运行ubuntu:14.10列出程序也可以看到PID为1的程序并不是sh。所以更否定了网友的说法,ENTRYPOINT并不默认为[“/bin/sh -c”] 。    

总结

以上是小编为你收集整理的Docker RUN vs CMD vs ENTRYPOINT全部内容。

如果觉得小编网站内容还不错,欢迎将小编网站推荐给好友。

Docker | dockerfile构建centos镜像,以及CMD和ENTRYPOINT的区别

Docker | dockerfile构建centos镜像,以及CMD和ENTRYPOINT的区别

构建自己的centos镜像

docker pull centos下载下来的镜像都是基础版本,缺少很多常用的命令功能,比如:llvim等等,

下面介绍制作一个功能较全的自己的centos镜像。

步骤

1、编写dockerfile文件

FROM centos
MAINTAINER xiao<example@163.com>
ENV MYPATH /usr/local
WORKDIR $MYPATH

RUN yum -y install vim       # vim命令
RUN yum -y install net-tools # ifconfig命令

EXPOSE 80
CMD echo $MYPATH
CMD echo "---end--"
CMD /bin/bash 

2、构建镜像

  • -f file 指定dockerfile文件的路径
  • -t tag 指定name:tag
docker build -f ./mydockerfile -t mycentos:0.1 .

Successfully built e7527f97f78a
Successfully tagged mycentos:0.1

3、测试运行

docker images
docker run -it mycentos:0.1

可以看到进入容器之后,直接就是在 /usr/local 目录下,是因为dockerfile配置的WORKDIR

这时,ifconfigvim命令都可以使用了

4、查看镜像构建历史记录

docker history imageID

CMD和ENTRYPOINT的区别

编写CMD测试dockerfile文件

  1. 编写dockerfile文件
FROM centos
CMD ["ls", "-a"]
  1. 构建镜像
docker build -f ./dockerfile -t cmd-test .
  1. 启动镜像
docker run imageID/iamgeName

测试发现,启动镜像时追加的命令替换了CMD命令,如下图所示:

编写ENTRYPOINT测试dockerfile文件

每个Dockerfile只能有一个ENTRYPOINT,如果指定了多个,只有最后一个被执行,而且一定会被执行

FROM centos
ENTRYPOINT ["ls", "-a"]
# nginx 镜像
ENTRYPOINT [ "/usr/sbin/nginx", "-g", "daemon off;" ]

总结

  1. CMD命令会被启动容器时追加的命令替换执行,

2.ENTRYPOINT命令不会被启动容器时追加的命令替换,而是合并执行


我是 甜点cc

热爱前端,也喜欢专研各种跟本职工作关系不大的技术,技术、产品兴趣广泛且浓厚,等待着一个创业机会。本号主要致力于分享个人经验总结,希望可以给一小部分人一些微小帮助。

希望能和大家一起努力营造一个良好的学习氛围,为了个人和家庭、为了我国的互联网物联网技术、数字化转型、数字经济发展做一点点贡献。数风流人物还看中国、看今朝、看你我。

Docker 中的 Dockerfile 命令详解 FROM RUN COPY ADD ENTRYPOINT...

Docker 中的 Dockerfile 命令详解 FROM RUN COPY ADD ENTRYPOINT...

Dockerfile 指令

这些建议旨在帮助您创建高效且可维护的 Dockerfile。

FROM

FROM 指令的 Dockerfile 引用

尽可能使用当前的官方图像作为图像的基础。我们推荐 Alpine 图像,因为它是严格控制的并且尺寸小(目前小于 5 MB),同时仍然是完整的 Linux 发行版。

标签

了解对象标签

您可以为图像添加标签,以帮助按项目组织图像,记录许可信息,帮助实现自动化或出于其他原因。对于每个标签,添加 LABEL 以一个或多个键值对开头的行。以下示例显示了不同的可接受格式。内容包括解释性意见。

必须引用带空格的字符串必须转义空格。内引号字符(")也必须进行转义。

# Set one or more individual labels

LABEL com.example.version="0.0.1-beta"

LABEL vendor1="ACME Incorporated"

LABEL vendor2=ZENITH\ Incorporated

LABEL com.example.release-date="2015-02-12"

LABEL com.example.version.is-production=""

图像可以有多个标签。在 Docker 1.10 之前,建议将所有标签组合到一条 LABEL 指令中,以防止创建额外的层。这不再是必需的,但仍然支持组合标签。

# Set multiple labels on one line

LABEL com.example.version="0.0.1-beta" com.example.release-date="2015-02-12"

以上也可以写成:

# Set multiple labels at once, using line-continuation characters to break long lines

LABEL vendor=ACME\ Incorporated \

      com.example.is-beta= \

      com.example.is-production="" \

      com.example.version="0.0.1-beta" \

      com.example.release-date="2015-02-12"

有关可接受的标签键和值的指导,请参阅了解对象标签。有关查询标​​签的信息,请参阅管理对象标签中与过滤相关的项目。另请参见 Dockerfile 参考中的 LABEL。

RUN

RUN 指令的 Dockerfile 参考

RUN 在使用反斜杠分隔的多行上拆分长或复杂语句,以使您 Dockerfile 更具可读性,可理解性和可维护性。

APT-GET 的

可能最常见的用例 RUN 是应用程序 apt-get。因为它安装了包,所以该 RUN apt-get 命令有几个需要注意的问题。

避免 RUN apt-get upgrade 和 dist-upgrade,因为父图像中的许多 “基本” 包无法在非特权容器内升级 。如果父图像中包含的包已过期,请与其维护人员联系。如果您知道有特定包,foo 需要更新,请使用 apt-get install -y foo 自动更新。

始终在同一 声明中结合 RUN apt-get update 使用。例如:apt-get installRUN

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

    package-bar \

    package-baz \

    package-foo

apt-get update 在 RUN 语句中单独使用会导致缓存问题,并且后续 apt-get install 指令会失败。例如,假设你有一个 Dockerfile:

FROM ubuntu:18.04

RUN apt-get update

RUN apt-get install -y curl

构建映像后,所有层都在 Docker 缓存中。假设您稍后 apt-get install 通过添加额外包修改:

FROM ubuntu:18.04

RUN apt-get update

RUN apt-get install -y curl nginx

Docker 将初始和修改的指令视为相同,并重用前面步骤中的缓存。其结果是,apt-get update 在执行,因为编译使用缓存的版本。因为 apt-get update 没有运行,您的构建有可能得到的一个过时的版本 curl 和 nginx 包。

使用 RUN apt-get update && apt-get install -y 确保您的 Dockerfile 安装最新的软件包版本,无需进一步编码或手动干预。这种技术被称为 “缓存破坏”。您还可以通过指定包版本来实现缓存清除。这称为版本固定,例如:

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

    package-bar \

    package-baz \

    package-foo=1.3.*

版本固定强制构建以检索特定版本,而不管缓存中的内容是什么。此技术还可以减少由于所需包中意外更改而导致的故障。

下面是一个结构良好的 RUN 说明,演示了所有 apt-get 建议。

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

    aufs-tools \

    automake \

    build-essential \

    curl \

    dpkg-sig \

    libcap-dev \

    libsqlite3-dev \

    mercurial \

    reprepro \

    ruby1.9.1 \

    ruby1.9.1-dev \

    s3cmd=1.1.* \

 && rm -rf /var/lib/apt/lists/*

该 s3cmd 参数指定一个版本 1.1.*。如果映像以前使用的是旧版本,则指定新版本会导致缓存破坏,apt-get update 并确保安装新版本。列出每行的包也可以防止包重复中的错误。

此外,当您通过删除 /var/lib/apt/lists 它来清理 apt 缓存时会减小图像大小,因为 apt 缓存不存储在图层中。由于 RUN 语句以#开头 apt-get update,因此包缓存始终在刷新之前刷新 apt-get install。

官方 Debian 和 Ubuntu 映像自动运行 apt-get clean,因此不需要显式调用。

使用管道

某些 RUN 命令依赖于使用管道符(|)将一个命令的输出传递到另一个命令的能力,如下例所示:

RUN wget -O - https://some.site | wc -l > /number

Docker 使用 /bin/sh -c 解释器执行这些命令,解释器仅评估管道中最后一个操作的退出代码以确定成功。在上面的示例中,只要 wc -l 命令成功,即使 wget 命令失败,此构建步骤也会成功并生成新映像。

如果您希望命令因管道中任何阶段的错误而失败,请预先 set -o pipefail && 确定意外错误,以防止构建无意中成功。例如:

RUN set -o pipefail && wget -O - https://some.site | wc -l > /number

并非所有 shell 都支持该 -o pipefail 选项。

在诸如 dash 基于 Debian 的映像上的 shell 的情况下,考虑使用 exec 形式 RUN 明确选择支持该 pipefail 选项的 shell 。例如:

RUN ["/bin/bash", "-c", "set -o pipefail && wget -O - https://some.site | wc -l > /number"]

CMD

CMD 指令的 Dockerfile 参考

该 CMD 指令应用于运行图像包含的软件以及任何参数。CMD 应该几乎总是以形式使用 CMD ["executable", "param1", "param2"…]。因此,如果图像是用于服务的,例如 Apache 和 Rails,那么你可以运行类似的东西 CMD ["apache2","-DFOREGROUND"]。实际上,建议将这种形式的指令用于任何基于服务的图像。

在大多数其他情况下,CMD 应该给出一个交互式 shell,例如 bash,python 和 perl。例如,CMD ["perl", "-de0"],CMD ["python"],或 CMD ["php", "-a"]。使用此表单意味着当您执行类似的操作时 docker run -it python,您将被放入可用的 shell 中,随时可以使用。 CMD 应该很少的方式使用 CMD ["param", "param"] 会同 ENTRYPOINT,除非你和你预期的用户已经非常熟悉如何 ENTRYPOINT 工作的。

EXPOSE

EXPOSE 指令的 Dockerfile 参考

该 EXPOSE 指令指示容器侦听连接的端口。因此,您应该为您的应用程序使用通用的传统端口。例如,包含 Apache Web 服务器 EXPOSE 80 的图像将使用,而包含 MongoDB 的图像将使用 EXPOSE 27017,依此类推。

对于外部访问,您的用户可以 docker run 使用一个标志来执行,该标志指示如何将指定端口映射到他们选择的端口。对于容器链接,Docker 为从接收容器返回源的路径提供环境变量(即 MYSQL_PORT_3306_TCP)。

ENV

ENV 指令的 Dockerfile 参考

要使新软件更易于运行,您可以使用 ENV 更新 PATH 容器安装的软件的 环境变量。例如,ENV PATH /usr/local/nginx/bin:$PATH 确保 CMD ["nginx"] 正常工作。

该 ENV 指令对于提供特定于您希望容纳的服务的必需环境变量也很有用,例如 Postgres PGDATA。

最后,ENV 还可以用于设置常用的版本号,以便更容易维护版本颠簸,如以下示例所示:

ENV PG_MAJOR 9.3

ENV PG_VERSION 9.3.4

RUN curl -SL http://example.com/postgres-$PG_VERSION.tar.xz | tar -xJC /usr/src/postgress && …

ENV PATH /usr/local/postgres-$PG_MAJOR/bin:$PATH

与在程序中使用常量变量(与硬编码值相对)类似,此方法允许您更改单个 ENV 指令以自动神奇地破坏容器中的软件版本。

每 ENV 行创建一个新的中间层,就像 RUN 命令一样。这意味着即使您在将来的图层中取消设置环境变量,它仍然会在此图层中保留,并且可以转储其值。您可以通过创建如下所示的 Dockerfile 来测试它,然后构建它。

FROM alpine

ENV ADMIN_USER="mark"

RUN echo $ADMIN_USER > ./mark

RUN unset ADMIN_USER

$ docker run --rm test sh -c ''echo $ADMIN_USER''

 

mark

要防止这种情况,并且确实取消设置环境变量,请使用 RUN 带有 shell 命令的命令,在单个图层中设置,使用和取消设置变量 all。您可以使用;或分隔命令 &&。如果您使用第二种方法,并且其中一个命令失败,则 docker build 也会失败。这通常是一个好主意。使用 \Linux Dockerfiles 作为行继续符可以提高可读性。您还可以将所有命令放入 shell 脚本中,并让 RUN 命令运行该 shell 脚本。

FROM alpine

RUN export ADMIN_USER="mark" \

    && echo $ADMIN_USER > ./mark \

    && unset ADMIN_USER

CMD sh

$ docker run --rm test sh -c ''echo $ADMIN_USER''

 

ADD COPY

  • ADD 指令的 Dockerfile 参考
  • COPY 指令的 Dockerfile 参考

一般而言,虽然 ADD 并且 COPY 在功能上类似,但是 COPY 是优选的。那是因为它更透明 ADD。COPY 仅支持将本地文件基本复制到容器中,同时 ADD 具有一些功能(如仅限本地的 tar 提取和远程 URL 支持),这些功能并不是很明显。因此,最好的用途 ADD 是将本地 tar 文件自动提取到图像中,如 ADD rootfs.tar.xz/。

如果您有多个 Dockerfile 步骤使用上下文中的不同文件,则 COPY 它们是单独的,而不是一次性完成。这可确保每个步骤的构建缓存仅在特定所需文件更改时失效(强制重新执行该步骤)。

例如:

COPY requirements.txt /tmp/

RUN pip install --requirement /tmp/requirements.txt

COPY . /tmp/

导致 RUN 步骤的缓存失效次数少于放置 COPY . /tmp/ 之前的缓存失效次数。

由于图像大小很重要,ADD 因此强烈建议不要使用从远程 URL 获取包。你应该使用 curl 或 wget 代替。这样,您可以删除提取后不再需要的文件,也不必在图像中添加其他图层。例如,你应该避免做以下事情:

ADD http://example.com/big.tar.xz /usr/src/things/

RUN tar -xJf /usr/src/things/big.tar.xz -C /usr/src/things

RUN make -C /usr/src/things all

而是做一些像:

RUN mkdir -p /usr/src/things \

    && curl -SL http://example.com/big.tar.xz \

    | tar -xJC /usr/src/things \

    && make -C /usr/src/things all

对于不需要 ADDtar 自动提取功能的其他项目(文件,目录),您应该始终使用 COPY。

ENTRYPOINT

ENTRYPOINT 指令的 Dockerfile 参考

最好的用法 ENTRYPOINT 是设置图像的主命令,允许该图像像该命令一样运行(然后 CMD 用作默认标志)。

让我们从命令行工具的图像示例开始 s3cmd:

ENTRYPOINT ["s3cmd"]

CMD ["--help"]

现在可以像这样运行图像来显示命令的帮助:

$ docker run s3cmd

或使用正确的参数执行命令:

$ docker run s3cmd ls s3://mybucket

这很有用,因为图像名称可以兼作二进制文件的引用,如上面的命令所示。

该 ENTRYPOINT 指令还可以与辅助脚本结合使用,允许它以与上述命令类似的方式运行,即使启动该工具可能需要多个步骤。

例如,Postgres 官方图像 使用以下脚本作为其 ENTRYPOINT:

#!/bin/bash

set -e

 

if [ "$1" = ''postgres'' ]; then

    chown -R postgres "$PGDATA"

 

    if [ -z "$(ls -A "$PGDATA")" ]; then

        gosu postgres initdb

    fi

 

    exec gosu postgres "$@"

fi

 

exec "$@"

app 配置为 PID 1

此脚本使用的 execbash 命令 ,以使最终运行的应用程序成为容器的 PID 1. 这允许应用程序接收发送到所述容器任何 Unix 信号。如需更多信息,请参阅 ENTRYPOINT 参考。

帮助程序脚本被复制到容器中并通过 ENTRYPOINT 容器启动运行:

COPY ./docker-entrypoint.sh /

ENTRYPOINT ["/docker-entrypoint.sh"]

CMD ["postgres"]

该脚本允许用户以多种方式与 Postgres 交互。

它可以简单地启动 Postgres:

$ docker run postgres

或者,它可用于运行 Postgres 并将参数传递给服务器:

$ docker run postgres postgres --help

最后,它还可以用来启动一个完全不同的工具,比如 Bash:

$ docker run --rm -it postgres bash

VOLUME

VOLUME 指令的 Dockerfile 参考

该 VOLUME 指令应用于公开由 docker 容器创建的任何数据库存储区域,配置存储或文件 / 文件夹。强烈建议您使用图像 VOLUME 的任何可变和 / 或用户可维修部分。

USER

USER 指令的 Dockerfile 参考

如果服务可以在没有权限的情况下运行,请使用 USER 更改为非 root 用户。首先在 Dockerfile 类似的东西中创建用户和组 RUN groupadd -r postgres && useradd --no-log-init -r -g postgres postgres。

考虑一个显式的 UID / GID

图像中的用户和组被分配了非确定性 UID / GID,因为无论图像重建如何,都会分配 “下一个” UID / GID。因此,如果它很重要,您应该分配一个显式的 UID / GID。

由于 Go 存档 /tar 包处理稀疏文件时未解决的错误,尝试在 Docker 容器内创建具有非常大的 UID 的用户可能导致磁盘耗尽,因为 /var/log/faillog 容器层中填充了 NULL(\ 0)字符。解决方法是将 --no-log-init 标志传递给 useradd。Debian / Ubuntu adduser 包装器不支持此标志。

避免安装或使用,sudo 因为它具有可能导致问题的不可预测的 TTY 和信号转发行为。如果您绝对需要类似的功能 sudo,例如将守护程序初始化 root 为非运行它 root,请考虑使用 “gosu”。

最后,为了减少层次和复杂性,避免 USER 频繁地来回切换。

WORKDIR

WORKDIR 指令的 Dockerfile 参考

为了清晰和可靠,您应该始终使用绝对路径 WORKDIR。此外,您应该使用难以阅读,排除故障和维护 WORKDIR 的扩散指令 RUN cd … && do-something。

ONBUILD

ONBUILD 指令的 Dockerfile 参考

一个 ONBUILD 命令将当前执行后 Dockerfile 构建完成。ONBUILD 在任何导出 FROM 当前图像的子图像中执行。将该 ONBUILD 命令视为父母 Dockerfile 给孩子的指令 Dockerfile。

Docker 构建 ONBUILD 在子代中的任何命令之前执行命令 Dockerfile。

ONBUILD 对于将要构建 FROM 给定图像的图像非常有用。例如,您将使用 ONBUILD 一个语言堆栈映像来构建在该语言中编写的任意用户软件 Dockerfile,正如您在 Ruby 的 ONBUILD 变体中所看到的那样。

构建的图像 ONBUILD 应该获得单独的标记,例如:ruby:1.9-onbuild 或 ruby:2.0-onbuild。

把时要小心,ADD 或 COPY 在 ONBUILD。如果新构建的上下文缺少正在添加的资源,则 “onbuild” 映像将发生灾难性故障。如上所述,添加单独的标记有助于通过允许 Dockerfile 作者做出选择来缓解这种情况。

关于Dockerfile RUN, CMD & ENTRYPOINT的问题就给大家分享到这里,感谢你花时间阅读本站内容,更多关于docker RUN CMD ENTRYPOINT 区别、Docker RUN vs CMD vs ENTRYPOINT、Docker | dockerfile构建centos镜像,以及CMD和ENTRYPOINT的区别、Docker 中的 Dockerfile 命令详解 FROM RUN COPY ADD ENTRYPOINT...等相关知识的信息别忘了在本站进行查找喔。

本文标签: