java docker总结-dockerfile

时间:2025-08-28 08:54:02来源:互联网

下面小编就为大家分享一篇java docker总结-dockerfile,具有很好的参考价值,希望对大家有所帮助。

Dockerfile说明:

Dockerfile 是一个用来构建镜像的文本文件,文本内容包含了一条条构建镜像所需的指令和说明。

Dockerfile 是由一系列的指令和参数构成的脚本,这些指令应用于基础镜像并创建一个新的镜像。以下是一些常用的 Dockerfile 指令:

- FROM:设置基础镜像,格式为 FROM <image>[:<tag>] [AS <name>]。

- RUN:执行任何被后续 CMD 指令引用的命令。

- CMD:提供容器默认的执行命令,格式为 CMD ["executable","param1","param2"]。

- LABEL:为镜像添加元数据,格式为 LABEL <key>=<value> <key>=<value> ...。

- EXPOSE:声明运行时容器提供服务的网络端口,格式为 EXPOSE <port> [<port>/<protocol>...]。

- ENV:设置环境变量,格式为 ENV <key>=<value> ...。

- ADD:将文件、目录或远程文件 url 添加到镜像,格式为 ADD <src>... <dest>。

- COPY:将新文件或目录复制到容器的文件系统,格式为 COPY [--chown=<user>:<group>] <src>... <dest>。

- ENTRYPOINT:为容器配置默认的可执行程序,格式为 ENTRYPOINT ["executable", "param1", "param2"]。

- VOLUME:创建一个可以从本地主机或其他容器挂载的挂载点,格式为 VOLUME ["/data"]。

- USER:设置运行容器时的用户名或 UID,格式为 USER <user>[:<group>]。

- WORKDIR:设置工作目录,格式为 WORKDIR /path/to/workdir。

- ARG:定义构建参数,格式为 ARG <name>[=<default value>]。

- ONBUILD:配置当镜像被作为其他镜像的基础镜像时,执行的操作,格式为 ONBUILD [INSTRUCTION]。

这些指令在 Dockerfile 中按照从上到下的顺序执行。Dockerfile 中的每一行都会创建一个新的镜像层并对镜像进行修改。当你修改 Dockerfile 并重新构建镜像时,只有从你修改的那一行指令开始的后续层会被重新构建。
 

实例:

# 使用官方的Python运行时作为父镜像
FROM python:3.7-slim

# 设置工作目录
WORKDIR /app

# 将当前目录的内容复制到容器的/app目录中
ADD . /app

# 安装在requirements.txt中列出的任何需要的包
RUN pip install --no-cache-dir -r requirements.txt

# 使容器监听80端口
EXPOSE 80

# 定义环境变量
ENV NAME World

# 在容器启动时运行app.py
CMD ["python", "app.py"]

构建镜像实例:

下面以定制一个 nginx 镜像(构建好的镜像内会有一个 /usr/share/nginx/html/index.html 文件):

在一个空目录下,新建一个名为 Dockerfile 文件,并在文件内添加以下内容:

FROM nginx

RUN echo '这是一个本地构建的nginx镜像' > /usr/share/nginx/html/index.html

FROM:定制的镜像都是基于 FROM 的镜像,这里的 nginx 就是定制需要的基础镜像。后续的操作都是基于 nginx。

注意:Dockerfile 的指令每执行一次都会在 docker 上新建一层。所以过多无意义的层,会造成镜像膨胀过大。例如:

FROM centos
RUN yum install wget
RUN wget -O redis.tar.gz "http://download.redis.io/releases/redis-5.0.3.tar.gz"
RUN tar -xvf redis.tar.gz
以上执行会创建 3 层镜像。可简化为以下格式:

FROM centos
RUN yum install wget 
    && wget -O redis.tar.gz "http://download.redis.io/releases/redis-5.0.3.tar.gz" 
    && tar -xvf redis.tar.gz

如上,以 && 符号连接命令,这样执行后,只会创建 1 层镜像。

开始构建镜像

在 Dockerfile 文件的存放目录下,执行构建动作。

以下示例,通过目录下的 Dockerfile 构建一个 nginx:v3(镜像名称:镜像标签)。

