Docker Dockerfile
Docker Dockerfile包含一组有关如何构建Docker镜像的说明。 Docker build命令执行Dockerfile并从中构建Docker镜像。本Dockerfile教程介绍了如何编写Dockerfile并将其构建到Docker镜像中。
Dockerfile的好处
Dockerfile捕获以书面形式构建Docker镜像的方法。 Docker镜像通常包含:
- 一个基本的Docker镜像,在此镜像之上可以构建自己的Docker镜像。
- 要在Docker镜像中安装的一组工具和应用程序。
- 一组要复制到Docker镜像中的文件(例如配置文件)。
- 可能会打开一个网络(TCP / UDP)端口(或者更多端口)以用于防火墙中的通信。
- 等等。
首先,在Dockerfile中以书面形式捕获所有这些信息意味着我们不必记住如何设置应用程序的新安装,以及操作系统要求,要安装的应用程序,要复制的文件,要打开的网络端口等所有这些都在Dockerfile中进行了描述。
此外,让Docker从Dockerfile构建Docker镜像意味着我们不必执行此手动,繁琐且易于出错的工作。 Docker为我们准备了它,因此我们可以在此期间做其他事情。这既容易,快捷又容易出错。
第三,与其他人共享Dockerfile并使他们能够构建Docker镜像确实很容易。
第四,Dockerfile可以轻松存储在Git之类的版本控制系统中,因此我们可以随时间跟踪对Dockerfile的更改(服务器和应用程序配置)。版本控制系统通常还可以使多个人更轻松地进行协作,例如在Dockerfile上,以及稍后共享Dockerfile。
Dockerfile结构
Dockerfile由一组指令组成。每个指令都包含一个命令,后跟该命令的参数,类似于命令行可执行文件。这是一个Dockerfile的简单示例:
# The base image FROM ubuntu:latest # More instructions here that install software and copy files into the image. COPY /myapp/target/myapp.jar /myapp/myapp.jar # The command executed when running a Docker container based on this image. CMD echo Starting Docker Container
Docker基础镜像
Docker镜像由层组成。每层都为最终的Docker镜像添加了一些内容。每层实际上是一个单独的Docker镜像。因此,Docker镜像由一个或者多个基础Docker镜像组成,在这些镜像之上我们添加了自己的层。
当我们通过Dockerfile指定自己的Docker镜像时,通常以Docker基本镜像开始。这是另一个Docker镜像,我们希望在其之上构建自己的Docker镜像。我们正在使用的Docker基本镜像本身可能包含多层,并且本身可以基于其他基本镜像等,直到我们掌握最基本的Docker镜像为止,我们可以创建未应用任何特殊设置的原始Linux容器镜像。
我们可以使用" FROM"命令在Dockerfile中指定Docker镜像的基础镜像,如以下部分所述。
MAINTAINER
Dockerfile的MAINTAINER命令仅用于告诉谁维护此Dockerfile。这是一个例子:
MAINTAINER Joe Blocks <[email protected]>
但是," MAINTAINER"指令并不经常使用,因为在GIT存储库和其他地方也经常可以使用这种信息。
FROM
DockerfileFROM
命令指定Docker镜像的基本镜像。如果要从裸露的Linux镜像开始,则可以使用以下" FROM"命令:
# The base image FROM ubuntu:latest
CMD
CMD命令指定基于此Dockerfile构建的Docker镜像的Docker容器启动时执行的命令行命令。以下是一些DockerfileCMD
示例:
CMD echo Docker container started.
此示例仅在启动Docker容器时打印文本Docker容器已启动
。
下一个CMD
示例运行一个Java应用程序:
CMD java -cp /myapp/myapp.jar com.jenkov.myapp.MainClass arg1 arg2 arg3
COPY(复制)
Dockerfile的COPY命令将一个或者多个文件从Docker主机(从Dockerfile构建Docker镜像的计算机)复制到Docker镜像。 COPY命令可以将文件或者目录从Docker主机复制到Docker镜像。这是一个DockerfileCOPY
示例:
COPY /myapp/target/myapp.jar /myapp/myapp.jar
本示例将Docker主机上的单个文件从/myapp/target/myapp.jar复制到Docker镜像在/myapp/myapp.jar。第一个参数是Docker主机路径(要从中复制),第二个参数是Docker镜像路径(要向其中复制)。
我们还可以将目录从Docker主机复制到Docker镜像。这是一个例子:
COPY /myapp/config/prod /myapp/config
本示例将目录/ myapp / config / prod从Docker主机复制到Docker镜像中的目录/ myapp / config。
我们可以使用COPY
命令将多个文件复制到Docker镜像中的单个目录中。这是一个例子:
COPY /myapp/config/prod/conf1.cfg /myapp/config/prod/conf2.cfg /myapp/config/
本示例将两个文件/myapp/config/prod/conf1.cfg和复制到myfile / conig / prod / conf2.cfg到Docker镜像目录/ myapp / config /中。请注意,目标目录必须以/
(斜杠)结尾才能起作用。
ADD
Dockerfile的ADD指令的工作方式与COPY指令的工作方式略有不同:
- " ADD"指令可以将TAR文件从Docker主机复制并提取到Docker镜像。
- " ADD"指令可以通过HTTP下载文件并将其复制到Docker镜像中。
这是一些DockerfileADD
示例:
ADD myapp.tar /myapp/
本示例将从Docker主机中提取给定的TAR文件到Docker镜像内的/ myapp /
目录中。
这是另一个示例:
ADD http://jenkov.com/myapp.jar /myapp/
ENV
Dockerfile的ENV命令可以在Docker镜像内设置环境变量。此环境变量可用于通过CMD
命令在Docker镜像内启动的应用程序。这是一个例子:
ENV MY_VAR 123
本示例将环境变量MY_VAR设置为值123.
RUN
Dockerfile的RUN命令可以在Docker镜像中执行命令行可执行文件。 RUN命令在Docker镜像的构建期间执行,因此RUN命令仅执行一次。 RUN命令可用于在Docker镜像中安装应用程序,提取文件或者运行一次以准备执行Docker镜像所需的其他命令行活动。
RUN apt-get install some-needed-app
ARG
Dockerfile ARG指令可让我们定义一个参数,当我们从Dockerfile构建Docker镜像时,该参数可以传递给Docker。这是一个例子:
ARG tcpPort
当我们运行Docker命令以构建包含上述ARG
指令的Dockerfile时,可以将参数传递给tcpPort
参数,如下所示:
docker build --build-arg tcpPort=8080 .
注意--build-arg
,后跟tcpPort = 8080
。这部分将tcpPort参数值设置为8080。
我们可以使用多个" ARG"指令来定义多个构建参数。这是一个例子:
ARG tcpPort ARG useTls
构建Docker镜像时,必须为所有构建参数提供值。为此,我们可以为要设置的每个参数重复执行--build-arg
节。这是一个例子:
docker build --build-arg tcpPort=8080 --build-arg useTls=true .
我们可以为ARG
设置默认值,以便在构建Docker镜像时为其提供值成为可选。如果未为参数提供值,则将为其提供默认值。这是一个例子:
ARG tcpPort=8080 ARG useTls=true
如果在为包含上述ARG指令的Dockerfile构建Docker镜像时,既未设置tcpPort参数,又未设置useTls参数,则其参数值将设置为8080和true。
由ARG声明的参数通常在Dockerfile中的其他地方引用。我们可以像这样引用" ARG"参数:
ARG tcpPort=8080 ARG useTls=true CMD start-my-server.sh -port ${tcpPort} -tls ${useTls}
注意两个引用$ {tcpPort}
和$ {useTls}
。这些引用了名为tcpPort
和useTls
的已声明的" ARG"参数。
docker build --build-arg tcpPort=8080
WORKDIR(工作目录)
WORKDIR指令指定Docker镜像内的工作目录应该是什么。工作目录将对WORKDIR
指令之后的所有命令生效。这是一个例子:
WORKDIR /java/jdk/bin
EXPOSE
Dockerfile的EXPOSE指令打开Docker容器中通往外界的网络端口。例如,如果Docker容器运行Web服务器,则该Web服务器可能需要打开端口80,以便任何客户端都能连接到该服务器。这是使用" EXPOSE"命令打开网络端口的示例:
EXPOSE 8080
我们还可以设置允许哪个协议在打开的端口上进行通信。例如,UDP或者TCP。以下是设置允许的协议的示例:
EXPOSE 8080/tcp 9999/udp
如果未设置协议(在/之后),则假定该协议为TCP。
VOLUME
Dockerfile的" VOLUME"指令在Docker镜像内创建一个目录,我们以后可以从Docker主机挂载一个卷(目录)。换句话说,我们可以在docker镜像内创建一个目录,例如称为/ data
的文件,以后可以挂载到目录中,例如在Docker主机中称为/ container-data / container1
。容器启动后即完成安装。这是一个使用VOLUME
指令在Dockerfile中定义卷(可挂载目录)的示例:
VOLUME /data
ENTRYPOINT
Dockerfile的" ENTRYPOINT"指令为从该Docker镜像启动的Docker容器提供了一个入口点。入口点是启动Docker容器时执行的应用程序或者命令。这样,ENTRYPOINT
的工作方式类似于CMD
,不同之处在于,当使用ENTRYPOINT
执行的应用程序完成时,使用ENTRYPOINT
可以关闭Docker容器。因此,ENTRYPOINT
可以使Docker镜像本身成为可执行命令,该命令可以启动,并在完成后自动关闭。这是一个DockerfileENTRYPOINT
的例子:
ENTRYPOINT java -cp /apps/myapp/myapp.jar com.jenkov.myapp.Main
此示例将在Docker容器启动时以及在应用程序关闭时执行Java应用程序主类com.jenkov.myapp.Main
。
HEALTHCHECK
Dockerfile的" HEALTHCHECK"指令可以定期执行运行状况检查命令行命令,以监视在Docker容器中运行的应用程序的运行状况。如果退出时命令行命令返回的值为0,则Docker认为应用程序和容器运行状况良好。如果命令行命令返回值1,则Docker认为应用程序和容器不健康。这是一个DockerfileHEALTHCHECK
示例:
HEALTHCHECK java -cp /apps/myapp/healthcheck.jar com.jenkov.myapp.HealthCheck https://localhost/healthcheck
本示例将Java应用程序com.jenkov.myapp.HealthCheck配置为healthcheck命令。我们可以在此处使用任何对我们有意义的healthcheck命令。
HEALTHCHECK(健康检查间隔)
默认情况下,Docker每30秒执行一次" HEALTHCHECK"命令。但是,如果我们希望使用与默认30秒不同的间隔长度,则可以设置自定义运行状况检查间隔。我们可以使用HEALTHCHECK指令的--interval参数来指定运行状况检查间隔。这是将" HEALTHCHECK"间隔设置为60秒的示例:
HEALTHCHECK --interval=60s java -cp /apps/myapp/healthcheck.jar com.jenkov.myapp.HealthCheck https://localhost/healthcheck
健康检查开始时间
默认情况下,Docker将立即开始检查Docker容器的运行状况。但是,有时应用程序可能需要一些时间才能启动,因此对健康进行检查可能要到一定时间后才有意义。这为应用程序提供了在Docker开始运行状况检查之前启动的机会。我们可以在" HEALTHCHECK"指令中使用" --start-period"参数来设置运行状况检查的开始时间。这是将运行状况检查开始时间设置为5分钟的示例,在Docker开始检查其运行状况之前,给容器和应用程序300秒(5分钟)启动时间:
HEALTHCHECK --start-period=300s java -cp /apps/myapp/healthcheck.jar com.jenkov.myapp.HealthCheck https://localhost/healthcheck
健康检查超时
健康检查可能会超时。如果" HEALTCHECK"命令花费的时间超过给定的时限,则Docker将认为运行状况检查超时。我们可以通过对HEALTHCHECK命令使用--timeout参数来设置超时限制。这是将运行状况检查超时时间限制设置为5秒的示例:
HEALTHCHECK --timeout=5s java -cp /apps/myapp/healthcheck.jar com.jenkov.myapp.HealthCheck https://localhost/healthcheck
注意:如果运行状况检查超时,则Docker也会认为该容器也不正常。
健康检查重试
如果HEALTHCHECK
失败,或者是由于HEALTCHECK
命令返回1,或者如果超时,则在考虑Docker容器之前,Docker将重试HEALTHCHECK
命令3次以查看Docker容器是否返回健康状态不良。我们可以使用HEALTHCHECK指令的--retries参数覆盖默认的3次重试。这是将运行状况检查重试次数设置为5的示例:
HEALTHCHECK --retries=5 java -cp /apps/myapp/healthcheck.jar com.jenkov.myapp.HealthCheck https://localhost/healthcheck