《SpringBoot 3:入门与应用实战》第 14 章 打包与部署 制作 Docker 镜像 阅读笔记 43
Docker 是一个开源的容器引擎,是当下容器虚拟化的主流选择,它可以为应用创建一个可移植的独立容器。Docker 的核心思想是一次构建处处运行,这与 Java 的一次编译处处执行相似。Docker 有启动快、占用资源少、容器隔离等优点,这使得 Docker 成为部署和运行基础组件、应用程序乃至微服务的不二选择。本节中会将工程打包为一个 Docker 镜像,并使其在 Docker 中运行。
14.3.1 Docker 基础
Docker 的安装方式非常简单,在 Linux 系统中只需要简单几条指令。笔者使用 CentOS 7 进行操作。
一个 Docker 实例中可以下载和存放很多个镜像,一个镜像又可以运行多个容器实例,这组概念比较类似于 Java 中的类和对象。Docker 中的每个容器之间都是环境隔离的,一个 Docker 容器可以简单理解为一个小微 Linux 系统的虚拟机。
通常使用 Docker 的指令完成镜像的搜索、下载拉取、删除以及对容器的创建、启停、移除等操作,常用的Docker 操作指令如表所示。
| 操作类别 | 核心指令 | 作用与说明 |
|---|---|---|
| 镜像管理 | docker pull <镜像名:标签> |
从镜像仓库拉取指定镜像到本地。 |
docker images |
查看本地所有已下载的镜像列表。 | |
docker build -t <名称:标签> <路径> |
根据 Dockerfile 构建自定义镜像。 | |
docker rmi <镜像名/ID> |
删除本地指定的镜像。 | |
docker save / docker load |
将镜像导出为 tar 压缩包,或从压缩包导入镜像(常用于离线迁移)。 | |
| 容器生命周期 | docker run [选项] <镜像> |
创建并启动新容器。常用参数:-d(后台运行)、-p(端口映射)、--name(指定名称)。 |
docker ps / docker ps -a |
查看正在运行的容器;加 -a 可查看包含已停止的所有容器。 |
|
docker start / stop / restart |
启动、优雅停止或重启指定的容器。 | |
docker rm <容器名/ID> |
删除已停止的容器(加 -f 可强制删除运行中的容器)。 |
|
| 容器交互与调试 | docker exec -it <容器> /bin/bash |
进入正在运行的容器内部,开启交互式终端。 |
docker logs -f <容器名/ID> |
查看容器日志,-f 参数可实时追踪最新日志。 |
|
docker cp <源路径> <目标路径> |
在宿主机与容器之间双向复制文件或目录。 | |
| 网络管理 | docker network ls |
查看当前 Docker 环境中的所有网络。 |
docker network create <网络名> |
创建自定义网络(常用于实现多容器间的内部通信)。 | |
docker network connect <网络> <容器> |
将运行中的容器连接到指定的网络。 | |
| 数据卷管理 | docker volume create <卷名> |
创建用于数据持久化的数据卷。 |
docker run -v <卷名>:<容器路径> |
在启动容器时挂载数据卷,确保容器删除后数据不丢失。 | |
docker volume inspect <卷名> |
查看数据卷的详细信息(包括在宿主机上的实际存储路径)。 | |
| 系统维护与清理 | docker system prune |
清理所有已停止的容器、未使用的网络及悬空镜像。 |
docker system prune -a |
深度清理,删除所有未使用的镜像和停止的容器(谨慎使用)。 | |
docker stats |
实时查看容器的 CPU、内存等资源使用情况。 |
14.3.2 Dockerfile 文件
使用 Dockerfile 文件可以将可执行 jar 包制作为 Docker 镜像,为此需要编写一个 Dockerfile 文件,首先要了解 Dockerfile 文件的一些指令,如表所示。
| 指令类别 | 核心指令 | 作用与说明 |
|---|---|---|
| 基础与元数据 | FROM |
指定基础镜像,必须是 Dockerfile 中的第一条非注释指令。 |
LABEL |
为镜像添加键值对形式的元数据(如维护者信息),用于替代已弃用的 MAINTAINER。 |
|
ARG |
定义仅在构建阶段(docker build)有效的变量,不会保留在最终镜像中。 |
|
| 文件与目录操作 | COPY |
将本地构建上下文中的文件或目录复制到镜像中,官方推荐优先使用。 |
ADD |
功能类似 COPY,但额外支持自动解压本地 tar 包及从 URL 下载资源。 |
|
WORKDIR |
设置后续指令的工作目录,若目录不存在会自动创建。 | |
VOLUME |
声明数据卷挂载点,主要用于数据持久化或容器间数据共享。 | |
| 环境配置与构建 | RUN |
在构建过程中执行命令(如安装依赖),每执行一次会生成一个新的镜像层。 |
ENV |
设置环境变量,在构建期和容器运行时均持久化生效。 | |
| 运行阶段控制 | EXPOSE |
声明容器运行时监听的端口(仅为文档说明,实际端口映射需在 docker run 时指定)。 |
CMD |
定义容器启动时的默认执行命令,可被 docker run 后的命令行参数覆盖。 |
|
ENTRYPOINT |
设置容器的主程序入口,不易被覆盖,通常与 CMD 配合使用以提供默认参数。 |
|
| 高级与状态检查 | USER |
指定运行后续指令的用户身份,生产环境推荐使用非 root 用户以增强安全性。 |
HEALTHCHECK |
定义周期性检查容器健康状态的命令,帮助 Docker 判断容器是否正常工作。 |
14.3.3 使用 Dockerfile 构建镜像
使用 Dockerfile 文件构建镜像时需要先准备好可执行 jar 包,把 14.1 节中打包好的 jar 包上传到 Linux 主机中,之后编写一个 Dockerfile 文件。简单解释这段 Dockerfile 的含义:使用 FROM 指令声明当前 Spring Boot 应用依赖 eclipse-temurin 镜像,这是一个基于 JDK 17 的较新的开源免费镜像;EXPOSE 8080 代表指定当前镜像最终会在内部暴露 8080 端口;使用 WORKDIR 和 VOLUME 分别指定工作目录和挂载目录;使用ADD 命令将宿主机的 springboot.jar 复制到 Docker 镜像中,最后使用 ENTRYPOINT 指定启动这个 jar 包。


