Docker Dockerfile指令简介

Dockerfile 是 Docker 用来定义容器镜像构建过程的脚本文件,包含一系列指令来描述如何构建镜像。以下是对 WORKDIRCOPYRUNENVCMD 指令的详细介绍,包括其功能、语法、用法和注意事项。


1. WORKDIR

功能

WORKDIR 指令用于设置 Dockerfile 中后续指令的工作目录(类似于 Linux 的 cd 命令)。它指定了在容器内执行命令或程序时的当前目录。如果指定的目录不存在,Docker 会自动创建。

语法

WORKDIR /path/to/workdir

用法

  • WORKDIR 定义的路径会影响后续的 RUNCMDENTRYPOINTCOPYADD 等指令的执行环境。
  • 可以多次使用 WORKDIR,每次都会切换到新的工作目录。
  • 支持相对路径和绝对路径:
  • 绝对路径:推荐使用,例如 WORKDIR /app
  • 相对路径:相对于上一个 WORKDIR 设置的目录。
  • 如果没有设置 WORKDIR,默认工作目录是 /(容器根目录)。

示例

WORKDIR /app
COPY . .
RUN pip install -r requirements.txt
  • 上述代码将工作目录设置为 /appCOPYRUN 指令会在 /app 目录下执行。
  • 如果再次设置 WORKDIR /data,后续指令会在 /data 下执行。

注意事项

  • 建议使用绝对路径以提高可读性和避免路径混淆。
  • 多次使用 WORKDIR 不会影响镜像的层级,但会影响指令的执行环境。
  • WORKDIR 设置的工作目录在容器运行时会成为默认的工作目录,除非 CMDENTRYPOINT 覆盖。

2. COPY

功能

COPY 指令用于将构建上下文(本地文件或目录)中的文件或目录复制到镜像中的指定路径。

语法

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

用法

  • <src>:源文件或目录的路径,相对于构建上下文(通常是 Dockerfile 所在目录)。
  • <dest>:目标路径,可以是镜像内的绝对路径或相对于 WORKDIR 的相对路径。
  • 支持复制多个源文件到目标路径(用空格分隔)。
  • --chown=<user>:<group>:(可选)设置复制文件的所有者和组(仅在 ADDCOPY 支持)。

示例

WORKDIR /app
COPY package.json .
COPY src/ ./src/
COPY --chown=user:group config.ini /config/config.ini
  • 第一行:将本地的 package.json 复制到镜像的 /app 目录。
  • 第二行:将本地 src 目录复制到镜像的 /app/src 目录。
  • 第三行:将 config.ini 复制到 /config/config.ini,并设置文件的所有者为 user:group

注意事项

  • 源路径必须在构建上下文中(即 docker build 指定的目录)。无法访问父目录(../)。
  • 如果目标路径不存在,Docker 会自动创建。
  • 如果目标路径以 / 结尾,表示目标是一个目录;否则,Docker 会根据源类型决定目标是文件还是目录。
  • COPY 不会解压文件(与 ADD 不同)。

3. RUN

功能

RUN 指令在构建镜像时执行指定的命令,并在镜像中创建新的层。常用于安装软件、更新系统或执行其他构建时需要的操作。

语法

RUN 有两种形式:

  1. Shell 形式(在 shell 中运行,默认为 /bin/sh -c):
   RUN <command>
  1. Exec 形式(直接执行命令,不通过 shell):
   RUN ["executable", "param1", "param2"]

用法

  • Shell 形式:适合简单的命令,运行时会启动一个 shell 环境。
  RUN apt-get update && apt-get install -y python3
  • 上述命令在 shell 中运行 apt-get updateapt-get install
  • Exec 形式:直接调用可执行文件,适合需要精确控制参数或避免 shell 开销的场景。
  RUN ["/bin/bash", "-c", "echo hello > /tmp/file"]
  • 直接调用 /bin/bash 执行命令。

示例

RUN apt-get update && apt-get install -y curl
RUN ["pip", "install", "--no-cache-dir", "requests"]
  • 第一行:在 shell 中更新包索引并安装 curl
  • 第二行:直接执行 pip install 安装 Python 的 requests 库。

注意事项

  • 每条 RUN 指令都会创建一个新的镜像层,建议将相关命令合并(如使用 &&)以减少层数。
  # 优化:合并命令
  RUN apt-get update && apt-get install -y curl && apt-get clean
  • Shell 形式会启动一个 shell 进程,可能增加开销,且信号处理(如 SIGTERM)可能不直接传递给命令。
  • Exec 形式不会启动 shell,信号处理更直接,但不支持 shell 的管道(|)或重定向(>)。
  • RUN 中执行的命令不会在容器运行时重复执行,仅在构建时运行。

4. ENV

功能

ENV 指令用于设置环境变量,这些变量在构建时和容器运行时都可用。环境变量可以被后续的 RUNCMDENTRYPOINT 指令使用。

