Dockerfile 简单使用
Dockerfile 是用来构建 Docker 镜像的文本文件,它包含了一系列的指令和配置,用于告诉 Docker 如何构建一个镜像。
以 Web 开发为例,我们可以在官方 nginx 镜像基础上,添加自定义的网页文件、修改配置文件、安装必要的工具等。
具体操作如下:
- 创建一个新的空白目录
myweb
。 - 在目录
myweb
下创建一个文本文件,命名为Dockerfile
,并在文件中添加如下内容。
# 指定使用最新版 nginx 作为基础镜像
FROM nginx:latest
# 将网页内容放到容器的 nginx 默认的网页目录中
RUN echo '<h1>My Custom Nginx Page</h1>' > /usr/share/nginx/html/index.html
# 声明容器会使用 80 端口
EXPOSE 80
- 在
myweb
目录下运行命令docker build -t my-web
. 进行自定义 nginx 镜像构建。
这样就完成了自定义 nginx 镜像的构建。其中 -t my-web
是给新镜像命名为 my-web
,最后的点表示使用当前目录的 Dockerfile。
构建完成后可以用 docker images
查看新构建的镜像。
docker images
- 运行
docker run -d -p 80:80 my-web
启动容器。
这时访问主机的 80 端口就能看到自定义网页了。
Dockerfile 常用指令
FROM 指令
FROM 指令用于指定基础镜像,必须是 Dockerfile 的第一个指令。基础镜像可以是官方镜像如 ubuntu:20.04,也可以是用户自定义的镜像。如果不指定标签,默认使用 latest 标签。例如 FROM nginx 表示基于最新版 nginx 镜像构建。
FROM 指令格式:
FROM <image>[:<tag>] [AS <name>]
参数说明:
<image>
:必需,指定基础镜像名称。:<tag>
:可选,指定镜像版本标签。AS <name>
:可选,为构建阶段命名。
示例:
FROM nginx:1.23
FROM python:3.9-alpine
FROM ubuntu:20.04 AS builder
LABEL 指令
用于添加元数据到镜像,采用键值对格式。
LABEL 指令格式:
LABEL <key>=<value>
示例:
LABEL version="1.0.1"
LABEL maintainer="admin@example.com"
RUN 指令
在镜像构建过程中执行命令,每条 RUN 指令都会创建一个新的镜像层。
RUN 有两种格式:Shell 格式(RUN <command>
)和 Exec 格式(RUN ["executable", "param1", "param2"])。
Shell 格式默认使用/bin/sh -c
执行,Exec 格式直接调用可执行文件。为了减少镜像层数,建议将多个命令合并到单个 RUN 指令中,用 &&
连接命令,用 \
换行。例如安装软件包时应该先更新包列表再安装,最后清理缓存。
RUN 指令格式:
# Shell 格式
RUN <command>
# Exec 格式
RUN ["executable", "param1", "param2"]
示例:
RUN yum -y install wget
RUN apt-get update && apt-get install -y \
git \
curl \
&& rm -rf /var/lib/apt/lists/*
RUN ["/bin/bash", "-c", "echo Hello, Docker!"]
RUN ["yum", "-y", "install", "wget"]
CMD 指令
指定容器启动时的默认命令,一个 Dockerfile 只能有一个有效的 CMD 指令。如果 docker run 指定了命令,CMD 会被覆盖。 CMD 有三种格式:Exec 格式(推荐)、Shell 格式和作为 ENTRYPOINT 的参数。
Exec 格式直接调用可执行文件,不经过 shell 处理环境变量;
Shell 格式会通过 /bin/sh -c 执行。例如运行 Python 应用时可以使用 CMD ["python", "app.py"]
。
CMD 指令格式:
# Exec 格式(推荐)
CMD ["executable","param1","param2"]
# Shell 格式
CMD command param1 param2
# 作为 ENTRYPOINT 的参数
CMD ["param1","param2"]
示例:
# Shell 格式示例: 运行 Python 脚本
CMD python app.py
# Exec 格式示例: 运行 Nginx
CMD ["nginx", "-g", "daemon off;"]
# 作为 ENTRYPOINT 参数
CMD ["--port=8080"]
ENTRYPOINT 指令
用于设置容器启动时的主要命令,与 CMD 不同,它不会被 docker run 后面的命令覆盖。
ENTRYPOINT 指令格式:
# Shell 格式
ENTRYPOINT command param1 param2
# Exec 格式
ENTRYPOINT ["executable", "param1", "param2"]
示例:
# Shell 格式示例: 运行 Python 脚本
ENTRYPOINT python app.py
# Exec 格式示例: 运行 Nginx
ENTRYPOINT ["nginx", "-g", "daemon off;"]
SHELL 指令
用于覆盖 Docker 默认的 shell 程序。默认情况下 Linux 使用 ["/bin/sh
", "-c
"],Windows 使用 ["cmd
", "/S
", "/C
"]。这个指令会影响 RUN、CMD 和 ENTRYPOINT 的 shell 格式执行方式。
SHELL 指令格式
SHELL ["executable", "parameters"]
示例:
# 切换为 PowerShell
SHELL ["powershell", "-command"]
# 切换回默认 shell
SHELL ["/bin/sh", "-c"]
EXPOSE 指令
声明容器运行时监听的网络端口,实际端口映射需要在运行容器时通过 -p
参数设置。 EXPOSE 可以指定 TCP 或 UDP 协议,默认是 TCP。
例如 EXPOSE 80/tcp
表示容器会监听 80
端口。
EXPOSE 指令格式:
EXPOSE <port> [<port>/<protocol>...]
示例:
# 声明单个端口
EXPOSE 80
# 声明多个端口
EXPOSE 80 443
# 指定协议
EXPOSE 53/udp
ENV 指令
设置环境变量,这些变量会在构建阶段和容器运行时生效。
ENV 指令格式:
# 定义单个变量
ENV <key> <value>
# 一次性定义多个变量
ENV <key1>=<value1> <key2>=<value2>...
示例:
# 设置单个变量
ENV NODE_VERSION=18.15.0
# 设置多个变量
ENV NODE_VERSION=18.15.0 NODE_ENV=production
COPY 指令
将文件或目录从构建上下文复制到镜像中,源路径
必须是相对路径
(相对于 Dockerfile 所在目录),不能使用绝对路径或 ../ 父目录引用。目标路径
可以是绝对路径
或相对于 WORKDIR 的路径。COPY 会保留文件元数据(权限、时间戳),但不支持自动解压压缩包。
例如复制项目代码到镜像的 /app 目录。
COPY 指令格式:
COPY <src>... <dest>
示例:
# 复制单个文件
COPY requirements.txt /app/
# 复制整个目录
COPY src /app/src
# 使用通配符复制多个文件
COPY *.sh /scripts/
ADD 指令
ADD 指令功能类似 COPY,但增加了自动解压压缩包
和处理远程 URL 的能力。当源路径是本地压缩文件(如 .tar、.gz)时,ADD 会自动解压到目标路径。源路径也可以是 URL,Docker 会下载文件到镜像中。例如 ADD https://example.com/file.tar.gz /tmp 会下载并解压文件。
ADD 指令格式:
ADD <src>... <dest>
示例:
# 添加本地文件
ADD app.jar /opt/app/
# 自动解压压缩包
ADD project.tar.gz /app
# 从 URL 下载文件
ADD https://example.com/data.json /data
WORKDIR 指令
设置工作目录,相当于 cd 命令的效果,如果目录不存在会自动创建。后续的 RUN、CMD、COPY 等指令都会在此目录下执行。WORKDIR 可以多次使用,路径可以是相对路径
(基于前一个 WORKDIR)。例如 WORKDIR /app 后接 WORKDIR src 最终路径是 /app/src。
WORKDIR 指令格式:
WORKDIR <path>
示例:
WORKDIR /usr/src
WORKDIR app
RUN pwd # 输出 /usr/src/app
VOLUME 指令
创建挂载点或声明卷,会在容器运行时自动挂载匿名卷。主要用途是保留重要数据(如数据库文件)或共享目录。例如 VOLUME /data 确保 /data 目录的数据持久化。
数据卷可以在容器间共享和重用,即使容器被删除,卷数据仍然存在。
VOLUME 声明后,运行时可以通过 -v
参数覆盖,但无法在构建阶段向挂载点写入数据(会被运行时覆盖)。
VOLUME 指令格式:
VOLUME ["<path1>", "<path2>", ...]
示例:
# 声明单个卷
VOLUME /data
# 声明多个卷
VOLUME ["/data", "/config"]
USER 指令
切换执行后续指令的用户身份,用户必须已通过 RUN 指令创建。
例如 USER nobody 让后续命令以 nobody 身份运行,增强安全性。该用户需要有足够的权限访问所需文件。
USER 指令格式:
USER <user>[:<group>]
示例:
RUN groupadd -r app && useradd -r -g app appuser
USER appuser
CMD ["python", "app.py"]
ARG 指令
指令定义构建时的变量。这些变量只在构建阶段有效,不会保留到容器运行时。可以通过 docker build --build-arg <name>=<value>
覆盖默认值。
例如 ARG VERSION=latest 定义版本变量。ARG 变量可以用于控制构建流程,如选择不同的软件版本。
ARG 指令格式:
ARG <name>[=<默认值>]
示例:
ARG NODE_VERSION=14
FROM node:${NODE_VERSION}
ONBUILD 指令
设置触发器。当当前镜像被用作其他镜像的基础时,这些指令会被触发执行。
例如 ONBUILD COPY . /app
会在子镜像构建时自动复制文件。ONBUILD 常用于创建基础镜像模板,子镜像可以继承特定的构建步骤。
通过 docker inspect 可以查看镜像的 ONBUILD 触发器。
ONBUILD 指令格式:
ONBUILD <其他指令>
示例:
ONBUILD RUN npm install
ONBUILD COPY . /app
STOPSIGNAL 指令
设置容器停止时发送的系统信号。信号可以是数字(如 9)或信号名(如 SIGKILL)。默认的信号是 SIGTERM,允许容器优雅退出。如果需要强制终止,可以设置为 SIGKILL。
例如 STOPSIGNAL SIGTERM 确保容器收到终止信号。这个设置会影响 docker stop 命令的行为。
STOPSIGNAL 指令格式:
STOPSIGNAL <信号>
示例:
STOPSIGNAL SIGQUIT
HEALTHCHECK 指令
定义容器健康检查,Docker 会定期执行检查命令判断容器是否健康。
检查命令返回 0 表示健康,1 表示不健康。
选项包括
- -interval(检查间隔)、
- -timeout(超时时间)、
- -start-period(启动宽限期)
- -retries(重试次数)。
例如 HEALTHCHECK --interval=30s CMD curl -f http://localhost/
每 30 秒检查 Web 服务是否响应。健康状态可以通过 docker ps
查看。
HEALTHCHECK 指令格式:
HEALTHCHECK [OPTIONS] CMD <command>
示例:
HEALTHCHECK --interval=5m --timeout=3s \
CMD curl -f http://localhost/ || exit 1