FROM eclipse-temurin:17.0.9_9-jre
EXPOSE 8080
WORKDIR /opt/springboot/work
VOLUME /opt/springboot/volume
ADD springboot.jar /opt/springboot/springboot.jar
ENTRYPOINT ["java", "-jar", "/opt/springboot/springboot.jar"]
编写完这个 Dockerfile 文件后将其复制到 Linux 主机上,放到与 springboot.jar 同一个目录下即可。之后使用命令行进入 /opt/springboot/ 目录下,执行 docker build -t springboot-packages:1.0 . 命令即可完成 Docker 镜像的构建,构建的镜像名为 springboot-packages,版本号为 1.0 。构建成功的效果如图所示。

bash
cd /opt/springboot/
docker build -t springboot-packages:1.0 .

如果此时使用 docker images 命令就可以看到刚构建的镜像,如果要创建一个容器来运行,可以使用 docker run -d --name springboot -p 8080:8080 springboot-packages:1.0 命令,执行完成后将会创建一个后台运行的名称为 springboot 的容器,且对外暴露 8080 端口提供服务。

bash
docker images
docker run -d --name springboot -p 8080:8080 springboot-packages:1.0
docker ps
14.3.4 使用 Maven 插件构建镜像
敏锐的读者可能对于上面的内容察觉到一点:使用 Dockerfile 创建镜像时需要每次先使用 Maven 打包之后再配合 Dockerfile 完成镜像构建,能不能将这两者合并以减少工作量?答案是可以的,Maven 中有一个 Spotify 公司提供的一次性完成打包和镜像构建的插件:docker-maven-plugin。下面来演示一下 docker-maven-plugin 插件的使用。
找到 pom.xml 文件,在 spring-boot-maven-plugin 插件的下面直接添加 docker-maven-plugin 插件的坐标,并配置几个必需的配置项即可,如代码所示。简单解释一下这些配置项的含义:imageName 指定了本次制作镜像的名称和版本号,类似于 14.3.3 节中 docker build 命令中指定的 -t参数;dockerDirectory 指定了当前 Dockerfile 文件的位置,这里选择放到 src/main/docker 目录下; 标签中声明的是将哪些文件打包到镜像中,很明显是通过 mvn package 命令得到的可执行 jar 包,所以按照代码的方式就可以得到唯一的 jar 文件。另外注意一点,为了与Dockerfile 中的 ADD 命令呼应,在 标签中声明一个 springboot,这样打包产生的 jar 文件名称就会变成springboot.jar。
xml
<build>
<finalName>springboot</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>com.spotify</groupId>
<artifactId>docker-maven-plugin</artifactId>
<version>1.2.2</version>
<configuration>
<imageName>springboot:${project.version}</imageName>
<dockerDirectory>${project.basedir}/src/main/docker</dockerDirectory>
<resources>
<resource>
<targetPath>/</targetPath>
<directory>${project.build.directory}</directory>
<include>${project.build.finalName}.jar</include>
</resource>
</resources>
</configuration>
</plugin>
</plugins>
</build>
编写完成后接下来就可以执行命令一次性完成打包和镜像构建,但是请读者注意,要想让这个 Maven 插件发挥作用,需要在执行打包和镜像构建的主机上安装 Docker 环境。当前使用的 Windows 主机在国内安装 Docker 环境非常麻烦,所以需要将当前工程的全部代码复制到 Linux 主机上,并在 Linux 主机上配置 JDK 和 Maven 环境,之后才能完成打包和镜像构建。
将工程复制到 Linux 主机后,执行 mvn clean package docker:build 命令,Maven 会先完成打包动作,之后根据提供的 Dockerfile 文件构建一个名为 springboot、版本号为 1.0-SNAPSHOT 的镜像,可以使用 docker images 命令查看当前镜像。至此,使用 Maven 插件完成 Docker 镜像构建的演示完毕。
14.4 小结
本章介绍了 Spring Boot 应用打包与部署的运行方式。项目开发完毕后必定要打包部署到生产环境运行,Spring Boot 提供了非常方便的打包和运行方式,同时兼顾了基于独立 jar 包运行和借助独立部署的 Servlet 容器运行的方式。此外,还可以制作 Docker 镜像,使用 Docker 容器的方式部署和运行 Spring Boot 的应用。