语法

ENV <key>=<value> ...

用法

  • 可以设置单个或多个环境变量。
  • 环境变量在容器运行时可以通过 $key${key} 引用。
  • 支持多行设置或单行多个变量。

示例

ENV APP_HOME=/app
ENV PORT=8080 LOG_LEVEL=info
WORKDIR $APP_HOME
RUN echo "Port is $PORT"
  • 第一行:设置 APP_HOME 环境变量为 /app
  • 第二行:设置 PORTLOG_LEVEL 两个环境变量。
  • 第三行:WORKDIR 使用环境变量 $APP_HOME 切换目录。
  • 第四行:RUN 命令引用 $PORT

注意事项

  • 环境变量在构建时和运行时都有效,容器运行时可以通过 docker run -e 覆盖。
  • 使用 ENV 设置的变量优先级低于 docker run-e--env 参数。
  • 避免在 ENV 中存储敏感信息(如密码),建议使用 Docker Secrets 或运行时环境变量。
  • 支持 ${key:-default} 形式,提供默认值。

5. CMD

功能

CMD 指令指定容器启动时默认执行的命令。它定义了容器运行时的默认行为(仅在容器启动时执行)。一个 Dockerfile 中只能有一个有效的 CMD 指令(如果有多个,只有最后一个生效)。

语法

CMD 有三种形式:

  1. Exec 形式(推荐):
   CMD ["executable", "param1", "param2"]
  1. Shell 形式
   CMD command param1 param2
  1. 参数形式(为 ENTRYPOINT 提供默认参数):
   CMD ["param1", "param2"]

用法

  • Exec 形式:直接执行命令,推荐用于启动应用程序。
  CMD ["nginx", "-g", "daemon off;"]
  • 启动 Nginx 作为前台进程。
  • Shell 形式:在 shell 中运行命令,默认使用 /bin/sh -c
  CMD python app.py
  • 在 shell 中运行 python app.py
  • 参数形式:与 ENTRYPOINT 配合使用,提供默认参数。
  ENTRYPOINT ["/bin/echo"]
  CMD ["Hello", "World"]
  • 容器启动时执行 /bin/echo Hello World

示例

WORKDIR /app
COPY app.py .
CMD ["python", "app.py"]
  • 容器启动时在 /app 目录下执行 python app.py

注意事项

  • CMD 指定的命令可以在 docker run 时被覆盖。例如:
  docker run myimage bash
  • 会忽略 CMD 中的命令,改为运行 bash
  • Exec 形式:推荐使用,因为它直接运行命令,信号处理更可靠,且不启动额外的 shell 进程。
  • Shell 形式:会启动 shell,可能导致信号(如 SIGTERM)无法直接传递给进程,容器可能无法优雅退出。
  • 如果定义了 ENTRYPOINTCMD 会作为其参数;否则,CMD 提供默认的容器启动命令。
  • 如果没有 CMDENTRYPOINT,容器启动会失败。

总结与对比

指令功能执行时机语法形式注意事项
WORKDIR设置工作目录构建时和运行时WORKDIR /path使用绝对路径,避免多次切换导致混乱。
COPY复制文件/目录到镜像构建时COPY src dest源路径限于构建上下文,支持 --chown 设置权限。
RUN执行构建时的命令,生成镜像层构建时RUN commandRUN ["exec"]合并命令减少层数,Exec 形式更高效。
ENV设置环境变量构建时和运行时ENV key=value可被 docker run -e 覆盖,避免存储敏感信息。
CMD指定容器启动时的默认命令运行时CMD ["exec"]CMD command推荐 Exec 形式,可被 docker run 覆盖,与 ENTRYPOINT 配合使用更灵活。

综合示例

以下是一个完整的 Dockerfile 示例,展示这些指令的协同使用:

# 设置基础镜像
FROM python:3.9-slim

# 设置工作目录
WORKDIR /app

# 复制文件到镜像
COPY requirements.txt .
COPY app.py .

# 设置环境变量
ENV PORT=8000
ENV LOG_LEVEL=debug

# 安装依赖
RUN pip install --no-cache-dir -r requirements.txt

# 指定容器启动命令
CMD ["python", "app.py"]

说明

  • WORKDIR /app:设置工作目录为 /app
  • COPY:将 requirements.txtapp.py 复制到 /app
  • ENV:设置 PORTLOG_LEVEL 环境变量。
  • RUN:安装 Python 依赖。
  • CMD:容器启动时运行 python app.py

最佳实践

  1. WORKDIR:始终使用绝对路径,保持路径清晰。
  2. COPY:只复制必要的文件,使用 .dockerignore 排除无关文件。
  3. RUN:合并命令减少镜像层,使用 Exec 形式提高效率。
  4. ENV:合理使用环境变量,方便配置复用。
  5. CMD:优先使用 Exec 形式(["command", "arg1"]),确保信号处理正确。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注