1. 概述

本教程将重点介绍如何将Spring Boot应用Docker化,使其在隔离环境(即容器)中运行。我们将学习如何创建相互依赖、在虚拟私有网络中互联的容器组合,并了解如何通过单条命令统一管理这些容器。

首先创建一个简单的Spring Boot应用,然后将其运行在轻量级的Alpine Linux基础镜像中。

2. Docker化独立Spring Boot应用

作为示例,我们创建一个名为docker-message-server的简单Spring Boot应用,它暴露一个接口并返回静态消息:

@RestController
public class DockerMessageController {
    @GetMapping("/messages")
    public String getMessage() {
        return "Hello from Docker!";
    }
}

配置正确的Maven文件后,创建可执行jar包:

$> mvn clean package

启动Spring Boot应用:

$> java -jar target/docker-message-server-1.0.0.jar

现在可通过localhost:8888/messages访问该应用。

要Docker化应用,首先创建Dockerfile文件:

FROM openjdk:17-jdk-alpine
MAINTAINER baeldung.com
COPY target/docker-message-server-1.0.0.jar message-server-1.0.0.jar
ENTRYPOINT ["java","-jar","/message-server-1.0.0.jar"]

该文件包含以下信息:

  • FROM:使用已安装Java的Alpine Linux作为基础镜像
  • MAINTAINER:镜像维护者
  • COPY:将jar文件复制到镜像中
  • ENTRYPOINT:容器启动时执行的命令(必须使用JSON数组格式)

通过docker build创建镜像:

$> docker build --tag=message-server:latest .

最后运行容器:

$> docker run -p8887:8888 message-server:latest

应用将在Docker中启动,可通过主机localhost:8887/messages访问。注意端口映射(主机8887 → 容器8888),如果端口被占用需更换可用端口。

以分离模式运行容器时,可使用以下命令管理:

$> docker inspect message-server
$> docker stop message-server
$> docker rm message-server

2.1. 更换基础镜像

可轻松更换基础镜像以使用不同Java版本。例如改用Amazon Corretto发行版:

FROM amazoncorretto:17-alpine-jdk
MAINTAINER baeldung.com
COPY target/docker-message-server-1.0.0.jar message-server-1.0.0.jar
ENTRYPOINT ["java","-jar","/message-server-1.0.0.jar"]

也可使用自定义基础镜像(后文详述)。

3. Docker化复合应用

Docker命令和Dockerfile适合创建单个容器,但当需要管理多个隔离应用组成的网络时,容器管理会变得混乱。

解决方案是Docker Compose,它使用YAML格式的构建文件,更适合管理多容器。例如:

  • 单条命令启动/停止服务组合
  • 合并多个服务的日志输出到伪终端

3.1. 第二个Spring Boot应用

构建两个在不同Docker容器中运行的应用示例。它们将相互通信,并作为"单一单元"呈现给主机系统。创建第二个应用docker-product-server

@RestController
public class DockerProductController {
    @GetMapping("/products")
    public String getMessage() {
        return "A brand new product";
    }
}

构建和启动方式与message-server相同。

3.2. Docker Compose文件

将两个服务的配置合并到docker-compose.yml

version: '2'
services:
    message-server:
        container_name: message-server
        build:
            context: docker-message-server
            dockerfile: Dockerfile
        image: message-server:latest
        ports:
            - 18888:8888
        networks:
            - spring-cloud-network
    product-server:
        container_name: product-server
        build:
            context: docker-product-server
            dockerfile: Dockerfile
        image: product-server:latest
        ports:
            - 19999:9999
        networks:
            - spring-cloud-network
networks:
    spring-cloud-network:
        driver: bridge

配置说明:

  • version:指定格式版本(必填),此处使用新版(旧版为'1')
  • services:定义服务(容器)对象(必填)
    • build:从Dockerfile构建镜像
      • context:构建目录(Dockerfile所在路径)
      • dockerfile:自定义Dockerfile名称
    • image:镜像名称(构建时使用)或从库/远程仓库拉取
    • networks:使用的网络标识符(需在networks部分定义)
  • networks:定义可用网络
    • 此处创建名为spring-cloud-network的bridge类型网络
    • 若设置external: true则使用现有网络

先检查语法错误:

$> docker-compose config

然后构建镜像、创建容器并启动:

$> docker-compose up --build

这将同时启动message-serverproduct-server

停止容器并移除相关网络:

$> docker-compose down

3.3. 服务扩缩容

Docker Compose的服务扩缩容功能很实用。例如运行3个message-server和2个product-server容器。

但需先移除docker-compose.yml中的container_name(让Docker自动命名),并修改端口配置避免冲突:

ports:
    - 18800-18888:8888

使用修改后的yml文件启动服务:

$> docker-compose --file docker-compose-scale.yml up -d --build --scale message-server=1 --scale product-server=1

扩缩容命令:

$> docker-compose --file docker-compose-scale.yml up -d --build --scale message-server=3 --scale product-server=2

此命令将启动额外2个message-server和1个product-server(不停止已运行容器)。

4. 自定义基础镜像

之前使用的基础镜像(openjdk:17-jdk-alpine)包含预装JDK 17的Alpine系统。也可基于Alpine或其他系统构建自定义基础镜像。

创建基于Alpine的Dockerfile并安装JDK:

FROM alpine:edge
MAINTAINER baeldung.com
RUN apk add --no-cache openjdk17

指令说明:

  • FROM:指定构建基础镜像(本地不存在时从DockerHub搜索)
  • MAINTAINER:镜像作者邮箱
  • RUN:在目标系统执行shell命令(使用Alpine包管理器apk安装OpenJDK 17)

构建镜像并存储到本地库:

docker build --tag=alpine-java:base --rm=true .

⚠️ --tag指定镜像名,--rm=true成功构建后删除中间镜像,末尾点表示构建目录。

现在可用alpine-java:base替代openjdk:17-jdk-alpine

5. Spring Boot 2.3的Buildpacks支持

Spring Boot 2.3新增了buildpacks支持。简单说,无需自行编写Dockerfile,只需执行:

$ mvn spring-boot:build-image

或Gradle项目:

$ ./gradlew bootBuildImage

前提:已安装并运行Docker

其核心理念是提供类似Heroku或Cloud Foundry的统一部署体验。只需运行build-image目标,平台自动处理构建和部署。

此外,它能帮助我们更高效地构建Docker镜像。只需修改或调优buildpacks镜像构建器,无需在多个项目中修改Dockerfile。

除易用性和开发体验外,效率更高

  • 构建分层Docker镜像
  • 使用jar文件的解压版本

执行命令后查看镜像列表:

docker image ls -a

将看到新创建的镜像:

docker-message-server 1.0.0 b535b0cc0079

镜像名和版本与Maven/Gradle配置一致,哈希值为镜像短哈希。

启动容器:

docker run -it -p9099:8888 docker-message-server:1.0.0

同样需要端口映射使应用可从外部访问。

6. 总结

本文学习了如何:

  • 构建自定义Docker镜像
  • 将Spring Boot应用作为Docker容器运行
  • 使用docker-compose创建容器组合

更多构建文件细节可参考官方文档:

本文源代码见GitHub仓库


原始标题:Dockerizing a Spring Boot Application