Dockerfile 详解:镜像构建的 “说明书”
Dockerfile 是一个文本文件,包含一系列构建镜像的指令,通过 docker build
命令可自动执行这些指令生成自定义镜像。它就像镜像的 “施工蓝图”,明确了从基础镜像到最终镜像的每一步操作,实现了镜像构建的自动化和可复用性。
Dockerfile 基本结构
Dockerfile 由指令(Instruction) 和注释组成,指令格式为:INSTRUCTION arguments
(指令大写,参数小写,惯例)。
核心指令包括:FROM
、RUN
、CMD
、COPY
、ADD
等,下文将详细解析。
核心指令详解
1. FROM
:指定基础镜像
作用:声明构建镜像的基础镜像(所有镜像都需基于某个基础镜像构建)。
位置:必须是 Dockerfile 的第一条指令。
示例:
1
2
3
4
5
6# 使用官方centos镜像的latest版本作为基础
FROM centos:latest
# 使用多阶段构建时,可多次使用FROM(如构建阶段和运行阶段)
FROM maven:3.8 AS builder # 构建阶段
FROM openjdk:8-jre # 运行阶段
2. MAINTAINER
:指定镜像作者(已过时,推荐用 LABEL
)
作用:标注镜像的作者信息(姓名、邮箱等)。
示例:
1
2
3
4
5
6MAINTAINER "张三 <zhangsan@example.com>"
# 推荐使用LABEL(更灵活,可添加多个元数据)
LABEL maintainer="张三 <zhangsan@example.com>"
LABEL version="1.0"
LABEL description="自定义Java应用镜像"
3. RUN
:执行构建时命令
作用:在构建镜像过程中(容器内)执行命令,常用于安装软件、配置环境等。
格式:
RUN <command>
(shell 格式,默认使用/bin/sh -c
执行);RUN ["executable", "param1", "param2"]
(exec 格式,推荐,避免 shell 解析问题)。
示例:
1
2
3
4
5# 安装nginx(shell格式)
RUN yum install -y nginx && yum clean all
# 创建目录(exec格式)
RUN ["mkdir", "-p", "/app/logs"]注意:每条
RUN
指令会创建一个新的镜像层,建议合并命令(用&&
连接)减少层数。
4. CMD
:指定容器启动时命令
作用:定义容器启动后默认执行的命令。
特点:
- 一个 Dockerfile 中只能有一条有效的
CMD
指令,多则仅最后一条生效; - 启动容器时,若指定了命令(如
docker run <镜像> <命令>
),会覆盖CMD
指令。
- 一个 Dockerfile 中只能有一条有效的
格式:
CMD <command>
(shell 格式);CMD ["executable", "param1", "param2"]
(exec 格式,推荐);CMD ["param1", "param2"]
(配合ENTRYPOINT
使用,作为参数)。
示例:
1
2
3
4# 启动nginx(exec格式)
CMD ["nginx", "-g", "daemon off;"]
# 若启动时执行 docker run mynginx /bin/bash,则CMD被覆盖,进入bash终端
5. ENTRYPOINT
:设置容器入口程序
作用:与
CMD
类似,但不会被启动命令覆盖,仅可通过--entrypoint
参数修改。场景:用于固定容器的主程序(如
java -jar
启动 Java 应用)。示例:
1
2
3
4
5# 固定入口为java命令,CMD作为参数
ENTRYPOINT ["java", "-jar"]
CMD ["app.jar"] # 启动时默认执行 java -jar app.jar
# 启动时可修改参数:docker run myapp demo.jar → 执行 java -jar demo.jar
6. COPY
与 ADD
:复制文件到容器
- 作用:将宿主机文件 / 目录复制到镜像的指定路径。
指令 | 功能 | 推荐场景 |
---|---|---|
COPY |
仅复制文件 / 目录,支持通配符。 | 普通文件复制(明确、无副作用) |
ADD |
除复制外,还支持自动解压压缩包(如 .tar 、.gz )和下载 URL 文件。 |
需要解压或下载文件时 |
示例:
1
2
3
4
5
6
7
8# 复制宿主机的app.jar到容器的/app目录
COPY app.jar /app/
# 复制并自动解压jre压缩包到/opt目录
ADD jre-8u311-linux-x64.tar.gz /opt/
# 下载URL文件(不推荐,建议用RUN wget替代,更可控)
ADD https://example.com/config.ini /app/config/注意:源路径为相对路径(相对于 Dockerfile 所在目录),目标路径需为绝对路径。
7. WORKDIR
:设置工作目录
作用:指定后续
RUN
、CMD
、ENTRYPOINT
等指令的工作目录(类似cd
命令)。特点:若目录不存在,会自动创建;可多次使用,切换不同目录。
示例:
1
2
3
4WORKDIR /app # 切换到/app目录
RUN pwd # 输出 /app
WORKDIR ./logs # 切换到/app/logs目录
CMD ["touch", "app.log"] # 在/app/logs创建app.log
8. ENV
:设置环境变量
作用:定义环境变量,在构建阶段和容器运行阶段均有效。
格式:
ENV <key> <value>
(单变量);ENV <key1>=<value1> <key2>=<value2>
(多变量)。
示例:
1
2
3
4
5
6# 设置Java环境变量
ENV JAVA_HOME /opt/jre1.8.0_311
ENV PATH $JAVA_HOME/bin:$PATH # 拼接PATH
# 多变量定义
ENV APP_NAME=myapp VERSION=1.0
9. EXPOSE
:声明暴露端口
作用:声明容器运行时对外暴露的端口(仅为文档说明,不自动映射)。
场景:提示使用者该镜像需要映射哪些端口,实际映射需通过
docker run -p
实现。示例:
1
2# 声明暴露80和443端口
EXPOSE 80 443
10. VOLUME
:定义数据卷
作用:指定容器中的目录作为数据卷(持久化存储,与宿主机目录关联)。
特点:运行容器时,若未指定宿主机目录,Docker 会自动创建匿名卷。
示例:
1
2
3
4# 将容器的/logs目录定义为数据卷
VOLUME ["/logs"]
# 运行时映射:docker run -v /host/logs:/logs myimage
Dockerfile 示例:构建 Java 应用镜像
1 | # 基础镜像:OpenJDK 8 |
构建镜像命令
1 | -t 指定镜像名和标签,. 表示Dockerfile在当前目录 |
Dockerfile 最佳实践
精简镜像层数:合并
RUN
命令(用&&
和\
换行),减少镜像大小。1
2
3
4# 推荐
RUN yum update -y && \
yum install -y nginx && \
yum clean all # 清理缓存,减小镜像体积使用
.dockerignore
文件:排除不需要复制到镜像的文件(如node_modules
、.git
),减少上下文传输时间。优先选择轻量基础镜像:如
alpine
版本(体积小,适合生产环境),避免使用ubuntu
等重量级镜像。多阶段构建:分离构建阶段和运行阶段,仅保留运行所需文件(如 Java 应用仅保留
jar
包,不包含源码和编译工具)。1
2
3
4
5
6
7
8
9
10
11
12# 构建阶段(使用maven)
FROM maven:3.8 AS builder
WORKDIR /app
COPY pom.xml .
COPY src ./src
RUN mvn package -DskipTests
# 运行阶段(使用轻量JRE)
FROM openjdk:8-jre-alpine
COPY --from=builder /app/target/app.jar /app/
EXPOSE 8080
CMD ["java", "-jar", "/app/app.jar"]避免使用
root
用户:在镜像中创建非 root 用户并切换,增强安全性。1
2RUN adduser -D appuser
USER appuser # 后续命令以appuser执行
总结
Dockerfile 通过指令定义了镜像的构建流程,是 Docker 生态中 “基础设施即代码” 的核心体现。掌握 FROM
、RUN
、CMD
、COPY
等核心指令的用法,结合最佳实践(如精简层数、多阶段构建),可构建出高效、安全、可维护的镜像
v1.3.10