Dockerfile基础
一、Dockerfile 指令核心分类
Dockerfile 是构建 Docker 镜像的文本文件,指令按功能可分为 7 大核心模块,涵盖基础镜像选择、构建参数配置、文件操作、环境配置、运行命令、容器启动设置等全流程,所有指令大小写不敏感,但惯例使用大写以区分参数。
二、基础镜像与构建阶段模块
该模块指令用于指定构建的基础镜像、构建阶段划分及跨平台适配,是镜像构建的起点。
| 指令 | 说明 |
|---|---|
FROM |
必选指令,指定构建的基础镜像(格式:镜像名:标签),所有后续指令基于该镜像执行;支持 `AS 语法,用于多阶段构建(不同阶段可使用不同基础镜像,最终仅保留目标阶段内容,减小镜像体积) |
FROM --platform |
扩展 FROM 指令,指定基础镜像的目标架构(如 linux/amd64、linux/arm64、windows/amd64),适配多架构镜像构建,解决跨平台部署问题 |
ARG |
定义构建阶段专用参数,仅在 docker build 过程中生效,容器运行时不可用;支持设置默认值(如 ARG APP_VERSION=1.0),可通过 docker build --build-arg <参数名>=> 命令覆盖默认值;ARG 指令需在引用它的指令之前定义,且在 FROM 之前定义的 ARG 仅能在 FROM 指令中使用 |
FROM --build-arg |
结合 ARG 使用,在指定基础镜像时传递构建参数(如 FROM --build-arg HTTP_PROXY=xxx ubuntu:22.04),用于基础镜像构建过程中的参数配置 |
三、文件操作与目录配置模块
该模块指令用于在镜像中复制文件、创建目录、设置工作目录,控制镜像内的文件结构。
| 指令 | 说明 |
|---|---|
COPY |
将本地主机的文件 / 目录复制到镜像的指定路径;支持通配符(如 COPY *.txt /app/);复制时保持源文件的权限属性;如果目标路径不存在,会自动创建;语法:COPY <源路径>... <目标路径> 或 COPY [">", " ..., ""](源路径含空格时需用引号包裹) |
ADD |
功能与 COPY 类似,额外支持:1. 自动解压本地压缩文件(如 .tar、.gz、.zip)到目标路径;2. 支持 URL 作为源路径,自动下载文件到目标路径(不推荐,建议用 RUN wget/curl 替代,便于控制下载过程);语法与 COPY 一致 |
WORKDIR |
设置容器启动后的默认工作目录,后续的 RUN、CMD、ENTRYPOINT、COPY、ADD 等指令会在该目录下执行;如果目录不存在,会自动创建;支持多次使用(每次使用会切换到新目录,如 WORKDIR /app → WORKDIR src,最终工作目录为 /app/src);路径支持相对路径和绝对路径 |
VOLUME |
声明容器运行时的持久化数据卷(仅声明,实际挂载需在 docker run 时指定主机路径或命名卷);用于存储容器运行时产生的动态数据(如数据库文件、日志),避免容器删除后数据丢失;支持单个路径(如 VOLUME /data)或多个路径(如 VOLUME ["/data", "/logs"]);声明的卷在容器启动时会自动创建,且权限为 root:root |
四、环境配置模块
该模块指令用于配置容器运行时的环境变量、用户权限、内核参数等,影响容器运行状态。
| 指令 | 说明 |
|---|---|
ENV |
设置容器运行时的环境变量(构建阶段和运行阶段均生效);支持两种格式:ENV <键>=<值>(单个变量)或 ENV > <值1> <键2> >(多个变量);后续指令(RUN、CMD 等)可直接引用(如 ENV PATH=/app/bin:$PATH);容器运行时可通过 docker run -e <值> 覆盖默认值 |
USER |
指定容器运行时的用户(默认以 root 用户运行);支持用户名、UID、UID:GID 格式(如 USER appuser、USER 1000、USER 1000:1000);使用非 root 用户可提高容器安全性;USER 指令之后的所有指令(RUN、CMD 等)都会以该用户身份执行;如需切换回 root 用户,可再次使用 USER root |
SHELL |
指定容器内的默认 shell 程序,用于 RUN、CMD、ENTRYPOINT 等指令的命令执行;默认 shell:Linux 镜像为 /bin/sh -c,Windows 镜像为 cmd /S /C;语法:SHELL ["<shell路径>", "<参数>"](如 SHELL ["/bin/bash", "-c"],让 RUN 指令使用 bash 执行命令) |
ENV --unset |
移除已设置的环境变量(如 ENV --unset HTTP_PROXY),用于清理构建过程中临时设置的环境变量,减少镜像冗余 |
LABEL |
为镜像添加元数据标签(键值对格式),用于分类、筛选、说明镜像信息(如作者、版本、用途);支持单个标签(LABEL maintainer=devops@example.com)或多个标签(LABEL com.example.version=1.0 com.example.env=prod);可通过 docker inspect > 查看标签信息;多个 LABEL 指令会合并为一个,建议集中编写 |
五、运行命令与依赖安装模块
该模块指令用于在构建镜像时执行命令(如安装依赖、编译程序、配置系统),指令执行结果会被固化到镜像层。
| 指令 | 说明 |
|---|---|
RUN |
构建阶段执行命令,每个 RUN 指令会创建一个新的镜像层;支持两种格式:1. 壳层格式(RUN <命令>):通过默认 shell 执行(如 /bin/sh -c),支持管道、变量替换等壳层特性(如 RUN apt update && apt install -y nginx);2. exec 格式(RUN ["<可执行文件>", "<参数1>", ">"]):直接执行可执行文件,不通过 shell,避免字符转义问题,且信号能直接传递(如 RUN ["/usr/bin/wget", "https://example.com/file.tar.gz"]);建议将多个相关命令合并为一个 RUN 指令(用 && 连接),减少镜像层数,减小镜像体积 |
RUN --mount |
构建阶段临时挂载文件系统(仅在当前 RUN 指令执行期间有效,指令结束后挂载消失),用于构建时的依赖缓存、秘密数据挂载等场景;支持多种挂载类型:type=bind(绑定本地目录)、type=cache(缓存目录,加速多次构建)、type=secret(挂载秘密文件,避免明文暴露)、type=tmpfs(临时文件系统);语法:RUN --mount=type=<类型>,src=路径>,dst=> RUN –mount=type=cache,target=/var/cache/apt apt update && apt install -y nginx`) |
RUN --network |
控制 RUN 指令执行时的网络模式(如 --network=none 禁用网络,--network=host 共享主机网络,--network=连接指定网络);默认网络模式为 default`(容器网络);用于控制构建过程中是否允许网络访问(如禁用网络以确保构建不依赖外部资源) |
六、容器启动配置模块
该模块指令用于设置容器启动时的默认行为(如启动命令、入口点、暴露端口),影响容器运行时的初始状态。
| 指令 | 说明 |
|---|---|
CMD |
指定容器启动时的默认命令,容器启动后仅执行一次;支持三种格式:1. 壳层格式(CMD :通过默认 shell 执行(如 CMD nginx -g ‘daemon off;’);2. exec 格式(CMD [""< 参数 1>", “2>”]):推荐格式,直接执行可执行文件(如 CMD [“nginx”, “-g”, “daemon off;”]);3. 参数格式(CMD ["< 参数 1>", “>”]):配合 ENTRYPOINT使用,为入口点传递默认参数;一个 Dockerfile 中仅能有一个CMD指令,多个CMD 仅最后一个生效;docker run命令后指定的参数会覆盖CMD` 的默认值 |
ENTRYPOINT |
定义容器的入口点(即容器启动时执行的可执行程序),与 CMD 配合使用时,CMD 仅作为参数传递给 ENTRYPOINT;支持两种格式:1. exec 格式(ENTRYPOINT ["<可执行文件>", "1>", ...]):推荐格式,信号可直接传递,容器启动后进程为 PID 1;2. 壳层格式(ENTRYPOINT >):通过 shell 执行,进程不会成为 PID 1,可能影响信号处理(如 docker stop 无法正常终止进程);一个 Dockerfile 中仅能有一个 ENTRYPOINT 指令,多个 ENTRYPOINT 仅最后一个生效;docker run --entrypoint 命令可覆盖 ENTRYPOINT 的默认值 |
EXPOSE |
声明容器运行时对外暴露的端口(仅为文档说明作用,不实际映射端口到主机);用于告知使用者容器的服务端口,便于 docker run -p 映射;支持单个端口(EXPOSE 80)、多个端口(EXPOSE 80 443)、指定协议(EXPOSE 80/tcp 80/udp,默认 TCP);即使不声明 EXPOSE,docker run -p 仍可映射端口 |
HEALTHCHECK |
定义容器健康检查规则,用于判断容器内服务是否正常运行;支持两种格式:1. HEALTHCHECK [选项] CMD (如 HEALTHCHECK –interval=30s –timeout=10s –retries=3 CMD curl -f http://localhost |
七、安全与资源控制模块
该模块指令用于配置容器运行时的安全策略、资源限制、内核参数,提升容器运行的安全性和稳定性。
| 指令 | 说明 |
|---|---|
SECURITY_OPT |
设置容器的安全选项,用于限制容器的权限、启用安全机制(如 --security-opt seccomp=profile.json 启用自定义 seccomp 安全配置,--security-opt apparmor=profile 启用 AppArmor 配置);语法:SECURITY_OPT ["<选项1>", ">"];用于增强容器安全性,限制容器对主机的访问权限 |
CAP_ADD |
为容器添加 Linux 内核能力(Capabilities),默认容器仅拥有部分基础能力;常见能力:NET_ADMIN(网络管理权限)、SYS_TIME(修改系统时间权限)、DAC_READ_SEARCH(读取任意文件权限);语法:CAP_ADD ["<能力1>", "2>"](如 CAP_ADD ["NET_ADMIN"]);仅授予必要能力,避免过度授权 |
CAP_DROP |
从容器中移除 Linux 内核能力,与 CAP_ADD 配合使用,最小化容器权限;支持 CAP_DROP ALL(移除所有能力,仅保留默认最小能力集);语法:CAP_DROP ["<能力1>", "<能力2>"](如 CAP_DROP ["SETUID", "SETGID"]) |
SYSCTL |
配置容器运行时的内核参数(仅在 Linux 镜像中生效),用于优化容器网络、内存等性能;语法:SYSCTL ["<参数1>=>", "<参数2>=<值2>"](如 SYSCTL ["net.ipv4.ip_forward=1", "net.core.somaxconn=1024"]);需确保内核参数支持容器级配置,部分参数需主机内核开启相关功能 |
USER --root |
扩展 USER 指令,强制以 root 用户执行后续指令(如 USER --root RUN apt update),用于需要临时提升权限的场景,执行完成后可切换回普通用户,平衡安全性和操作便利性 |
八、多阶段构建专用模块
该模块指令仅用于多阶段构建,实现构建过程与运行环境分离,减小最终镜像体积。
| 指令 | 说明 |
|---|---|
COPY --from |
多阶段构建专用,从之前命名的构建阶段复制文件到当前阶段(如 COPY --from=builder /app/bin/app /usr/local/bin/);builder 为前一阶段的 FROM AS 定义的名称;支持从外部镜像复制文件(如 COPY –from=nginx:alpine /etc/nginx/nginx.conf/app/`);核心作用是仅保留运行时必需的文件(如编译后的程序),丢弃构建时的依赖(如编译器、源代码),大幅减小镜像体积 |
FROM --from |
多阶段构建专用,指定当前阶段的基础镜像为前一构建阶段(如 FROM --from=builder alpine:3.18),用于基于前一阶段的构建结果继续构建,适用于复杂的分层构建场景 |
九、示例
# ===================== 第一阶段:构建阶段(多阶段构建核心)=====================
# 指定构建基础镜像,带版本锁定+镜像别名,适配多阶段复用
FROM maven:3.9.6-openjdk-17-slim AS builder
# 设置构建阶段的工作目录(核心指令,统一后续操作路径)
WORKDIR /app/build
# 声明元数据:镜像作者(Name <Email> 规范格式)
LABEL maintainer="DevOps-Team <devops@company.com>"
# 声明元数据:镜像描述、版本、应用类型(标准化镜像标识)
LABEL org.opencontainers.image.title="Java-Backend-Service"
LABEL org.opencontainers.image.description="Production-grade Java microservice with full optimizations"
LABEL org.opencontainers.image.version="v2.1.0"
LABEL org.opencontainers.image.authors="devops-team"
# 声明元数据:镜像开源协议、仓库地址
LABEL org.opencontainers.image.licenses="MIT"
LABEL org.opencontainers.image.source="https://github.com/xxx/java-service"
# 1. COPY 指令多参数演示:--chown(指定文件属主)、通配符、多源复制
# 复制Maven配置文件(优先下载依赖,利用Docker分层缓存,提升构建效率)
COPY --chown=1000:1000 pom.xml ./
COPY --chown=1000:1000 settings.xml /usr/share/maven/conf/
# 2. RUN 指令多参数演示:\换行拼接、&& 链式执行、管道符、apt包管理全参数
# 安装构建依赖+清理缓存,减少镜像体积;指定DEBIAN_FRONTEND避免交互
RUN apt-get update \
&& DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends git curl wget \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
# 下载Maven依赖(分层缓存核心:依赖不变则该层不重建)
RUN mvn dependency:go-offline -B
# 复制项目源码(源码变动仅重建该层及后续层)
COPY --chown=1000:1000 src/ ./src/
# 打包项目:跳过测试、指定编码、输出可执行Jar包
RUN mvn clean package -DskipTests -Dfile.encoding=UTF-8 -Dmaven.compiler.source=17 -Dmaven.compiler.target=17
# ===================== 第二阶段:运行阶段(精简镜像,生产环境规范)=====================
# 选型轻量级基础镜像(Alpine版,体积仅几十MB,比slim更精简),指定具体版本避免漂移
FROM openjdk:17-jdk-alpine3.19 AS production
# 设置时区(解决容器内时区与宿主机不一致问题,生产必配)
ENV TZ=Asia/Shanghai
# 3. ENV 指令多参数演示:批量设置环境变量(应用配置、JVM调优、路径配置)
# 应用核心配置
ENV APP_NAME=java-service \
APP_PORT=8080 \
SPRING_PROFILES_ACTIVE=prod \
# JVM性能调优参数(生产级,适配容器内存限制)
JAVA_OPTS="-Xms512m -Xmx1024m -XX:+UseContainerSupport -XX:MaxRAMPercentage=80.0" \
# 应用工作路径
APP_HOME=/app/runtime
# 4. ARG 指令演示:构建时参数(仅构建阶段生效,可通过 docker build --build-arg 传参)
# 定义运行时用户ID/组ID,支持构建时自定义
ARG RUN_USER=appuser
ARG RUN_UID=1000
ARG RUN_GID=1000
# 创建非root用户+组(生产安全规范:禁止容器以root运行,降低权限风险)
RUN addgroup --gid ${RUN_GID} ${RUN_USER} \
&& adduser --uid ${RUN_UID} --gid ${RUN_GID} --disabled-password --gecos "" ${RUN_USER}
# 创建应用工作目录+授权(指定属主,避免权限问题)
RUN mkdir -p ${APP_HOME}/logs ${APP_HOME}/conf \
&& chown -R ${RUN_USER}:${RUN_USER} ${APP_HOME}
# 切换工作目录(后续指令默认在此路径执行)
WORKDIR ${APP_HOME}
# 5. COPY --from 多阶段复制核心:从builder阶段复制打包产物,仅保留运行必需文件
COPY --from=builder --chown=${RUN_USER}:${RUN_USER} /app/build/target/*.jar ${APP_HOME}/app.jar
# 6. USER 指令:切换为非root用户(生产必配,完成权限降级)
USER ${RUN_USER}
# 7. EXPOSE 指令:声明容器对外暴露的端口(TCP协议,生产规范:仅声明,不映射)
# 支持多端口声明,区分应用端口、监控端口
EXPOSE ${APP_PORT}/tcp 9100/tcp
# 8. VOLUME 指令:声明持久化数据卷(日志、配置、数据,实现容器数据与容器解耦)
# 容器销毁后,卷内数据可保留,支持宿主机挂载/容器间共享
VOLUME ["${APP_HOME}/logs", "${APP_HOME}/conf", "/tmp"]
# 9. HEALTHCHECK 健康检查指令(生产必配,Docker容器自愈核心)
# --interval:检查间隔(30秒)、--timeout:超时时间(5秒)、--retries:重试次数(3次)、--start-period:启动等待时间(60秒)
# 检查逻辑:通过curl访问健康接口,返回200则健康,否则不健康
HEALTHCHECK --interval=30s --timeout=5s --retries=3 --start-period=60s \
CMD curl -f http://localhost:${APP_PORT}/actuator/health || exit 1
# 10. ENTRYPOINT + CMD 组合(生产最优解:ENTRYPOINT固定执行逻辑,CMD传默认参数)
# ENTRYPOINT:不可被docker run命令行参数覆盖,保证启动脚本固定
# CMD:可被docker run参数覆盖,支持启动参数自定义
ENTRYPOINT ["java", "-jar"]
CMD ["app.jar"]补充说明
-
指令执行顺序:Dockerfile 指令按从上到下的顺序执行,
FROM指令必须是第一个非注释指令; -
镜像层优化:
RUN、COPY、ADD指令会创建新的镜像层,层数越多镜像体积越大,建议合并相关RUN指令,避免无用文件复制; -
注释语法:使用
#开头表示注释(如# 安装 Nginx),注释仅用于说明,不会被执行; -
官方文档参考:所有指令的最新说明可查阅 Docker 官方文档:Dockerfile Reference