跳到内容

元数据卡

  • 前置知识:镜像 vs 容器的概念(上一页)
  • 预计时间:12 分钟
  • 完成标志:能写一个 Dockerfile 把自己应用打包成镜像

你的进度

"你从 Docker Hub 拿别人的蓝图造了房子。"工坊主人点点头。"但你要在里面跑你自己的东西——JDK 17、Maven、你的 Spring Boot 应用。别人给你画好的蓝图可不包含这些。"

"所以我得自己画一张蓝图?"

"对。"他从桌上拿起一张白纸。"你想让别人在任何一台电脑上都能复刻你的环境?那就把步骤写下来——用 Docker 能读懂的格式。"


Dockerfile 是什么

Dockerfile 就是你的施工图。Docker 读这个文件,按照每一行的指示,一层一层造出镜像。

想象你有一个 Java 项目,需要 JDK 17。你要把这个环境打包成一个自包含的箱子。在项目根目录创建一个文件叫 Dockerfile(注意没有扩展名):

dockerfile
# 基础镜像:从带有 JDK 17 的官方镜像开始
FROM eclipse-temurin:17-jdk

# 创建应用目录
WORKDIR /app

# 把当前目录下的文件复制到容器里的 /app
COPY . .

# 告诉 Docker 这个容器要暴露 8080 端口
EXPOSE 8080

# 容器启动时运行的命令
CMD ["java", "-jar", "my-app.jar"]

每一行的含义:

指令作用类比
FROM选一个基础镜像决定地基是什么
WORKDIR设置工作目录划一块区域
COPY把文件复制进镜像搬材料进去
EXPOSE声明容器会用的端口预留门洞
CMD容器启动时运行的默认命令定好最后一步怎么做
bash
# 把蓝图变成镜像
docker build -t my-app:v1 .

# 从镜像启动容器
docker run -d -p 8080:8080 --name my-app my-app:v1

docker build -t my-app:v1 . 的意思是:在当前目录(.)找 Dockerfile,按步骤构建镜像,取名叫 my-app:v1

优化的 Dockerfile:层缓存

你刚烧完一个镜像,工坊主人走过来看了一眼。"等一下,"他说,"你这个蓝图每次改代码就要重新下载所有依赖——连那些没变过的包都要重新下载一遍。这不是浪费炭火吗?"

Dockerfile 是按层(layer)构建的。每一层变更会导致后面所有层重新构建。你应该把不变的东西放在前面,变的东西放在后面

dockerfile
FROM eclipse-temurin:17-jdk
WORKDIR /app

# 先把依赖描述文件复制进去——依赖通常不变
COPY pom.xml .
RUN mvn dependency:resolve

# 再复制代码——只有代码变了才会触发这层之后的构建
COPY src ./src
RUN mvn package -DskipTests

EXPOSE 8080
CMD ["java", "-jar", "target/my-app-1.0.jar"]

"改动少的在前,改动多的在后"——这是 Dockerfile 优化的第一原则。依赖通常不常变,代码经常变,所以把 COPY pom.xmlRUN mvn dependency:resolve 放在前面。


常见陷阱:我改了代码,但镜像好像没更新?

如果你改了 pom.xmlsrc/ 里的代码但镜像没变——很可能是 Docker 用了缓存层。加 --no-cache 强制重构建:

bash
docker build --no-cache -t my-app:v2 .

旅人笔记

Dockerfile 是你的施工图。FROM 选地基,WORKDIR 划区域,COPY 搬材料,CMD 定启动咒语。不变的东西放前面,变的东西放后面,靠层缓存省时间。

下一步:Docker Compose——管理多个服务

单个容器太简单了。真实项目不只是一个 Java 应用——它还有数据库、缓存、消息队列。

学多服务管理 →

Built with VitePress | Software Systems Atlas