0%

DockerFile

Dockerfile 详解:镜像构建的 “说明书”

Dockerfile 是一个文本文件,包含一系列构建镜像的指令,通过 docker build 命令可自动执行这些指令生成自定义镜像。它就像镜像的 “施工蓝图”,明确了从基础镜像到最终镜像的每一步操作,实现了镜像构建的自动化和可复用性。

Dockerfile 基本结构

Dockerfile 由指令(Instruction)注释组成,指令格式为:
INSTRUCTION arguments(指令大写,参数小写,惯例)。

核心指令包括:FROMRUNCMDCOPYADD 等,下文将详细解析。

核心指令详解

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
    6
    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 解析问题)。
  • 示例:

    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 指令。
  • 格式:

    • 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. COPYADD:复制文件到容器

  • 作用:将宿主机文件 / 目录复制到镜像的指定路径。
指令 功能 推荐场景
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:设置工作目录

  • 作用:指定后续 RUNCMDENTRYPOINT 等指令的工作目录(类似 cd 命令)。

  • 特点:若目录不存在,会自动创建;可多次使用,切换不同目录。

  • 示例:

    1
    2
    3
    4
    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>(多变量)。
  • 示例:

    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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 基础镜像: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"]

构建镜像命令

1
2
# -t 指定镜像名和标签,. 表示Dockerfile在当前目录
docker build -t my-java-app:1.0 .

Dockerfile 最佳实践

  1. 精简镜像层数:合并 RUN 命令(用 &&\ 换行),减少镜像大小。

    1
    2
    3
    4
    # 推荐
    RUN yum update -y && \
    yum install -y nginx && \
    yum clean all # 清理缓存,减小镜像体积
  2. 使用 .dockerignore 文件:排除不需要复制到镜像的文件(如 node_modules.git),减少上下文传输时间。

  3. 优先选择轻量基础镜像:如 alpine 版本(体积小,适合生产环境),避免使用 ubuntu 等重量级镜像。

  4. 多阶段构建:分离构建阶段和运行阶段,仅保留运行所需文件(如 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"]
  5. 避免使用 root 用户:在镜像中创建非 root 用户并切换,增强安全性。

    1
    2
    RUN adduser -D appuser
    USER appuser # 后续命令以appuser执行

总结

Dockerfile 通过指令定义了镜像的构建流程,是 Docker 生态中 “基础设施即代码” 的核心体现。掌握 FROMRUNCMDCOPY 等核心指令的用法,结合最佳实践(如精简层数、多阶段构建),可构建出高效、安全、可维护的镜像

欢迎关注我的其它发布渠道

表情 | 预览
快来做第一个评论的人吧~
Powered By Valine
v1.3.10