Docker之Dockerfile 指令详解

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/cx55887/article/details/84646446

闲话不多说,dokerfile常用指令解析奉上

FROM
作用:指定基础镜像,必须放在DOckerfile的第一行,表示从哪个baseimage开始构建
格式:

	FROM <image>:[tag]
	FROM <image>@<digest>
  • 镜像必须是Dockerfile文件中第一条非注释指令,表示从哪个baseimage开始构建 FROM
  • 指令能同一个Dockerfile文件中出现多次,为了创建多个镜像 tag 和 digest
  • 值是可选的,如果缺省,构建器默认为latest,当tag不匹配时,构建器返回错误

MAINTAINER
作用:指定作者信息,该指令已被废弃但是目前还可以使用,可以用LABEL指令代替。
格式:

	MAINTAINER 	<name>
eg.
	MAINTANER  "cx55887 <[email protected]>"

LABEL
作用:设定一些添加镜像的元数据,LABEL是一对key-value值
格式:

	LABEL <key>=<value> <key>=<value> <key>=<value> ...
eg.
	LABEL version="2.1"
	LABEL creator="cx55887"

镜像可以有多个LABEL,来指定多个标签,Docker建议在可能的情况下将 标签组合到单个LABEL指令中,
因为每一个LABEL指令都会产生一个新的层,而层数越多就会导致执行花费时间越长。

	LABEL version="2.1" \
		  creator="cx55887" \
		  other="value"

LABEL中如果key已存在,后面添加相同的key那么新的value会覆盖掉前面的。

COPY
作用:将工作目录下的文件复制到所做的镜像中的文件系统中
格式:

	COPY [--chown=<user>:<group>] <源路径>... <目标路径>
	COPY [--chown=<user>:<group>] ["<源路径1>",... "<目标路径>"]
  • <源路径>用相对路径,可以用通配符, 源文件必须在工作目录或者工作目录的子目录中,<目标路径> 可以是容器内的绝对路径,也可以是相对于工作目录的相对路径(工作目录可以用 WORKDIR 指令来指定)
  • 目标路径不需要事先创建,如果目录不存在会在复制文件前先行创建缺失目录。
  • 如果源文件是一个目录,会自动递归复制目录下的文件到目标位置,但是目录自身不会复制
  • 如果复制多个文件,或者源文件中用了通配符,那么目标路径必须以 / 为结尾
  • 此外,还需要注意一点,使用 COPY指令,源文件的各种元数据都会保留。比如读、写、执行权限、文件变更时间等。这个特性对于镜像定制很有用。特别是构建相关文件都在使用 Git进行管理的时候。
    在使用该指令的时候还可以加上 --chown=: 选项来改变文件的所属用户及所属组。
	COPY --chown=cx55887:cx55887 files* /mydir/
	COPY --chown=cx55887 files* /mydir/
	COPY --chown=1 files* /mydir/
	COPY --chown=10:11 files* /mydir/

ADD
作用:和COPY类似,可以实现将文件和目录复制到镜像中,但是区别是可以实现:
如果 <源路径> 为一个 tar 压缩文件的话,压缩格式为 gzip, bzip2 以及 xz 的情况下,ADD 指令将会自动解压缩这个压缩文件到 <目标路径> 去。
如果<源路径>是一个URL,Docker引擎会去下载这个链接的文件放到<目标路径>,下载后文件的权限自动设置为600。注意:下载的tar包不会自动解压
格式:

	ADD  [--chown=<user>:<group>] <源路径>... <目标路径>
	ADD  [--chown=<user>:<group>] ["<源路径1>",... "<目标路径>"]

使用ADD指令的时候也可以通过--chown=<user>:<group>选项廖改变文件的属主和属组

	ADD --chown=cx55887:cx55887 files* /mydir/
	ADD --chown=cx55887 files* /mydir/
	ADD --chown=1 files* /mydir/
	ADD --chown=10:11 files* /mydir/

