Dockerfile语法全解析:从构建原理到分层构建的实战指南

admin 2026-04-21 01:06:31 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: 本文详细解析Dockerfile语法与构建原理,涵盖FROM、LABEL、COPY、RUN、CMD等核心指令的功能及最佳实践,强调分层构建对镜像体积优化的重要性。重点介绍多阶段构建技术,通过分离构建环境与运行环境显著减少镜像大小,并提供SpringBoot应用实战示例。文章还涉及健康检查、参数化构建等高级特性,为容器化部署提供完整指导。 综合评分: 85 文章分类: 安全开发,技术标准,云安全,其他


cover_image

Dockerfile语法全解析:从构建原理到分层构建的实战指南

原创

一只岸上的鱼 一只岸上的鱼

一只岸上的鱼

2026年4月20日 16:45 江苏

在小说阅读器读本章

去阅读

Dockerfile语法全解析:从构建原理到分层构建的实战指南

缘起

终于写到Dockerfile,构建应用docker镜像是使用docker打包应用的基础,而dockerfile,就是构建docker镜像的灵魂。

什么是Dockerfile

Dockerfile就是一个纯文本文件,里面包含了一条条的指令,用来描述如何自动构建一个Docker镜像。

可以理解为这是一个详细的操作说明书,按照步骤一步一步的定制一个docker镜像。dockerfile的存在,让docker镜像有了:

  1. 标准化了构建过程,确保开发、测试和生产环境的高度一致性
  2. 版本控制与可追溯性:作为纯文本文件,Dockerfile可以像代码一样被Git管理,任何环境变更都有迹可循
  3. 自动化CI/CD的基石:结合Jenkins、GitHub Actions等工具,实现一键自动构建和部署

Dockerfile的基本结构

一个典型的Dockerfile通常分为四个部分:基础镜像信息、维护者信息、镜像操作指令、容器启动时执行指令,先看个例子:

# 1. 基础镜像信息:这是构建的起点FROM ubuntu:20.04
# 2. 维护者信息:告诉别人谁负责这个镜像LABEL maintainer="[email protected]"
# 3. 镜像操作指令:安装软件、配置环境等RUN apt-get update && apt-get install -y nginxCOPY index.html /var/www/html/
# 4. 容器启动时执行指令:启动容器时默认运行的命令CMD ["nginx", "-g", "daemon off;"]

核心语法指令

FROM 万丈高楼平地起

每个Dockerfile的第一条非注释指令必须是FROM,它指定了你的基础镜像

FROM ubuntu:20.04

Dockerfile每一条指令都会在镜像上创建一个新的层:,这也是镜像体积优化的关键:

当有多个镜像公用一个基础镜像(FROM 同一个基础镜像)的时候,系统只存储一份,然后使用类似于超链接的方式,来节省存储空间。

**最佳实践:**尽量选择官方镜像,明确指定标签(tag,如20.04),避免使用latest:这是个游标tag,永远指向最新版本,以防止底层不可控的更新导致程序奔溃。

LABEL:镜像的身份证

用于添加元数据,如作者、版本、描述,例子:

LABEL maintainer="[email protected]" version="1.0" description="Hello World App"

WORKDIR:设置工作目录

WORKDIR /app

简单理解就是cd到当前目录,后续的相对目录就是以此目录为基础路径。

COPY 与 ADD:把文件搬进容器

  1. COPY:纯粹的复制文件
  2. ADD:除了复制,还支持自动解压本地tar包和从URL下载文件
COPY package.json /app/# ADD package.tar.gz /app/  # 会自动解压

最佳实践: 推荐使用简单的命令:意思是如果只是复制文件,就用COPY,不要用ADD

RUN:在构建阶段执行命令

# Shell格式RUN apt-get update && apt-get install -y curl

run用于执行命令,这里有点讲究:每条命令会产生一个层,所有合理的合并、分拆命令组合,能够做到减少存储和镜像大小:

最佳实践

  1. 合理分拆: 举例你有2个镜像需要构建构建,他们都是基于debian:12,然后a镜像需要安装软件a、b、c,b镜像需要安装如那件a、b、d,那么你可以把安装a、b的命令放在一个RUN指令里,安装c和d的命令放在另一个RUN指令里,这样就能让a和b镜像共享安装a、b的层,节省存储空间。
  2. 合理合并: 当你有2条命令,分别安装2个软件,但是这俩个软件只有这个镜像使用,就可以合并到一条指令里面安装
