Dockerfile中重要命令详解

从前面的章节我们了解到在编写Dockerfile时有很多不同的命令,我们需要大致了解它们的区别才能快速的编写一个正确的Dockerfile文件。本章节将对一些重要的命令做一个详细的分析。

一、ADD和COPY命令

1、ADD指令
ADD指令的作用是将宿主机构建环境(上下文)目录中的文件、目录或者一个URL标记的文件拷贝到镜像中。在将本地文件添加到镜像中时,如果是tar类型文件会自动解压,并且ADD可以用于添加网络资源,类似wget。

但是为了让镜像尽量小,最好不要使用 ADD 指令从远程 URL 获取包,而是通过RUN使用 curl 和 wget。这样可以在文件提取完之后删掉不再需要的文件来避免在镜像中额外添加一层。

其格式是: ADD 源路径 目标路径

FROM centos:7
MAINTAINER margu_168
ADD a.txt a.txt
ADD a.txt a.txt.bak
ADD a.txt /data/
ADD data1/ data
ADD data2/ data2
ADD zip.tar /myzip

关于ADD命令有如下几点注意事项:(总得来说就是规范,文件不加/ ,路径一定要加/)

1)如果源路径是个文件,且目标路径是以 / 结尾, 则docker会把目标路径当作一个目录,会把源文件拷贝到该目录下。
如果目标路径不存在,则会自动创建目标路径。

2)如果源路径是个文件,且目标路径是不是以 / 结尾,则docker会把目标路径当作一个文件。
如果目标路径不存在,会以目标路径为名创建一个文件,内容同源文件;
如果目标文件是个存在的文件,会用源文件覆盖它,当然只是内容覆盖,文件名还是目标文件名。
如果目标文件实际是个存在的目录,则会源文件拷贝到该目录下。 注意,这种情况下,最好显示的以 / 结尾,以避免混淆。

3)如果源路径是个目录,且目标路径不存在,则docker会自动以目标路径创建一个目录,把源路径目录下的文件拷贝进来。
如果目标路径是个已经存在的目录,则docker会把源路径目录下的文件拷贝到该目录下。

4)如果源文件是个归档文件(压缩文件),则docker会自动帮解压。

2、COPY指令

COPY指令和ADD指令功能和使用方式类似。只是COPY指令不会做自动解压工作,而且也不支持从网络获取文件
总的来说就是ADD的功能更加强大。

此外,在使用dockerfile构建镜像时,如果想拷贝某个文件夹下面除某个文件外的所有文件,可以用(.dockerignore)文件来排除该文件。

二、CMD和ENTRYPOINT命令

1、CMD

cmd设置的是一个容器的默认的可执行体。也就是容器启动以后,默认的执行的命令(default)。重点就是这个“默认”。意思是 说,如果docker run没有指定任何的执行命令或dockerfile里面也没有设置entrypoint,那么,就会使用cmd指定的默认的执行命令执行。同时也从侧面说明了entrypoint的优先级更高,它才是真正的容器启动以后要执行命令。

“cmd会被覆盖”,其实为什么会覆盖?因为cmd的角色定位就是默认,如果你不额外指定,那么就执行cmd的命令,否则呢?只要你指定了,那么就不会执行cmd,也就是cmd会被覆盖。

明白了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)

第一种用法:运行一个可执行的文件并提供参数。
第二种用法:为ENTRYPOINT提供参数。
第三种用法(shell form):是以”/bin/sh -c”的方法执行后面的命令。

示例:
1)用法1:
CMD [“echo”,“HELLO”]
然后运行
docker run IMAGE_NAME #输出为HELLO
docker run IMAGE_NAME echo hello #输出为hello
第二种CMD里指定的echo会被新指定的echo覆盖,所以最终相当于运行echo hello,所以最终打印出的结果就是:
hello,而不是HELLO

注意,此格式中命令没有再任何shell终端环境下,如果我们要执行shell,必须把shell加入到中括号的参数中。这种用法就像一个c语言的exec函数,意思是我们要执行一个进程。如果采用shell的方法,那么上面的例子要修改为:
CMD [“/bin/bash”,“-c”,"echo ‘HELLO world’ "]

2)用法2:
ENTRYPOINT [“echo”]
CMD [“HELLO”]
docker run IMAGE_NAME #输出为HELLO
docker run IMAGE_NAME echo hello #输出为echo hello,相当于CONTAINER_NAME后面的echo foo都作为参数传递给ENTRYPOING里指定的echo命令了,所以相当于执行了echo “echo hello”

3)方法3:
即没有中括号的形式。那么命令command默认是在"/bin/sh -c"下执行的。比如下面的dockerfile:
CMD echo “hello world !”
docker run IMAGE_NAME #输出hello world !

2、ENTRYPOINT

An ENTRYPOINT allows you to configure a container that will run as an executable.
也就是说entrypoint才是正统地用于定义容器启动以后的执行体的,其实我们从名字也可以理解,这个是容器的“入口”。

有两种用法:
ENTRYPOINT has two forms:

ENTRYPOINT [“executable”, “param1”, “param2”] (exec form, preferred)
ENTRYPOINT command param1 param2 (shell form)

命令行和shell。

1)方法一:
命令行模式,也就是带中括号的,和cmd的中括号形式是一致的,但是与cmd有一定的区别。如果在docker run命令后面有东西,那么后面的全部都会作为entrypoint的参数,而忽略cmd里面的参数。如果docker run后面没有额外的东西,但是cmd有,那么cmd的全部内容会作为entrypoint的参数,这同时是cmd的第二种用法。但是如果ENTRYPOINT 后面也有参数,无论后面cmd或者run里面有没有参数,里面的内容都不会被覆盖。当然如果要在run里面覆盖,也是有办法的,使用--entrypoint即可。

下面看几个例子。
FROM centos:7
ENTRYPOINT [“echo”,“entrypoint”]
CMD [“HELLO”]

如果run不带参数:
docker run IMAGE_NAME #输出为entrypoint HELLO
如果run带参数:
docker run IMAGE_NAME echo hello #输出为entrypoint echo hello ,只会覆盖CMD里面的内容

而且,确实entrypoint的中括号形式下,command是在shell环境下运行的,否则这里的echo是无法被执行的。

此外,docker run -it --entrypoint 指定命令 用于覆盖dockerfile内部设置的entrypoint

2)方法二:
shell模式。在这种模式下,任何run和cmd的参数都无法被传入到entrypoint里。因此工作中推荐第一种用法。

FROM centos:7
ENTRYPOINT echo
CMD [“HELLO”]
docker run IMAGE_NAME
docker run IMAGE_NAME hello ##会发现两个都没有任何输出,说明cmd的参数或者run都无法把参数传入到entrypoint。

总结:一般还是会用entrypoint的中括号形式作为docker容器启动以后的默认执行命令,里面放的是不变的部分,可变部分比如命令参数可以使用cmd的形式提供默认版本,也就是run里面没有任何参数时使用的默认参数。如果我们想用默认参数,就直接run,否则想用其他参数,就run 里面加参数。

单cmd默认 run+cmd覆盖默认
单entrypoint
cmd+entrypoint entrypoint> run>cmd,相当于优先级。cmd为默认参数,run为指定参数,entrypoint为命令

更多关于docker容器和运维相关的知识,请前往博客主页。

你可能感兴趣的:(docker,docker,运维)