Dockerfile 是一个文本文件,它包含了一系列的指令和参数,用来自动化构建 Docker 镜像的过程。每一个指令通常都会创建镜像的一层。下面是一些常用的 Dockerfile 指令。
语法:FROM <image>[:<tag>] [AS <name>]
用法:设定基础镜像,所有后续的指令都基于这个基础镜像来构建。指定一个已存在的镜像作为新镜像的起点。
示例:
# 使用官方的 Node.js 镜像作为基础镜像
FROM node:14
# 为多阶段构建指定一个名称
FROM python:3.8 AS builder
多阶段示例:
# 第一阶段,使用 Node.js 镜像构建前端静态文件
FROM node:12 AS build-stage
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY ./ ./
RUN npm run build
# 第二阶段,使用 Nginx 镜像来提供服务
FROM nginx:stable
COPY --from=build-stage /app/build /usr/share/nginx/html
# 在这个多阶段构建的例子中,第一阶段使用了 node:12 镜像,
# 标记为 build-stage,用于构建前端静态文件。第二阶段则使用 nginx:stable 镜像,
# 从第一阶段复制构建好的静态文件到 Nginx 服务的相应目录中。这样做的好处是,
# 最终的镜像不包含构建前端所需的 Node.js 环境,从而降低了镜像的大小。
语法:RUN <command>
?(shell 格式) 或?RUN ["executable", "param1", "param2"]
?(exec 格式)
用法:执行命令并创建新的镜像层。用于安装软件包、创建文件夹、下载文件等。
示例:
# 使用 shell 形式安装软件包
RUN apt-get update && apt-get install -y git
# 使用 exec 形式执行命令
RUN ["apt-get", "update"]
RUN ["apt-get", "install", "-y", "nginx"]
语法:CMD ["executable","param1","param2"]
?(exec 格式) 或?CMD command param1 param2
?(shell 格式)
用法:提供容器默认的执行命令。设置容器启动后默认执行的命令和参数。
示例:
# 为容器提供默认运行的命令
CMD ["node", "app.js"]
# 使用 shell 形式提供默认命令
CMD echo "Hello, Docker!"
# 当使用 ENTRYPOINT 定义了可执行程序时,CMD 指定所需的参数。
# 在这个例子中,如果你没有给 docker run 提供额外的命令行参数,
# 容器将会输出 "Hello, World!"。如果你提供了额外的参数,
# 比如 docker run <image> Hello, Docker!,
# 那么容器将会输出 "Hello, Docker!",因为 CMD 中的默认参数被覆盖了。
ENTRYPOINT ["/bin/echo"]
CMD ["Hello, World!"]
注意:CMD
?只应该在 Dockerfile 中使用一次。如果定义了多个?CMD
?指令,只有最后一个会生效。
语法:LABEL <key>=<value> <key>=<value> ...
用法:添加元数据。为镜像添加元数据,如维护者信息、版本信息等。
示例:
# 添加单个标签
LABEL version="1.0"
# 添加多个标签
LABEL maintainer="gusy@example.com" description="this is a description"
语法:EXPOSE <port> [<port>/<protocol>...]
用法:声明容器运行时监听的端口。用于指定容器在运行时监听的端口号,供外部连接使用。
示例:
# 暴露 80 端口
EXPOSE 80
# 暴露 80 端口和 443 端口
EXPOSE 80 443
# 暴露 7000 端口使用 TCP 和 7001 使用 UDP
EXPOSE 7000/tcp 7001/udp
语法:ENV <key>=<value> ...
用法:设置环境变量。为镜像构建过程和容器运行时设置环境变量。
示例:
# 单个环境变量
ENV MY_NAME="John Doe"
# 多个环境变量
ENV MY_NAME="John Doe" \
MY_DOG="Rex" \
MY_CAT="Whiskers"
# 使用环境变量的好处是可以在不更改 Dockerfile 的情况下,
# 通过修改环境变量的值来调整容器的行为,这可以在运行容器时通过
# docker run 命令的 -e 或 --env 选项来实现、
docker run -e "MY_NAME=Jane Doe" -e "MY_CAT=Garfield" myimage
语法:ADD <原路径> <目标路径>?
WORKDIR
)的相对路径。用法:复制新文件、目录或远程文件URL到容器的文件系统中指定路径。用于将宿主机的文件添加到镜像中。
<源路径>
?是一个本地压缩格式的归档文件(如 tar、gzip、bzip2 等),ADD
?会自动解压缩这些文件到?<目标路径>
。<源路径>
?是一个 URL,ADD
?会自动下载这个 URL 的内容到?<目标路径>
。ADD
?指令会保留源文件或目录的所有权限信息。示例:
# 添加本地的 test.txt 文件到容器的 /tmp 目录
ADD test.txt /tmp/
# 添加一个目录到容器中的 /path/in/container
ADD my_directory /path/in/container
# 从远程 URL 添加文件到容器中的 /path/in/container
ADD https://example.com/big.tar.xz /path/in/container
# 添加本地的压缩文件 archive.tar.gz,并自动解压到 /path/in/container
ADD archive.tar.gz /path/in/container/
注意:虽然ADD
?功能强大,但 Docker 官方文档推荐尽可能使用?COPY
?指令,因为?COPY
?更透明。COPY
?只支持基本的复制文件和目录的功能,没有自动解压缩的功能,也不支持从 URL 添加文件。如果不需要?ADD
?的特殊功能,使用?COPY
?是更好的选择。
语法:COPY [--chown=<user>:<group>] <src>... <dest>
用法:复制新文件或目录到容器的文件系统中指定路径。类似 ADD,但是不会自动解压缩文件或者支持 URL。
示例:
# 复制当前目录下的 test.txt 到容器的 /tmp 目录
COPY test.txt /tmp/
# 复制当前目录下的文件到容器中的 /tmp,保持原有的文件名
COPY . /tmp/
# 使用多阶段构建时,可能会从一个阶段复制文件到另一个阶段
# 假设在之前的阶段中有一个名为 builder 的阶段
COPY --from=builder /app/output /app/
注意:
<源路径>
?必须在构建上下文中,不能是构建上下文外部的文件或目录。<源路径>
?是目录,则复制目录内的所有内容(不包括目录本身)。<目标路径>
?不存在,它将被自动创建,包括任何必要的中间目录。语法:ENTRYPOINT ["executable", "param1", "param2"]
?(exec 格式) 或?ENTRYPOINT command param1 param2
?(shell 格式)
用法:?配置容器启动时运行的命令,不会被?docker run
?提供的参数覆盖。允许容器像命令一样运行,并且可以向容器传递额外的参数。
示例:
# 使用 exec 形式设置入口点
ENTRYPOINT ["node", "app.js"]
# 使用 shell 形式设置入口点
ENTRYPOINT exec java -jar /usr/share/tag/app.jar
# 结合 CMD 使用,CMD 提供了默认参数
ENTRYPOINT ["/bin/echo", "Hello"]
CMD ["world"]
语法:VOLUME ["/data"]
用法:创建一个可以从本地主机或其他容器挂载的挂载点。用于指定挂载点来持久化数据。
示例:
# 创建一个挂载点目录
VOLUME /data
# 创建多个挂载点
VOLUME ["/data", "/var/log"]
使用:如果你想要启动一个容器,并将本地目录?/path/on/host
?挂载到容器的?/myvol
?目录,你可以使用以下命令:
# 以下例子中,/path/on/host 是你主机上的目录,/myvol 是容器内的挂载点。
# 使用这种方式,你可以在容器之间共享和重用数据。
docker run -v /path/on/host:/myvol myimage
# 或者新的 --mount 语法
docker run --mount type=bind,source=/path/on/host,target=/myvol myimage
注:
数据持久化:卷是用来持久化数据的,即使容器被删除,卷中的数据也会保留。
数据共享与重用:卷可以在容器之间共享和重用。例如,数据库的数据可以存储在卷中,供其他容器访问。
容器间解耦:卷可以帮助解耦容器与数据,使得容器的迁移和备份更加容易。
性能:卷通常可以提供比容器层更好的性能,特别是对于有大量写入操作的应用。
管理:卷的生命周期独立于容器,可以使用 Docker 的卷管理命令来管理。
匿名卷与命名卷:在 Dockerfile 中声明的卷是匿名的,但是用户在使用?docker run
?命令时可以通过?-v
?或?--mount
?标志来创建命名卷或绑定挂载
语法:USER <username>[:<group>]
用法:指定运行容器时的用户名或 UID(和可选的用户组或 GID)。确保容器以特定的用户权限运行。
示例:
# 切换到已存在的用户
USER john
# 切换到 UID
USER 1000
语法:WORKDIR /path/to/workdir
用法:为 RUN、CMD、ENTRYPOINT、COPY 和 ADD 设置工作目录。
示例:
# 设置工作目录
WORKDIR /app
# 在前一个 WORKDIR 的基础上,设置相对路径的工作目录
WORKDIR /app/build
语法:?ARG <name>[=<default value>]
用法: 定义构建时的变量。
示例:
# 定义了一个名为 VERSION 的变量,默认值为 latest
ARG VERSION=latest
# 使用 ARG 定义的变量来指定基础镜像的版本
FROM alpine:$VERSION
# 构建过程使用 alpine:3.12 作为基础镜像。
docker build --build-arg VERSION=3.12
语法:?ONBUILD <INSTRUCTION>
用法: 添加触发器指令,当镜像作为基础镜像时,触发器指令将被执行。
示例:
# 当构建一个继承了此镜像的 Dockerfile 时,运行 npm install
ONBUILD RUN npm install
# 添加触发器拷贝文件
ONBUILD ADD . /app/src
语法:?STOPSIGNAL signal
用法: 设置停止容器时发送给容器的系统调用信号。
示例:
# 设置 STOPSIGNAL 为 SIGTERM
STOPSIGNAL SIGTERM
语法:?HEALTHCHECK [OPTIONS] CMD command
?或?HEALTHCHECK NONE
用法: 告诉 Docker 如何测试容器以检查它是否仍在运行。
示例:
# 设置健康检查命令
HEALTHCHECK CMD curl --fail http://localhost:8080/ || exit 1
# 设置带有选项的健康检查
HEALTHCHECK --interval=5m --timeout=3s \
CMD curl -f http://localhost/ || exit 1
# 禁用健康检查
HEALTHCHECK NONE
语法:?SHELL ["executable", "parameters"]
用法: 设置运行命令时使用的默认 shell。
示例:
# 更改默认 shell 到 powershell
SHELL ["powershell", "-command"]