Dockerfile 是用来定义 Docker 镜像构建过程的纯文本文件。通过一系列指令,Docker 可以自动读取并执行,最终生成一个可运行的镜像。下面是 完整、详细的 Dockerfile 核心指令与配置详解,包含语法、作用、示例、区别与最佳实践。

一、Dockerfile 基本结构
一个标准 Dockerfile 通常包含:
- 解析器指令(可选,开头)
- 基础镜像(FROM,必选)
- 元数据(LABEL、MAINTAINER)
- 环境变量(ENV、ARG)
- 文件操作(COPY、ADD)
- 构建时命令(RUN)
- 工作目录(WORKDIR)
- 用户(USER)
- 端口声明(EXPOSE)
- 数据卷(VOLUME)
- 健康检查(HEALTHCHECK)
- 启动命令(CMD、ENTRYPOINT)
二、核心指令详解(按常用顺序)
1. FROM ------ 基础镜像(必选)
作用 :指定构建新镜像所依赖的基础镜像(所有镜像都必须基于某个基础镜像)。
语法:
dockerfile
FROM <image>[:<tag>] [AS <name>] # 多阶段构建可用 AS
示例:
dockerfile
FROM ubuntu:22.04
FROM openjdk:17-jdk-slim
FROM scratch # 空镜像(用于构建最底层镜像)
要点:
- 必须是 第一个非注释指令(ARG 可在 FROM 前)。
- 标签尽量固定(如
22.04),不要用latest(不稳定)。 - 多阶段构建:
FROM ... AS builder可拆分构建与运行阶段,大幅减小镜像体积。
2. ARG ------ 构建参数(构建时有效)
作用 :定义构建过程中 可用的变量(容器运行时不存在)。
语法:
dockerfile
ARG <name>[=<default value>]
示例:
dockerfile
ARG NGINX_VERSION=1.25.3
FROM nginx:${NGINX_VERSION}
# 构建时覆盖:
# docker build --build-arg NGINX_VERSION=1.24.0 -t my-nginx .
与 ENV 区别:
- ARG:仅构建时有效,镜像/容器中不保留。
- ENV:构建与运行时都有效,会写入镜像。
3. LABEL ------ 元数据标签
作用 :给镜像添加键值对元数据(作者、版本、描述等)。
语法:
dockerfile
LABEL <key>=<value> <key>=<value> ...
示例:
dockerfile
LABEL maintainer="yourname@example.com"
LABEL version="1.0" description="Hadoop Base Image"
替代 :旧指令 MAINTAINER 已废弃,用 LABEL 代替。
4. ENV ------ 环境变量(永久生效)
作用 :设置环境变量(构建、运行、子进程都可用)。
语法:
dockerfile
ENV <key>=<value> ... # 推荐一行多个
ENV <key> <value> # 旧格式
示例:
dockerfile
ENV JAVA_HOME=/usr/lib/jvm/default-java \
HADOOP_HOME=/usr/local/hadoop \
PATH=$PATH:$HADOOP_HOME/bin
作用:
- 简化后续指令路径
- 容器运行时可直接使用
- 可被
docker run -e key=val覆盖
5. WORKDIR ------ 工作目录
作用 :设置后续 RUN/CMD/ENTRYPOINT/COPY/ADD 的工作目录(自动创建)。
语法:
dockerfile
WORKDIR <path>
示例:
dockerfile
WORKDIR /usr/local/hadoop
RUN pwd # 输出 /usr/local/hadoop
最佳实践:
- 用绝对路径
- 不要多次
RUN cd /path,用 WORKDIR 代替 - 推荐:
/app、/usr/src/app
6. COPY ------ 复制文件(推荐)
作用 :从 构建上下文(宿主机) 复制文件/目录到镜像内。
语法:
dockerfile
COPY <src> <dest>
COPY ["<src>", "<dest>"] # 路径含空格用此格式
示例:
dockerfile
COPY hadoop-config /usr/local/hadoop/etc/hadoop
COPY target/app.jar /app/
特点:
- 仅本地文件,不支持 URL、不解压
- 透明、可缓存、安全(推荐优先用 COPY)
7. ADD ------ 增强复制(慎用)
作用:类似 COPY,但额外支持:
- 自动解压 本地 tar.gz 到目标目录
- 从 URL 下载文件到目标(不推荐)
语法:
dockerfile
ADD <src> <dest>
示例:
dockerfile
ADD apache-hive-3.1.3-bin.tar.gz /usr/local/ # 自动解压
ADD https://example.com/file.txt /tmp/ # 下载(不推荐)
注意:
- 会破坏缓存、增加镜像体积
- 仅需解压时用 ADD,其他一律用 COPY
8. RUN ------ 构建时执行命令(核心)
作用 :在构建镜像阶段 执行命令(安装软件、配置、编译等)。
两种格式:
(1)Shell 格式(常用)
dockerfile
RUN apt update && apt install -y vim
- 会用
/bin/sh -c执行 - 支持管道、变量
(2)Exec 格式(推荐)
dockerfile
RUN ["apt", "update"]
- 不启动 shell,信号传递更好
- 无环境变量解析
最佳实践(非常重要):
- 合并多个 RUN(减少镜像层数)
dockerfile
RUN apt update && \
apt install -y openjdk-11-jdk ssh && \
apt clean && \
rm -rf /var/lib/apt/lists/* # 清理缓存,减小体积
- 每一层尽量清理临时文件、缓存
9. EXPOSE ------ 声明端口
作用 :声明 容器运行时监听的端口(仅文档作用,不会自动映射 )。
语法:
dockerfile
EXPOSE <port>[/<protocol>]
EXPOSE 80 443/tcp 9000
要点:
- 只是声明,实际暴露需
docker run -p 主机端口:容器端口 - 帮助使用者了解端口用途
10. VOLUME ------ 匿名数据卷
作用 :声明容器内的匿名挂载点 ,用于持久化、防止数据丢失。
语法:
dockerfile
VOLUME ["/path1", "/path2"]
VOLUME /usr/local/hadoop/namenode_dir
效果:
- 运行时自动创建匿名卷
- 容器删除后,卷数据保留
- 可被
docker run -v 主机路径:容器路径覆盖
11. USER ------ 指定运行用户
作用 :指定后续 RUN/CMD/ENTRYPOINT 执行的用户(默认 root)。
语法:
dockerfile
USER <user>[:<group>]
USER uid[:gid]
示例:
dockerfile
RUN groupadd -r hadoop && useradd -r -g hadoop hadoop
USER hadoop
安全意义:
- 避免以 root 运行,降低容器逃逸风险
12. CMD ------ 容器默认启动命令(可被覆盖)
作用 :指定 容器启动时默认执行的命令 ,可被 docker run 后面的命令覆盖。
三种格式:
dockerfile
# 1. Exec 格式(推荐,信号正常传递)
CMD ["executable","param1","param2"]
# 2. Shell 格式
CMD command param1 param2
# 3. 给 ENTRYPOINT 传参
CMD ["param1","param2"]
示例:
dockerfile
CMD ["hadoop", "namenode", "-foreground"]
规则:
- 一个 Dockerfile 只能有一个 CMD(最后一个生效)
- 被
docker run 镜像名 命令覆盖
13. ENTRYPOINT ------ 容器入口点(不易覆盖)
作用 :指定容器真正入口程序 ,通常不希望被覆盖。
两种格式:
dockerfile
# 1. Exec 格式(推荐)
ENTRYPOINT ["executable", "param1"]
# 2. Shell 格式(不推荐,信号丢失)
ENTRYPOINT command param1
与 CMD 组合(经典用法):
dockerfile
ENTRYPOINT ["hadoop"]
CMD ["namenode", "-foreground"]
# 效果:
# docker run my-hadoop → hadoop namenode -foreground
# docker run my-hadoop datanode → hadoop datanode
区别总结:
| 指令 | 覆盖性 | 用途 |
|---|---|---|
| CMD | 易被覆盖 | 默认参数/命令 |
| ENTRYPOINT | 不易覆盖(需 --entrypoint) | 固定主程序 |
14. HEALTHCHECK ------ 健康检查
作用 :定义如何检查容器是否正常运行。
语法:
dockerfile
HEALTHCHECK [选项] CMD <命令>
选项:
--interval=5s:检查间隔--timeout=3s:超时--retries=3:重试次数
示例:
dockerfile
HEALTHCHECK --interval=10s --timeout=3s \
CMD curl -f http://localhost:9870/ || exit 1
15. ONBUILD ------ 子镜像触发指令
作用 :当前镜像作为基础镜像 被其他 Dockerfile 使用时,才执行的指令。
示例:
dockerfile
ONBUILD COPY . /app
ONBUILD RUN mvn install
三、COPY vs ADD 对比(必懂)
| 特性 | COPY | ADD |
|---|---|---|
| 本地文件 | ✅ | ✅ |
| 自动解压 tar | ❌ | ✅ |
| 支持 URL | ❌ | ✅(不推荐) |
| 构建缓存 | 好 | 差 |
| 安全性 | 高 | 中 |
| 推荐场景 | 绝大多数复制 | 仅需解压 |
四、CMD vs ENTRYPOINT 对比(必懂)
- 单独使用 CMD:可被完全覆盖 → 适合默认命令
- 单独使用 ENTRYPOINT:不易覆盖 → 适合固定主程序
- ENTRYPOINT + CMD :
- ENTRYPOINT = 主程序
- CMD = 默认参数
docker run后面参数会替换 CMD → 最灵活
五、多阶段构建(关键优化)
作用 :把「构建环境」和「运行环境」分离,极大减小最终镜像体积 。
示例(Java 项目):
dockerfile
# 阶段1:构建(含 Maven/JDK,体积大)
FROM maven:3.8-openjdk-11 AS builder
WORKDIR /app
COPY . .
RUN mvn clean package -DskipTests
# 阶段2:运行(仅 JRE,体积小)
FROM openjdk:11-jre-slim
WORKDIR /app
# 从上一阶段复制 jar
COPY --from=builder /app/target/*.jar app.jar
ENTRYPOINT ["java", "-jar", "app.jar"]
六、Dockerfile 最佳实践(避坑)
- 使用官方最小基础镜像(alpine > slim > 普通)
- 合并 RUN 指令,减少层数
- 安装后立即清理缓存(apt clean、yum clean、rm -rf /var/lib/apt/lists/*)
- 优先用 COPY,少用 ADD
- 用 WORKDIR 代替 RUN cd
- 非必要不 root,使用 USER 切换普通用户
- EXPOSE 声明端口,便于使用
- VOLUME 声明持久化目录
- CMD/ENTRYPOINT 用 Exec 格式(信号正常)
- 多阶段构建减小镜像
- 标签固定版本,不用 latest
- 一行一个 ENV,减少层数
七、完整示例(Hadoop Base)
dockerfile
# syntax=docker/dockerfile:1
FROM ubuntu:22.04
LABEL maintainer="admin@example.com"
LABEL version="3.3.4"
LABEL description="Hadoop Base Image"
ENV DEBIAN_FRONTEND=noninteractive
ENV JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64
ENV HADOOP_VERSION=3.3.4
ENV HADOOP_HOME=/usr/local/hadoop
ENV PATH=$PATH:$HADOOP_HOME/bin:$HADOOP_HOME/sbin
# 安装依赖
RUN apt update && \
apt install -y openjdk-11-jdk-headless ssh pdsh && \
apt clean && \
rm -rf /var/lib/apt/lists/*
# 安装 Hadoop
ADD hadoop-${HADOOP_VERSION}.tar.gz /usr/local/
RUN ln -s /usr/local/hadoop-${HADOOP_VERSION} $HADOOP_HOME
# 复制配置
WORKDIR $HADOOP_HOME
COPY hadoop-config etc/hadoop/
# 端口
EXPOSE 9000 9870 8088
# 数据卷
VOLUME ["$HADOOP_HOME/namenode_dir", "$HADOOP_HOME/datanode_dir"]
# 启动脚本
COPY entrypoint.sh /
RUN chmod +x /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]
CMD ["bash"]
八、构建与运行
bash
# 构建
docker build -t hadoop-base .
# 运行
docker run -itd --name master hadoop-base
如果你需要,我可以根据你 已有的 Hadoop Docker 环境 ,直接给你写一个 可直接使用的 Hive Dockerfile + 构建运行脚本,适配你的集群。需要吗?