# 👎 产生3个层RUN apt-get updateRUN apt-get install -y curlRUN rm -rf /var/lib/apt/lists/*
# 👍 仅产生1个层,镜像更小RUN apt-get update && apt-get install -y --no-install-recommends curl \    && rm -rf /var/lib/apt/lists/*

注意: 这里只是以安装软件为例,所有的命令都适用分拆合并规则。

CMD 与 ENTRYPOINT:容器的启动命令

  1. CMD:提供容器启动的默认命令。一个Dockerfile只有最后一个CMD生效(就是顺序排,后面的替代前面的),且可以被docker run命令行参数直接覆盖。
  2. ENTRYPOINT:定义容器的主命令,不会被docker run的参数覆盖,而是将docker run后的参数作为附加参数传给ENTRYPOINT: 可理解这个是指明运行环境:python表示使用python运行cmd的命令,bash就是用bash运行cmd命令……
# 示例:组合使用,实现灵活启动ENTRYPOINT ["python"]CMD ["app.py"]  # 默认执行 python app.py# 如果 docker run myimage server.py,则执行 python server.py

EXPOSE  声明端口

EXPOSE 8080

仅作为文档说明,告知使用者容器监听的端口。

ENV 设置环境变量

ENV NODE_ENV=productionENV PATH="/app/bin:${PATH}"

设置构建和运行时的环境变量

VOLUME 声明数据卷

VOLUME ["/data"]

声明容器中需要持久化存储的目录:数据库、日志文件、上传目录等。

ARG:构建时参数化

这是一个非常实用的命令,将多次用到的数据、字符、版本等等变量化,这样当需要修改的适合,只需要修改一次了:

# 在Dockerfile中定义默认值ARG APP_VERSION=1.0# 在构建指令中使用#第一次用RUN echo "Building version $APP_VERSION"#第二次用RUN echo "Building version $APP_VERSION"# 第三次用...RUN echo "Building version $APP_VERSION"

HEALTHCHECK 容器健康检查

你可能在运行容器的适合,看过一些容器是这样的:caddy(healthy),能实现这个的就是这个命令了:

定期检查容器的健康状态,确保服务可用:

HEALTHCHECK --interval=30s --timeout=3s --retries=3 \  CMD curl -f http://localhost:8080/health || exit 1

多阶段构建:分层构建的实战指南

理解多阶段构建的需求,得先明白一个知识:

构建环境与运行环境

java程序员肯定都知道jdk和jre的区别,这就是开发环境和运行环境,其大小有很大的区别,其他语言也一样。

这就产生了多阶段构建的需求:编译程序的时候,使用开发环境,最后运行,使用运行环境,可以大大减少镜像的体积:

# ================= 第一阶段:构建阶段 (Builder Stage) =================# 使用包含Maven的官方镜像进行编译打包FROM maven:3.8.6-openjdk-17 AS builder
# 设置工作目录WORKDIR /app
# 1. 先只拷贝pom.xml文件,利用缓存预下载依赖# 这一步是关键优化:如果pom.xml未变更,Docker会复用缓存层,跳过依赖下载COPY pom.xml .RUN mvn dependency:go-offline -B
# 2. 拷贝源代码并进行打包COPY src ./srcRUN mvn clean package -DskipTests
# ================= 第二阶段:运行阶段 (Runtime Stage) =================# 使用轻量级的OpenJDK运行时镜像FROM openjdk:17-jdk-slim
# 设置工作目录WORKDIR /app
# 3. 从构建阶段仅复制生成的JAR包到最终镜像# 这是多阶段构建的核心:只保留运行所需的最小文件集COPY --from=builder /app/target/*.jar app.jar
# 暴露应用端口(Spring Boot默认8080)EXPOSE 8080
# 添加健康检查指令HEALTHCHECK --interval=30s --timeout=3s --retries=3 \  CMD curl --fail http://localhost:8080/actuator/health || exit 1
# 设置容器启动命令ENTRYPOINT ["java", "-jar", "app.jar"]

对springboot镜像构建,推荐:

探索springboot程序打包docker的最佳方式

小结

凭借记忆,写了一些常用的命令,肯定给还有遗漏的

本系列其他文章:

  1. Docker 入门之基本概念
  2. Docker 入门之网络基础
  3. Docker 入门之overlay网络
  4. Docker 入门之单机常用命令总结

免责声明:

本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。

任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。

本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我

本文转载自:一只岸上的鱼 一只岸上的鱼 一只岸上的鱼《Dockerfile语法全解析:从构建原理到分层构建的实战指南》

评论:0   参与:  0