DockerFile
Dockerfile 详解:镜像构建的 “说明书”
Dockerfile 是一个文本文件,包含一系列构建镜像的指令,通过 docker build 命令可自动执行这些指令生成自定义镜像。它就像镜像的 “施工蓝图”,明确了从基础镜像到最终镜像的每一步操作,实现了镜像构建的自动化和可复用性。
Dockerfile 基本结构
Dockerfile 由指令(Instruction) 和注释组成,指令格式为:INSTRUCTION arguments(指令大写,参数小写,惯例)。
核心指令包括:FROM、RUN、CMD、COPY、ADD 等,下文将详细解析。
核心指令详解
1. FROM:指定基础镜像
作用:声明构建镜像的基础镜像(所有镜像都需基于某个基础镜像构建)。
位置:必须是 Dockerfile 的第一条指令。
示例:
# 使用官方centos镜像的latest版本作为基础 FROM centos:latest # 使用多阶段构建时,可多次使用FROM(如构建阶段和运行阶段) FROM maven:3.8 AS builder # 构建阶段 FROM openjdk:8-jre # 运行阶段
2. MAINTAINER:指定镜像作者(已过时,推荐用 LABEL)
作用:标注镜像的作者信息(姓名、邮箱等)。
示例:
MAINTAINER "张三 <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 解析问题)。
示例:
# 安装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使用,作为参数)。
示例:
# 启动nginx(exec格式) CMD ["nginx", "-g", "daemon off;"] # 若启动时执行 docker run mynginx /bin/bash,则CMD被覆盖,进入bash终端
5. ENTRYPOINT:设置容器入口程序
作用:与
CMD类似,但不会被启动命令覆盖,仅可通过--entrypoint参数修改。场景:用于固定容器的主程序(如
java -jar启动 Java 应用)。示例:
# 固定入口为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 文件。 |
需要解压或下载文件时 |
示例:
# 复制宿主机的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命令)。特点:若目录不存在,会自动创建;可多次使用,切换不同目录。
示例:
WORKDIR /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>(多变量)。
示例:
# 设置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实现。示例:
# 声明暴露80和443端口 EXPOSE 80 443
10. VOLUME:定义数据卷
作用:指定容器中的目录作为数据卷(持久化存储,与宿主机目录关联)。
特点:运行容器时,若未指定宿主机目录,Docker 会自动创建匿名卷。
示例:
# 将容器的/logs目录定义为数据卷 VOLUME ["/logs"] # 运行时映射:docker run -v /host/logs:/logs myimage
Dockerfile 示例:构建 Java 应用镜像
# 基础镜像:OpenJDK 8
FROM openjdk:8-jre-alpine
# 元数据
LABEL maintainer="dev@example.com"
LABEL version="1.0"
# 设置工作目录
WORKDIR /app
# 复制宿主机的app.jar到容器
COPY target/app.jar /app/app.jar
# 暴露端口
EXPOSE 8080
# 启动命令:java -jar app.jar
ENTRYPOINT ["java", "-jar"]
CMD ["app.jar"]
构建镜像命令
-t 指定镜像名和标签,. 表示Dockerfile在当前目录
docker build -t my-java-app:1.0 .
Dockerfile 最佳实践
精简镜像层数:合并
RUN命令(用&&和\换行),减少镜像大小。# 推荐 RUN yum update -y && \ yum install -y nginx && \ yum clean all # 清理缓存,减小镜像体积使用
.dockerignore文件:排除不需要复制到镜像的文件(如node_modules、.git),减少上下文传输时间。优先选择轻量基础镜像:如
alpine版本(体积小,适合生产环境),避免使用ubuntu等重量级镜像。多阶段构建:分离构建阶段和运行阶段,仅保留运行所需文件(如 Java 应用仅保留
jar包,不包含源码和编译工具)。# 构建阶段(使用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 用户并切换,增强安全性。RUN adduser -D appuser USER appuser # 后续命令以appuser执行
总结
Dockerfile 通过指令定义了镜像的构建流程,是 Docker 生态中 “基础设施即代码” 的核心体现。掌握 FROM、RUN、CMD、COPY 等核心指令的用法,结合最佳实践(如精简层数、多阶段构建),可构建出高效、安全、可维护的镜像