注:最后的 . 代表本次执行的上下文路径

docker build -t nginx:v3 .

 

上下文路径是指 docker 在构建镜像,有时候想要使用到本机的文件(比如复制),docker build 命令得知这个路径后,会将路径下的所有内容打包。如果未说明最后一个参数,那么默认上下文路径就是 Dockerfile 所在的位置。

指令说明

FROM:

FROM 是 Dockerfile 中的第一个指令,它定义了将要构建的新镜像的基础镜像。

FROM <image>[:<tag>] [AS <name>]

- <image>: 基础镜像的名称。这可以是任何可用的镜像,它可以是 Docker Hub 上的公共镜像,也可以是私有仓库中的镜像。
- [:<tag>] (可选): 基础镜像的标签。如果不指定,Docker 将使用 latest 标签。
- [AS <name>] (可选): 为新的构建阶段设置一个名称。这在多阶段构建中非常有用,可以用来引用特定的构建阶段。

例如,以下 Dockerfile 使用 ubuntu:18.04 作为基础镜像:

FROM ubuntu:18.04

如果在 FROM 指令中没有指定镜像仓库地址,Docker 默认会从 Docker Hub(https://hub.docker.com/)下载基础镜像。Docker Hub 是 Docker 的公开镜像仓库

多阶段构建

Dockerfile的多阶段构建是一种优化构建过程和减小最终镜像大小的方法。在多阶段构建中,你可以使用多个临时的中间镜像进行编译和其他任务,然后在最后阶段只复制所需的内容到最终镜像。

以下是一个简单的例子:

# 第一阶段:使用Golang镜像进行编译
FROM golang:1.16 AS build
WORKDIR /src
COPY . .
RUN go build -o app .

# 第二阶段:只复制编译后的程序到最终镜像
FROM alpine:latest
WORKDIR /app
COPY --from=build /src/app /app/
ENTRYPOINT ["./app"]

在这个例子中,第一阶段使用 golang:1.16 镜像进行编译,然后在第二阶段,我们只复制了编译后的程序到最终的 alpine:latest 镜像中,这样可以大大减小最终镜像的大小。

--from=build 指定了复制文件的源镜像,这里是第一阶段的镜像。/src/app 是在第一阶段镜像中的文件路径,/app/ 是在最终镜像中的目标路径。
 

 

RUN:

用于在镜像构建过程中执行命令。这些命令通常用于安装软件包、设置环境变量、运行构建任务等。

每个 RUN 指令都会在当前镜像的基础上创建一个新的层,并提交为新的临时镜像。如果 Dockerfile 中有多个 RUN 指令,那么就会创建多个层。因此通常建议将多个相关的命令组合在一行中,以减少镜像层的数量。 

RUN 指令后面可以跟任何在基础镜像的 shell 中可以执行的命令。这些命令主要取决于你的基础镜像。

用于执行后面跟着的命令行命令。有以下俩种格式:

shell 格式

RUN <command>
# <command> 等同于,在终端操作的 shell 命令。

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

exec 格式

在 Exec 形式中,executable 和参数列表是一个 JSON 数组。这种形式不会启动 shell,因此不需要考虑 shell 的特性或兼容性问题。

RUN ["executable", "param1", "param2"]

# 例如:
# RUN ["./test.php", "dev", "offline"] 等价于 RUN ./test.php dev offline

 

COPY

复制指令,从上下文目录中复制文件或者目录到容器里指定路径。

格式:

COPY [--chown=<user>:<group>] <src>... <dest>

[--chown=<user>:<group>]:可选参数,用户改变复制到容器内文件的拥有者和属组。

- <src>: 源文件或目录,可以指定多个,路径是相对于 Docker 构建上下文的。如果是目录,会复制目录及其内部的所有内容。
- <dest>: 目标路径,如果目标路径不存在,Docker 会自动创建。

COPY 指令只能复制 Docker 构建上下文中的文件,不能复制 Docker 主机上的文件。如果你需要复制 Docker 主机上的文件,可以使用 ADD 指令。

可以是通配符表达式,其通配符规则要满足 Go 的 filepath.Match 规则。例如:

COPY hom* /mydir/

COPY hom?.txt /mydir/

可以复制多个文件

COPY file1.js file2.js /app/

可以是目录

COPY app/ /app/

ADD

用于将文件或目录从 Docker 构建上下文复制到新的镜像中。与 COPY 指令不同,ADD 还有一些额外的功能:
1. 可以处理网络 URL。如果 <src> 是一个 URL,Docker 会下载这个 URL 的内容并复制到 <dest>。
2. 可以自动解压缩本地的 tar 文件。压缩格式为 gzip, bzip2 以及 xz 的情况下,会自动复制并解压到 <目标路径>。

格式:

ADD [--chown=<user>:<group>] <src>... <dest>

将当前目录下的 app.tar.gz 文件解压缩并复制到镜像的 /app 目录中:

ADD app.tar.gz /app/

如果 <src> 是一个 URL,Docker 会下载这个 URL 的内容:

ADD http://example.com/app.tar.gz /app/

尽管 ADD 指令功能强大,但在大多数情况下,推荐使用 COPY 指令,因为 COPY 更简单,更明确。只有在需要自动解压缩 tar 文件或处理网络 URL 时,才使用 ADD 指令。 

 

ADD 指令相比 COPY 指令的主要缺点有以下几点:

1. 不明确:ADD 指令既可以复制文件,也可以解压缩文件,还可以下载网络文件。这种多功能性使得 ADD 指令的行为不够明确,可能会导致意外的结果。

2. 可能导致缓存失效:如果 ADD 指令的 <src> 是一个 URL,那么每次构建镜像时,Docker 都会尝试下载这个 URL 的内容,即使 URL 指向的文件没有变化。这可能会导致 Docker 缓存失效,增加构建时间。

3. 可能增加镜像大小:如果 <src> 是一个 tar 文件,ADD 指令会自动解压缩这个文件。这可能会导致镜像大小增加,特别是当 tar 文件包含了大量不需要的文件时。

因此,除非需要 ADD 指令的特殊功能(如解压缩 tar 文件或下载网络文件),否则推荐使用 COPY 指令。
 

 

构建镜像的缓存机制:

Docker 在构建镜像时会尽可能地使用缓存以提高构建速度。这是通过检查每个指令和它的参数来实现的。如果 Docker 发现一个指令和它的参数与之前构建的一个层完全相同,那么 Docker 就会使用这个已经存在的层,而不是重新执行这个指令。

例如,假设你有以下的 Dockerfile:

FROM ubuntu:18.04
RUN apt-get update
RUN apt-get install -y curl
COPY . /app

在第一次构建镜像时,Docker 会执行所有的指令。但在第二次构建镜像时,如果 Dockerfile 没有改变,那么 Docker 就会使用缓存的层,而不是重新执行指令。
但是,如果你改变了 COPY . /app 这一行,例如改变了本地目录中的文件,那么 Docker 就会重新执行这个指令和它后面的所有指令,因为这个指令的结果可能会影响后面的指令。
注意,ADD 和 COPY 指令会检查文件的内容和元数据,如果文件没有改变,那么 Docker 就会使用缓存。但是,如果 ADD 指令的参数是一个 URL,那么 Docker 每次都会尝试下载这个 URL 的内容,即使 URL 指向的文件没有变化,这可能会导致缓存失效。
为了最大化利用缓存,通常建议将不经常改变的指令(如安装软件包的 RUN 指令)放在 Dockerfile 的前面,将经常改变的指令(如复制源代码的 COPY 指令)放在 Dockerfile 的后面。
 

CMD

用于提供容器启动时的默认命令。CMD 指令有两种格式:

1. Shell 格式:CMD command param1 param2
2. Exec 格式:CMD ["executable","param1","param2"]

例如,以下 Dockerfile 使用 shell 格式的 CMD 指令启动一个 web 服务器:

CMD python -m SimpleHTTPServer 8080

使用 exec 格式的 CMD 指令:

CMD ["python", "-m", "SimpleHTTPServer", "8080"]

如果 Dockerfile 中同时存在 CMD 和 ENTRYPOINT 指令,那么 CMD 中的参数将会被添加到 ENTRYPOINT 指令的参数后面。

如果在运行 docker run 命令时指定了任何命令,那么 CMD 指令将会被忽略。例如,如果你运行 docker run image_name python app.py,那么 CMD 指令中的 python -m SimpleHTTPServer 8080 将会被 python app.py 替换。

注意,每个 Dockerfile 只能有一个 CMD 指令。如果指定了多个 CMD 指令,那么只有最后一个 CMD 指令会生效。

推荐使用Exec 格式:

1. 更可靠:Exec 格式不会通过 shell 执行,这意味着你的命令不会受到环境变量或 shell 特性的影响,执行结果更可预测。
2. 信号传递:如果使用 Exec 格式,当 Docker 发送停止信号(如 SIGTERM)时,信号会直接传递给你的进程,而不是 shell。这使得你的进程可以正确地收到并处理这些信号。

 

CMD指令和RUN指令对比

1. 执行时间:RUN 指令在镜像构建阶段执行,而 CMD 指令在容器启动阶段执行。

2. 用途:RUN 指令主要用于安装软件包和设置环境,而 CMD 指令用于设置容器启动后默认执行的命令和参数。

以下 Dockerfile 使用 RUN 指令安装了 Node.js,然后使用 CMD 指令设置了容器启动后运行的命令:

FROM ubuntu:18.04
RUN apt-get update && apt-get install -y nodejs
CMD ["node", "-v"]

 

ENTRYPOINT

用于设置容器启动时默认执行的命令。ENTRYPOINT 指令有两种格式:

1. Shell 格式:ENTRYPOINT command param1 param2
2. Exec 格式:ENTRYPOINT ["executable","param1","param2"]

shell格式:

ENTRYPOINT python -m SimpleHTTPServer 8080

exec 格式:

ENTRYPOINT ["python", "-m", "SimpleHTTPServer", "8080"]

如果 Dockerfile 中同时存在 CMD 和 ENTRYPOINT 指令,那么 CMD 中的参数将会被添加到 ENTRYPOINT 指令的参数后面。

如果在运行 docker run 命令时指定了任何命令,那么这些命令将会被添加到 ENTRYPOINT 指令的参数后面,而不是替换 ENTRYPOINT 指令。

注意,每个 Dockerfile 只能有一个 ENTRYPOINT 指令。如果指定了多个 ENTRYPOINT 指令,那么只有最后一个 ENTRYPOINT 指令会生效。
 

 

类似于 CMD 指令,但其不会被 docker run 的命令行参数指定的指令所覆盖,而且这些命令行参数会被当作参数送给 ENTRYPOINT 指令指定的程序。

 

但是, 如果运行 docker run 时使用了 --entrypoint 选项,将覆盖 CMD 指令指定的程序。

优点:在执行 docker run 的时候可以指定 ENTRYPOINT 运行所需的参数。

 

可以搭配 CMD 命令使用:一般是变参才会使用 CMD ,这里的 CMD 等于是在给 ENTRYPOINT 传参,以下示例会提到。

示例:

假设已通过 Dockerfile 构建了 nginx:test 镜像:

FROM nginx

ENTRYPOINT ["nginx", "-c"] # 定参
CMD ["/etc/nginx/nginx.conf"] # 变参

1、不传参运行

$ docker run  nginx:test

容器内会默认运行以下命令,启动主进程。

nginx -c /etc/nginx/nginx.conf

 

2、传参运行

$ docker run  nginx:test -c /etc/nginx/new.conf

容器内会默认运行以下命令,启动主进程(/etc/nginx/new.conf:假设容器内已有此文件)

nginx -c /etc/nginx/new.conf

 

ENV

用于设置环境变量。这些环境变量在构建镜像和运行容器时都可用。

ENV 指令有两种格式:

1. 单个键值对:ENV <key>=<value>
2. 多个键值对:ENV <key1>=<value1> <key2>=<value2> ...

在 Dockerfile 中设置的环境变量可以在 RUN, CMD, ENTRYPOINT 等指令中使用。例如:

ENV VERSION=1.0
RUN echo $VERSION > version.txt

如果你只想在构建镜像时使用环境变量,可以使用 ARG 指令。

ARG

用于定义在构建过程中可以使用的变量。这些变量在构建镜像时可用,但在运行容器时不可用。

格式如下:ARG <name>[=<default value>]

以下 Dockerfile 定义了一个名为 VERSION 的变量:

ARG VERSION

在 Dockerfile 中,你可以使用 ARG 变量,如下所示:

ARG VERSION=1.0
RUN echo $VERSION > version.txt

可以在运行 docker build 命令时使用 --build-arg <varname>=<value> 选项来覆盖 ARG 指令的值。例如:

docker build --build-arg VERSION=2.0 .

构建参数,与 ENV 作用一致。不过作用域不一样。ARG 设置的环境变量仅对 Dockerfile 内有效,也就是说只有 docker build 的过程中有效,构建好的镜像内不存在此环境变量。

构建命令 docker build 中可以用 --build-arg <参数名>=<值> 来覆盖。

在这个例子中,VERSION 变量的值被设置为 2.0。

 

VOLUME

用于在容器中创建一个挂载点,与 Docker 主机的文件系统进行交互。

VOLUME 指令的格式如下:VOLUME ["/path/to/directory"]

作用:

避免重要的数据,因容器重启而丢失,这是非常致命的。

避免容器不断变大。

例如,以下 Dockerfile 创建了一个挂载点 /data:

VOLUME ["/data"]

在这个例子中,/data 目录可以用于持久化数据或与 Docker 主机共享数据。

当你运行一个包含 VOLUME 指令的容器时,Docker 会在主机上自动创建一个新的匿名卷,并挂载到容器的 /data 目录。你也可以在运行 docker run 命令时使用 -v 选项来指定挂载点的源目录或卷。

指定多个挂载点:

VOLUME ["/data1"]
VOLUME ["/data2"]

也可以在一个 VOLUME 指令中指定多个挂载点,只需将它们放在同一个数组中即可:

VOLUME ["/data1", "/data2"]


注意,VOLUME 指令不能在 Dockerfile 中指定卷的源目录,源目录只能在运行容器时指定。
 没有指定会自动创建匿名卷来挂载

可以使用 docker inspect 命令来查看容器的详细信息,包括挂载点和卷的信息。例如:

docker inspect container_id

在输出的 JSON 中,你可以找到 "Mounts" 部分,这里会显示所有的挂载点和卷的信息,包括源目录和目标目录。 

docker run命令指定源目录:

docker run -v <host-directory>:<container-path> ...

或 docker run --volume <host-directory>:<container-path> ...

如果 <host-directory> 是一个目录,并且该目录在 Docker 主机上不存在,Docker 会自动创建该目录。 

dockerfile中没有使用VOLUME指令指定挂载点也不影响docker run指定的挂载生效

例子:

以下命令将主机上的 /home/user/data 目录挂载到容器的 /data 目录:docker run -v /home/user/data:/data imageName

 

EXPOSE

用于指定容器监听的网络端口

格式如下:EXPOSE <port> [<port>/<protocol>...]

以下 Dockerfile 指定了容器监听 80 端口:

EXPOSE 80

也可以指定协议(TCP 或 UDP)。如果没有指定协议,Docker 会默认使用 TCP。

EXPOSE 80/tcp 53/udp

EXPOSE 指令并不会使容器的端口对 Docker 主机或网络可见。它充当了构建人员和运行人员之间的一种文档,即打算发布哪些端口信息在运行容器时映射端口

要将容器的端口映射到 Docker 主机,你需要在运行 docker run 命令时使用 -p 或 --publish 选项。

docker run -p 80:80 image_name

在这个例子中,Docker 主机的 80 端口被映射到了容器的 80 端口。

随机端口映射:

docker run 命令的 -P 或 --publish-all 选项可以将 EXPOSE 指令在 Dockerfile 中指定的所有端口映射到 Docker 主机的随机端口。例如:

 docker run -P image_name

在这个例子中,Docker 会自动将 EXPOSE 指令指定的所有端口映射到 Docker 主机的随机端口。

你可以使用 docker port 命令来查看这些映射的端口。例如:

docker port container_id

这个命令会显示容器的所有端口映射,包括 EXPOSE 指令指定的端口和 docker run -P 命令映射的随机端口。

WORKDIR

用于设置后续指令(如 RUN, CMD, ENTRYPOINT, COPY 和 ADD)的工作目录。

指令的格式如下:WORKDIR /path/to/workdir

WORKDIR /app

在这个例子中,如果后续有 RUN, CMD, ENTRYPOINT, COPY 或 ADD 指令,它们会在 /app 目录下执行。

如果指定的工作目录不存在,Docker 会自动创建这个目录。

你可以在 Dockerfile 中使用多个 WORKDIR 指令。如果有多个 WORKDIR 指令,每个 WORKDIR 指令都会在前一个 WORKDIR 指令的基础上修改工作目录。

WORKDIR /app
WORKDIR src

在这个例子中,工作目录最终被设置为 /app/src。

如果你没有在 Dockerfile 中使用 WORKDIR 指令,Docker 会使用默认的工作目录,这通常是根目录 /。

 

USER

用于设置后续指令(如 RUN, CMD 和 ENTRYPOINT)的执行用户。

格式如下:USER <user> 或 USER <user>:<group>

以下 Dockerfile 设置了执行用户为 myuser:

USER myuser

在这个例子中,如果后续有 RUN, CMD 或 ENTRYPOINT 指令,它们会以 myuser 用户的身份执行。

注意,指定的用户和用户组必须在镜像中存在。如果不存在,你需要在 USER 指令之前使用 RUN 指令来创建它们。

HEALTHCHECK

用于检查容器中的应用是否还在运行。如果应用停止运行,Docker 可以自动重启容器。

指令有两种形式:

1. HEALTHCHECK [OPTIONS] CMD command:用于设置健康检查命令和参数。
2. HEALTHCHECK NONE:用于禁用任何先前的健康检查。

在第一种形式中,command 是用于检查应用是否还在运行的命令。这个命令应该在容器内部执行,并返回状态码 0(表示健康)或 1(表示不健康)。

OPTIONS 可以是以下选项:

- --interval=DURATION(默认值:30s):两次健康检查之间的间隔。
- --timeout=DURATION(默认值:30s):健康检查命令的超时时间。
- --start-period=DURATION(默认值:0s):容器启动后,开始进行健康检查之前的等待时间。
- --retries=N(默认值:3):连续多少次健康检查失败后,容器被认为是不健康。

例如,以下 Dockerfile 设置了每 5 分钟进行一次健康检查,健康检查命令的超时时间为 3 秒,容器启动后立即开始健康检查,连续 3 次健康检查失败后,容器被认为是不健康:

HEALTHCHECK --interval=5m --timeout=3s 
  --start-period=0s --retries=3 
  CMD curl -f http://localhost/ || exit 1

在这个例子中,健康检查命令是 curl -f http://localhost/ || exit 1。这个命令尝试访问容器的本地服务器,如果访问失败,返回状态码 1。 

ONBUILD

用于添加将在后续构建中执行的触发器。这些触发器会在下一次 FROM 指令使用当前镜像作为基础镜像时执行。

格式如下:ONBUILD <INSTRUCTION>

以下 Dockerfile 添加了一个 ONBUILD 触发器,该触发器在后续构建中会复制 app/ 目录到工作目录:

ONBUILD COPY app/ .

在这个例子中,如果有另一个 Dockerfile 使用 FROM 指令引用这个镜像,那么 COPY app/ . 指令会在那个 Dockerfile 的所有指令之前执行。

ONBUILD 指令通常用于创建将被用作基础镜像的镜像,这些基础镜像包含了一些在后续构建中通常需要执行的指令。
 

 

LABEL

用于添加元数据到镜像。这些元数据以键值对的形式存储,可以包含任何你想添加的信息,如镜像的版本、构建日期或者维护者的联系信息。

LABEL 指令的格式如下:LABEL <key>=<value> <key>=<value> ...

例如,以下 Dockerfile 添加了两个标签,一个表示镜像的版本,一个表示维护者的邮箱:

LABEL version="1.0" maintainer.email="[email protected]"

你可以使用 docker inspect 命令查看镜像的标签。 

本站部分内容转载自互联网,如果有网站内容侵犯了您的权益,可直接联系我们删除,感谢支持!