Appearance
Dockerfile 指令详解
本节详细介绍 Dockerfile 中所有指令的语法、参数和使用场景。
指令总览
| 指令 | 说明 |
|---|---|
FROM | 指定基础镜像 |
LABEL | 添加元数据标签 |
ENV | 设置环境变量 |
ARG | 构建参数 |
WORKDIR | 设置工作目录 |
COPY | 复制文件或目录 |
ADD | 添加文件(支持 URL 和解压) |
RUN | 执行命令 |
CMD | 容器启动命令(可被覆盖) |
ENTRYPOINT | 容器入口点(不可被覆盖) |
EXPOSE | 声明端口 |
VOLUME | 声明匿名数据卷 |
USER | 切换运行用户 |
HEALTHCHECK | 健康检查 |
STOPSIGNAL | 停止信号 |
ONBUILD | 子镜像构建触发器 |
SHELL | 修改默认 Shell |
FROM
dockerfile
FROM <镜像>[:<标签>] [AS <名称>]
# 示例
FROM ubuntu:22.04
FROM node:20-alpine AS builder
FROM scratch- 每个 Dockerfile 必须有一条
FROM指令 - 多个
FROM表示多阶段构建 FROM scratch创建空白镜像,适用于静态二进制
LABEL
为镜像添加元数据,便于管理和检索:
dockerfile
LABEL version="1.0"
LABEL maintainer="name@example.com"
LABEL description="My application"
# 推荐:一条 LABEL 声明所有标签
LABEL version="1.0" \
maintainer="name@example.com" \
description="My application" \
org.opencontainers.image.created="2024-01-01"bash
# 查看镜像标签
docker inspect myimage --format '{{json .Config.Labels}}'
# 按标签过滤镜像
docker images --filter label=version=1.0ENV
dockerfile
ENV <key>=<value> ...
# 示例
ENV NODE_ENV=production
ENV PORT=3000 HOST=0.0.0.0
# 可以在后续指令中引用
ENV APP_HOME=/app
WORKDIR $APP_HOME- 在构建阶段和容器运行时都有效
- 可以在
docker run时通过-e覆盖
ARG
dockerfile
ARG <name>[=<默认值>]
# 示例
ARG NODE_VERSION=20
ARG BUILD_DATE
ARG GIT_COMMIT
FROM node:${NODE_VERSION}-alpine
# 使用 ARG
RUN echo "Build date: ${BUILD_DATE}"- 只在构建阶段有效,不会保留到最终镜像
- 可以通过
docker build --build-arg key=value传入
bash
docker build \
--build-arg NODE_VERSION=18 \
--build-arg BUILD_DATE=$(date -u +%Y-%m-%d) \
-t myapp .ARG 与 ENV 的区别:
| 特性 | ARG | ENV |
|---|---|---|
| 作用范围 | 构建时 | 构建时 + 运行时 |
| 是否保留到镜像 | 否 | 是 |
| 是否可通过环境变量覆盖 | --build-arg | -e |
WORKDIR
dockerfile
WORKDIR <目录路径>
# 示例
WORKDIR /app
WORKDIR /app/src # 绝对路径
# 相对路径(相对于上一个 WORKDIR)
WORKDIR /a
WORKDIR b # /a/b
WORKDIR c # /a/b/c- 目录不存在时自动创建
- 影响后续的
RUN、CMD、COPY、ADD指令 - 推荐使用绝对路径
COPY
dockerfile
COPY [--chown=<user>:<group>] [--chmod=<权限>] <源路径> <目标路径>
# 示例
COPY app.js .
COPY package*.json ./
COPY src/ ./src/
COPY . . # 复制所有文件(配合 .dockerignore 使用)
# 设置文件所有者
COPY --chown=node:node . .
# 设置文件权限
COPY --chmod=755 scripts/entrypoint.sh /entrypoint.sh
# 从其他构建阶段复制(多阶段构建)
COPY --from=builder /app/dist ./distADD
dockerfile
ADD [--chown=<user>:<group>] <源路径> <目标路径>
# 自动解压 tar 文件
ADD source.tar.gz /app/
# 从 URL 下载(不推荐,推荐用 RUN curl)
ADD https://example.com/file.txt /app/
# 从其他阶段复制
ADD --from=builder /app/dist ./推荐使用 COPY,只在需要自动解压时使用
ADD。URL 下载推荐用RUN curl代替。
RUN
dockerfile
# shell 格式(默认 /bin/sh -c)
RUN <命令>
# exec 格式(推荐)
RUN ["executable", "param1", "param2"]
# 示例
RUN apt-get update && apt-get install -y curl
RUN ["apt-get", "install", "-y", "vim"]
# 多命令合并(减少层数,利用缓存)
RUN apt-get update \
&& apt-get install -y \
curl \
vim \
git \
&& rm -rf /var/lib/apt/lists/*RUN 的最佳实践:
- 多条安装命令合并成一条
RUN(减少镜像层数) - 安装后清理缓存(
apt-get clean/rm -rf /var/lib/apt/lists/*) - 合理利用构建缓存
CMD
dockerfile
# exec 格式(推荐)
CMD ["executable", "param1", "param2"]
# shell 格式
CMD command param1 param2
# 作为 ENTRYPOINT 的参数
CMD ["param1", "param2"]
# 示例
CMD ["nginx", "-g", "daemon off;"]
CMD ["node", "app.js"]
CMD ["python", "-m", "flask", "run"]- 每个 Dockerfile 只有最后一条
CMD有效 - 可以被
docker run的命令参数覆盖
ENTRYPOINT
dockerfile
# exec 格式(推荐)
ENTRYPOINT ["executable", "param1", "param2"]
# shell 格式(不推荐,会忽略 CMD 和 docker run 的参数)
ENTRYPOINT command param1 param2
# 示例:将容器作为命令工具
ENTRYPOINT ["curl"]
CMD ["--help"]
# docker run myimage → curl --help
# docker run myimage -v → curl -v与 CMD 组合使用:
dockerfile
ENTRYPOINT ["node"]
CMD ["app.js"]
# 默认执行:node app.js
# docker run myimage other.js → 执行:node other.jsEXPOSE
dockerfile
EXPOSE <端口> [<端口>/<协议> ...]
# 示例
EXPOSE 80
EXPOSE 443
EXPOSE 3000/tcp
EXPOSE 5353/udp- 仅是文档说明,不会自动进行端口映射
- 需要配合
docker run -p或-P才能实际映射
VOLUME
dockerfile
VOLUME ["/数据目录"]
VOLUME /var/log /var/db
# 示例
VOLUME ["/var/lib/mysql"]
VOLUME /uploads- 声明匿名数据卷挂载点
- 容器创建时 Docker 会自动创建匿名卷
- 主要用于文档化,提示用户这些目录需要持久化
USER
dockerfile
USER <user>[:<group>]
USER <UID>[:<GID>]
# 示例:切换到非 root 用户(安全最佳实践)
RUN addgroup --system appgroup \
&& adduser --system --group appuser
USER appuser- 影响后续的
RUN、CMD、ENTRYPOINT指令 - 安全最佳实践:不要以 root 用户运行应用
HEALTHCHECK
dockerfile
HEALTHCHECK [选项] CMD <命令>
HEALTHCHECK NONE # 禁用基础镜像的健康检查
# 选项
# --interval=30s 检查间隔(默认 30s)
# --timeout=30s 超时时间(默认 30s)
# --start-period=0s 容器启动后多久开始检查
# --retries=3 失败次数(超过则标记为 unhealthy)
# 示例
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
CMD curl -f http://localhost/health || exit 1
HEALTHCHECK --interval=5s --timeout=3s \
CMD wget -qO- http://localhost:3000/health || exit 1STOPSIGNAL
dockerfile
STOPSIGNAL <信号>
# 示例
STOPSIGNAL SIGTERM # 默认
STOPSIGNAL SIGQUIT # Nginx 使用此信号优雅退出
STOPSIGNAL 9 # SIGKILLONBUILD
dockerfile
ONBUILD <其他 Dockerfile 指令>
# 示例:创建基础镜像,子镜像构建时自动执行
ONBUILD COPY . /app
ONBUILD RUN npm install- 只在作为其他镜像的基础镜像时触发
- 适用于创建通用基础镜像
SHELL
dockerfile
SHELL ["executable", "parameters"]
# 示例:修改默认 shell
SHELL ["/bin/bash", "-c"]
SHELL ["powershell", "-command"] # Windows
# 修改后影响后续的 RUN、CMD、ENTRYPOINT(shell 格式)
SHELL ["/bin/bash", "-c"]
RUN echo "using bash"综合示例
dockerfile
# ==== 多阶段构建:生产级 Node.js 应用 ====
# 构建阶段
FROM node:20-alpine AS builder
WORKDIR /build
COPY package*.json ./
RUN npm ci --only=production
COPY . .
RUN npm run build
# 运行阶段
FROM node:20-alpine AS runtime
LABEL version="1.0" \
maintainer="team@example.com"
ENV NODE_ENV=production \
PORT=3000
# 创建非 root 用户
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
WORKDIR /app
# 从构建阶段复制结果
COPY --from=builder --chown=appuser:appgroup /build/dist ./dist
COPY --from=builder --chown=appuser:appgroup /build/node_modules ./node_modules
COPY --chown=appuser:appgroup package.json .
# 切换用户
USER appuser
EXPOSE 3000
HEALTHCHECK --interval=30s --timeout=10s --start-period=10s --retries=3 \
CMD wget -qO- http://localhost:3000/health || exit 1
CMD ["node", "dist/app.js"]总结
熟练掌握 Dockerfile 指令是构建高质量镜像的基础。关键要点:
- 合并
RUN指令减少层数 - 使用
.dockerignore排除无关文件 - 利用
COPY分离依赖安装和代码复制以提升缓存效率 - 使用
USER切换非 root 用户提升安全性 - 添加
HEALTHCHECK使容器状态可观测
下一节介绍多阶段构建来进一步优化镜像大小。