WORKDIR
作用:设置镜像中的工作目录,相当于cd命令
格式:

	WORKDIR <工作目录路径>
  • WORKDIR 指令可以来指定工作目录(或者称为当前目录),以后各层的当前目录就被改为指定的目录,如该目录不存在,WORKDIR会帮你建立目录。

VOLUME
作用:指定数据卷的挂载点,若不存在会自动创建
格式:

扫描二维码关注公众号,回复: 5748701 查看本文章
	VOLUME ["<路径1>", "<路径2>"...]
	VOLUME <路径>
eg.
	VOLUME /data

这样/data目录就会在运行的自动挂载,任何向/data写入的信息都不会记录进容器储存层,从而保证容器储存层的无状态化,当然运行时可以覆盖掉这个挂载设置:

	docker run -d -v mydata:/data xxxx

在这条命令中,就使用了mydata 这个命名卷改在到了/data这个位置,替代了 Dockerfile中定义的匿名卷的挂在配置

EXPOSE
作用:告诉 Docker 服务端 容器对外映射的本地端口。
格式:

	EXPOSE  <端口1> [<端口2>...]

EXPOSE 指令是声明运行时容器提供服务端口,这只是一个声明,在运行时并不会因为这个声明应用就会开启这个端口的服务。在dockerfile中声名有两个好处:

  • 帮助镜像使用者理解这个镜像服务的守护端口,方便配置映射
  • 运行时使用随机端口映射时,也就是docker run -P时,会随机映射EXPOSE中声明的端口。
  • 另外需要注意的是将EXPOSE和在运行时使用-p <宿主端口>:<容器端口>区分开,-p是映射宿主端口和容器端口,也就是说将容器的对应端口服务公开给外界访问,而EXPOSE仅仅是声名容器打算使用那些端口而已,并不会自动在宿主机进行端口映射

ENV
作用:设置环境变量
格式:

	ENV <key> <value>
	ENV <key1>=<value1> <key2>=<value2> ...
eg.
	ENV VERSION=1.0 DEBUG=no  \
	NAME="cx baby"

通过ENV所定义的变量是可以传递到容器之中,但是,在创建容器的时候,如果手动指定了变量的值,那么这个值会覆盖掉镜像中原有的值

RUN
作用:RUN指令会在当前镜像的基础上指定命令,并提交为新镜像
格式:

	RUN <command>       
	RUN ["executable","param1","param2"]    

前者将在shell终端中运行命令,即/bin/sh -c;后者则使用exec执行。指定使用其它终端可以通过第二种方式实现,例如RUN ["/bin/bash", "-c", "echo hello"]
CMD
作用:定义容器启动以后要默认运行的程序,即pid为1的程序
格式:

shell 格式:CMD <命令>
exec 格式:CMD ["可执行文件", "参数1", "参数2"...]
参数列表格式:CMD ["参数1", "参数2"...]。在指定了 ENTRYPOINT 指令后,用 CMD 指定具体的参数。

我们知道Docker不同于虚拟机,容器就是进程,既然是进程,那么在启动容器的时候,需要指定所运行的程序及参数。CMD指令就是指定容器主进程启动命令的。

在运行的时候可以指定新的命令来替代镜像设置中的这个默认命令,比如ubuntu镜像的默认的CMD是/bin/bsah,如果我们直接docker run -it ubuntu的话,会进入bash 。我们也可以在运行时指定运行别的命令,如 docker run ubuntu cat /etc/os-release。这就是用 cat /etc/os-release 命令替换了默认的/bin/bash 命令输出了系统版本信息。

在指令格式上,推荐使用exec格式,这类格式在解析是会被解析成JOSN数组,因此一定要使用双引号,而不要使用单引号。

如果使用 shell 格式的话,实际的命令会被包装为 sh -c 的参数的形式进行执行。比如:

	CMD echo $NAME
在实际执行中,会将其变更为:
	CMD [ "sh" ,"-c", "echo $NAME"]

这就是为什么我们可以使用环境变量的原因,因为这些环境变量会被 shell 进行解析处理。

