概述
Dockerfile 是 Docker 镜像的构建蓝图。写好 Dockerfile,镜像体积更小、构建更快、运行更安全。本文将 13 个核心指令按功能分类,逐一讲解用法和最佳实践,适合作为速查手册。
13 个指令分为四大类:

分类指令

基础镜像信息FROM
维护者信息LABEL(原 MAINTAINER)
镜像构建操作RUN、COPY、ADD、EXPOSE、WORKDIR、ONBUILD、USER、VOLUME、ENV
容器启动执行CMD、ENTRYPOINT

  1. FROM:指定基础镜像
    必须是 Dockerfile 第一个非注释行,指定后续指令基于哪个镜像构建。
    FROM openjdk:8-jdk-alpine

建议优先使用官方镜像和特定版本 Tag,避免使用 latest。

  1. LABEL:镜像元数据(替代 MAINTAINER)
    旧版用 MAINTAINER 指定作者,现已废弃,推荐使用 LABEL:
    LABEL org.opencontainers.image.authors=“your-name your-email@gmail.com”

LABEL 还可以添加版本、描述等其他元数据:
LABEL version=“1.0” description=“My application”

  1. RUN:执行命令
    构建镜像时运行命令,每一条 RUN 都会创建一层镜像。尽量用 && 把多条命令合并,减少镜像层数:
    RUN apk add --no-cache tzdata && ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone

  2. COPY:复制文件
    将文件从宿主机(构建上下文)复制到镜像内。源文件需和 Dockerfile 在同目录或相对路径。
    COPY update.json /usr/local/nginx/share/html/

支持通配符:
COPY *.jar /app/

一般优先使用 COPY,ADD 只在需要自动解压时使用。

  1. CMD:容器启动命令
    容器启动时默认执行的命令。如果 Dockerfile 中有多个 CMD,只有最后一个生效。docker run 指定的命令会覆盖 CMD。
    推荐使用 exec 格式:
    CMD [“nginx”, “-g”, “daemon off;”]

  2. EXPOSE:声明端口
    声明容器打算暴露哪个端口。这只是声明,并不会自动在宿主机打开端口。运行时需要用 -p 映射:
    EXPOSE 8080

docker run -p 8080:80 my-image

  1. WORKDIR:配置工作目录
    指定容器启动后默认所在目录。目录不存在会自动创建。
    WORKDIR /usr/local/nginx/share/html/

后续的 RUN、CMD、ENTRYPOINT 指令都会在这个目录下执行。

  1. ENTRYPOINT:容器启动入口命令
    ENTRYPOINT 和 CMD 语法类似,关键区别:

CMD 的命令会被 docker run 的参数覆盖,而 ENTRYPOINT 不会
如果两者同时存在,CMD 的内容会变成 ENTRYPOINT 的默认参数

ENTRYPOINT [“java”, “-Djava.security.egd=file:/dev/./urandom”, “-jar”, “/app.jar”, “–spring.profiles.active=test”]

典型用法:ENTRYPOINT 指定固定入口程序,CMD 指定可变参数。

  1. VOLUME:挂载卷
    指定容器内的路径会被自动挂载为匿名卷,防止数据写入容器存储层。
    VOLUME /tmp

启动容器时可以手动挂载到宿主机目录:
docker run -v /host/path:/container/path my-image

  1. USER:指定用户
    指定后续 RUN、CMD、ENTRYPOINT 指令使用什么用户运行。出于安全考虑,不建议以 root 用户运行:
    USER daemon

  2. ADD:添加文件
    用法和 COPY 基本相同,但 ADD 额外支持:

自动解压压缩文件(.tar、.gz、.bz2 等)
从 URL 下载文件

ADD nginx-1.15.8.tar.gz /usr/src/

推荐:能用 COPY 就用 COPY,只在需要自动解压时用 ADD。

  1. ONBUILD:延迟构建指令
    当本镜像作为其他镜像的基础镜像时,ONBUILD 指定的指令才会执行。适用于构建基础镜像或 SDK 镜像。
    ONBUILD COPY . /app
    ONBUILD RUN cd /app && make

  2. ENV:设置环境变量
    设置环境变量,在后续所有 Dockerfile 指令中都可以使用,并且会保留到运行的容器中。
    ENV TZ=Asia/Shanghai
    ENV JAVA_HOME=/opt/jdk
    ENV PATH= P A T H : PATH: PATH:JAVA_HOME/bin

ENV 具有传递性——当前镜像被用作基础镜像时,新镜像会继承所有环境变量。

完整示例:编译安装 Nginx
FROM centos
LABEL org.opencontainers.image.authors=“your-name your-email@gmail.com”

安装依赖

RUN yum -y install gcc make pcre-devel zlib-devel tar zlib

复制源码包

ADD nginx-1.15.8.tar.gz /usr/src/

编译安装

RUN cd /usr/src/nginx-1.15.8 && mkdir /usr/local/nginx && ./configure --prefix=/usr/local/nginx && make && make install && ln -s /usr/local/nginx/sbin/nginx /usr/local/sbin/

清理源码

RUN rm -rf /usr/src/nginx-1.15.8
EXPOSE 80
CMD [“nginx”, “-g”, “daemon off;”]

构建与常用参数
docker build -t nginx:v1.0 .

参数说明

–build-arg=[]设置镜像创建时的变量
-f指定要使用的 Dockerfile 路径
–force-rm构建过程中删除中间容器
–rm构建成功后删除中间容器
-t, --tag镜像的名字及标签,格式 name:tag

几点最佳实践

减少层数:用 && 合并 RUN 命令,减少镜像层
优先 COPY 而非 ADD:COPY 更透明,ADD 只在需要自动解压时用
使用 .dockerignore:排除不需要的文件,缩小构建上下文
指定版本号:FROM 和依赖安装都指定明确版本,避免 latest
不以 root 运行:用 USER 切换到非 root 用户
清理临时文件:在同一个 RUN 中安装、清理,避免垃圾留在镜像层

更多推荐