提到 CMD 就不得不提容器中应用在前台执行和后台执行的问题。这是初学者常出现的一个混淆。

Docker 不是虚拟机,容器中的应用都应该以前台执行,而不是像虚拟机、物理机里面那样,用 upstart/systemd 去启动后台服务,容器内没有后台服务的概念。
一些初学者将CMD写为:

CMD server nginx start

然后发现容器执行后就立即退出了。甚至在容器内去使用 systemctl 命令结果却发现根本执行不了。这就是因为没有搞明白前台、后台的概念,没有区分容器和虚拟机的差异,依旧在以传统虚拟机的角度去理解容器。

对于容器而言,其启动程序就是容器应用进程,容器就是为了主进程而存在的,主进程退出,容器就失去了存在的意义,从而退出,其它辅助进程不是它需要关心的东西。

而使用 service nginx start 命令,则是希望 upstart 来以后台守护进程形式启动 nginx 服务。而刚才说了 CMD service nginx start 会被理解为 CMD [ “sh”, “-c”, “service nginx start”],因此主进程实际上是 sh。那么当 service nginx start 命令结束后,sh 也就结束了,sh 作为主进程退出了,自然就会令容器退出。

正确的做法是直接执行 nginx 可执行文件,并且要求以前台形式运行。比如:

CMD [“nginx”, “-g”, “daemon off;”]
ENTRYPOINT
作用:ENTRYPOINT 的目的和 CMD 一样,都是在指定容器启动程序及参数
格式:

ENTRYPOINT ["executable", "param1", "param2"]
ENTRYPOINT command param1 param2(shell中执行)
  • 在运行RUN的时候所执行的命令无法覆盖ENTRYPOINT中的命令 RUN
  • 后面的命令会被以参数的方式追加到原本要执行的命令的末尾,而不是替换

ARG
作用:定义在构建镜像时候所使用的变量,在将来容器运行时是不会存在这些环境变量的。
格式:

	ARG <参数名>[=<默认值>]

Dockerfile 中的 ARG 指令是定义参数名称,以及定义其默认值。该默认值可以在构建命令 docker build 中用 --build-arg <参数名>=<值> 来覆盖。

USER
作用:定义容器中的进程以哪个用户的身份运行
格式:

USER <用户名>[:<用户组>]

该用户必须存在于容器的用户空间中(容器的文件系统的中的/etc/passwd中)
HEALTHCHECK
作用:HEALTHCHECK 指令是告诉 Docker 应该如何进行判断容器的状态是否正常
格式:

HEALTHCHECK [选项] CMD <命令>:设置检查容器健康状况的命令
HEALTHCHECK NONE:如果基础镜像有健康检查指令,使用这行可以屏蔽掉其健康检查指令

当在一个镜像指定了 HEALTHCHECK 指令后,用其启动容器,初始状态会为 starting,在 HEALTHCHECK 指令检查成功后变为 healthy,如果连续一定次数失败,则会变为 unhealthy。命令的返回值决定了该次健康检查的成功与否:0:成功;1:失败;2:保留,不要使用这个值。

HEALTHCHECK 支持下列选项:

	--interval=<间隔>:两次健康检查的间隔,默认为 30 秒;
	--timeout=<时长>:健康检查命令运行超时时间,如果超过这个时间,本次健康检查就被视为失败,默认 30 秒;
	--retries=<次数>:当连续失败指定次数后,则将容器状态视为 unhealthy,默认 3 次。

ONBULID
作用:定义一个触发器,用来实现当基于这个这个镜像做新镜像的时候要执行的命令
格式:

	ONBUILD <其它指令>

ONBUILD 是一个特殊的指令,它后面跟的是其它指令,比如 RUN, COPY 等,而这些指令,在当前镜像构建时并不会被执行。只有当以当前镜像为基础镜像,去构建下一级镜像的时候才会被执行。

------做运维之前很矫情的小年轻-----

猜你喜欢

转载自blog.csdn.net/cx55887/article/details/84646446