代码改变世界

Windows Docker 部署 Spring Boot 项目

  Fururur  阅读(4091)  评论(0编辑  收藏  举报

本文首发于我的个人博客,Windows Docker 部署 Spring Boot 项目 ,欢迎访问!

使用 Docker 部署一个简单的 Spring Boot 数据库项目。

最近容器化技术 hin 流行啊,所以开始折腾一下呗。试用了下,有的时候的确比虚拟机要方便。其实起初是要用 Redis,但是 Windows 安装不方便,于是就看了下 Docker,基本开箱即用,Docker Hub 上 pull 一个 Redis 官方镜像就可以了。刚好最近在学 Spring Cloud 微服务,也就尝试下 Docker 部署 Spring Boot 项目。

内容上,本文主要是对 Spring Boot 官方文档的一个补充,英语不错的可以直接浏览参考文献 6-7。

Docker 的基本概念和用法,这里就详细展开了,可以看参考文献 1-3。

Docker Configuration

Docker 一般是安装在 Linux 系统中的,但是目前 Windows 也能使用,下载安装后开箱即用。额外需要配置的是:

1.暴露 TCP 端口,可以在 IDEA 的 Docker 插件中连接使用。

2.替换官方的 Docker 仓库,使用阿里云镜像加速。在 Daemon 中可进行配置。

Config IDEA Plugin

Docker 本身是没有 GUI 界面的,所以所有的维护管理都必须使用命令行,比较麻烦,而 IDEA 给我们提供了一个简单的 Docker 插件,用于管理 Image 和 Container。

在设置中直接搜索 docker,添加一个 Docker Engine,配置 URL,稍等下面提示连接成功后,就可以了。如果连接失败了,可以检查下 TCP 的 2375 端口是否暴露了。

然后在底部,就能看到 Docker 的 tab了。里面的信息和命令行中看到的一致。基本的创建、删除、端口映射等操作都能在上面进行。

那么 Docker 相关的配置就完成了。

Create Spring Boot Project

这里用来演示的是一个 Spring Boot 的数据库项目。跟之前一样,配置一些基本内容就可以了。

<!--pom.xml-->
<groupId>com.example</groupId>
<artifactId>spring-docker</artifactId>
<version>1.0.0</version>
<name>spring-docker</name>

<properties>
  <java.version>1.8</java.version>
  <skipTests>true</skipTests>		
  <druid-spring-boot-starter.version>1.1.10</druid-spring-boot-starter.version>
  <dockerfile-maven-plugin.version>1.4.10</dockerfile-maven-plugin.version>
  <docker.image.prefix>springboot</docker.image.prefix>
</properties>

<dependencies>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
  </dependency>

  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
  </dependency>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
  </dependency>
  <dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid-spring-boot-starter</artifactId>
    <version>${druid-spring-boot-starter.version}</version>
  </dependency>
  <dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <scope>runtime</scope>
  </dependency>
</dependencies>
# application.yml
# 配置数据库信息
spring:
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://ip:port/test?serverTimezone=Hongkong&characterEncoding=utf-8&useSSL=false
    username: 
    password: 
// Spring Boot 启动类
@SpringBootApplication
@RestController
public class SpringDockerApplication {

    private final JdbcTemplate jdbcTemplate;
    public SpringDockerApplication(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }

    @GetMapping("/")
    public Message index() {
        RowMapper<Message> rowMapper= new BeanPropertyRowMapper<>(Message.class);
        Message msg = jdbcTemplate.queryForObject("select * from message where k = ?", rowMapper,"msg");
        return msg;
    }

    public static void main(String[] args) {
        SpringApplication.run(SpringDockerApplication.class, args);
    }
}

本地访问,能成功运行就说明,Spring Boot 已经配置完成了。下面就是容器化的操作了。

Containerize It

容器化其实就是创建 Docker 镜像的过程,需要把 jar 包封装进去。具体有两种方式:

  1. 创建 Dockerfile,手动执行 build 和 run。
  2. 使用 dockerfile-maven-plugin 插件。

Use Dockerfile

首先,在 src/main 下创建 docker 文件夹,并创建一个 Dockerfile,内容如下:

FROM openjdk:8-jdk-alpine
VOLUME /tmp
COPY spring-docker-1.0.0.jar app.jar
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]

假设大家对 Dockerfile 有一定的了解,解释一下上面的内容,

  • FROM...,表示使用 openjdk 作为基本镜像,标签为:8-jdk-alpine,意思 jdk 版本为 1.8,精简版。
  • VOLUME...,创建一个 VOLUME 指向 /tmp 的内容。因为这是 Spring Boot 应用程序默认为 Tomcat 创建工作目录的地方。效果是在 / var / lib / docker 下的主机上创建一个临时文件,并将其链接到 /tmp 下的容器。
  • COPY...,把项目中的 jar 文件复制过去,并重命名为 app.jar
  • ENTRYPOINT...,执行 java -jar 启动项目。java.security.egd=file:/dev/./urandom 的目的是为了缩短 Tomcat 启动的时间。

接下来,使用 maven 打包一个 jar,手动复制到 src/main/docker目录下。

配置 IDEA 来 build 和 run docker。

需要配置的参数如下:

  1. Name,创建的配置文件名称。
  2. Image tag,创建镜像的 repository:tags。
  3. Container name,创建容器名。
  4. Bind posts,端口映射,这里将默认的 8080 端口映射到外网的 8888 端口。
  5. 最后 IDEA 会将参数拼接成 docker build & run 的命令。

点击 Run。镜像就会被自动 build,并且在容器中运行了。

选择我们刚刚部署的那个容器的 Log tab,就能看到 Spring Boot 启动的日志了,是不是有一种似曾相识的感觉 😃

假设之前我们连接的是本地的 MySQL那么执行到这里应该会报错了,错误如下:

2019-08-27 10:37:04.197 ERROR 1 --- [eate-1939990953] com.alibaba.druid.pool.DruidDataSource   : create connection SQLException, url: jdbc:mysql://127.0.0.1:3306/test?serverTimezone=Hongkong&characterEncoding=utf-8&useSSL=false, errorCode 0, state 08S01

com.mysql.cj.jdbc.exceptions.CommunicationsException: Communications link failure
Caused by: com.mysql.cj.exceptions.CJCommunicationsException: Communications link failure
Caused by: java.net.ConnectException: Connection refused (Connection refused)

这是由于我们配置数据库 url 出现了问题,本地数据库,一般会写 localhost127.0.0.0.1。但是这个地址在 Docker 容器中是不认的。所以连不上本地数据库。幸好 Docker 在安装的时候配置了一个虚拟网桥,通过那个地址可以和 Docker 容器内部进行通信。

我们在宿主机上的 cmd 中输入 ipconfig ,就可以看到。

C:\Users\mqy6289>ipconfig
Windows IP 配置

以太网适配器 vEthernet (DockerNAT):
   连接特定的 DNS 后缀 . . . . . . . :
   IPv4 地址 . . . . . . . . . . . . : 10.0.75.1
   子网掩码  . . . . . . . . . . . . : 255.255.255.240
   默认网关. . . . . . . . . . . . . :

以太网适配器 以太网:
   连接特定的 DNS 后缀 . . . . . . . : apac.arcsoft.corp
   本地链接 IPv6 地址. . . . . . . . : fe80::c64:6e72:8311:378c%13
   IPv4 地址 . . . . . . . . . . . . : 172.17.218.99
   子网掩码  . . . . . . . . . . . . : 255.255.224.0
   默认网关. . . . . . . . . . . . . : 172.17.192.1

在 DockerNAT 中,宿主机的 ip 为 10.0.75.1,将数据库的 url ip 改成这个。将之前的容器和镜像删除后,重新执行之前的步骤,发现部署成功。

在浏览器中输入:http://127.0.0.1:8888/ ,就能看到 hello world 了。整个 Docker 部署的过程完成。

针对之前的网络通信问题,我们可以在 cmd 中输入 docker inspect hello-world 来查看容器的参数。可以看到容器的 IP 和网关的确不在一个网段,无法进行通信。

{
    "Networks": {
        "bridge": {
            "Gateway": "172.17.0.1",
            "IPAddress": "172.17.0.2",
            "MacAddress": "02:42:ac:11:00:02",
        }
    }
}

Use Maven Plugin

之前我们创建完 dockerfile 之后通过 IDEA 进行镜像的 build 和 run 工作,同样的我们也可以通过 Maven 插件将 Docker 镜像和容器的构建和 Maven 集成起来。阅读了很多博客,大多数任然使用 docker-maven-plugin,但是这个插件早就已经被官方废弃,不推荐使用,spotify 也推荐使用 dockerfile-maven-plugin 来代替。下面的 pom.xml 的配置:

<plugin>
  <groupId>com.spotify</groupId>
  <artifactId>dockerfile-maven-plugin</artifactId>
  <version>${dockerfile-maven-plugin.version}</version>
  <configuration>
    <contextDirectory>src/main/docker</contextDirectory>
    <repository>${docker.image.prefix}/${project.artifactId}</repository>
    <tag>v1</tag>
  </configuration>
</plugin>

刷新后,可在 IDEA 的 Maven tab 看到插件的功能,主要用到的就是 build、push、tag。

默认插件会找本地 tcp://localhost:2375 如果开启了,双击 dockerfile:build 镜像就会被 build 到 Docker 中去。

可以看到,整个 build 的过程被放到 Maven 中去了。需要运行的话,选择相应的镜像,create container 再做简单配置就可以了。

Troubleshooting

1.数据库连接不上。

本地数据库需要配置支持远程额访问,由于是 Windows,一般不会配置,可能会忽视。

UPDATE USER SET HOST = '%' WHERE USER = 'root';
FLUSH PRIVILEGES;

2.进入终端

我们这个基础镜像是 Java,默认应该是不带终端的,如果要查看的话,可再起一个容器

docker run -ti --entrypoint /bin/sh springboot/spring-docker:v1

进入后输入 ls -al,可以看到之前复制过去的 app.jar 文件

Summary

本文主要讲了如果在 Docker 中部署 Spring Boot 项目,针对于 Dockfile 的写法和 Maven 插件的使用,可以看参考文献 5-6,里面有更多的细节。我个人觉得这种部署方法,直接把 jar 和基本的环境打成一个 Docker 镜像还是过于简单了,很难去做监控和管理。是否还是应该像服务器部署那样,创建一个基本的 Centos 镜像,然后安装 Java 的环境,通过 ssh 连接,直接把 jar 包和配置文件复制到容器中通过 bash 运行,这种方式可能更符合常理。后期如果工作上有需求,可以再深度学习一下,看看实际生产中是如何操作的。

Reference

  1. Docker Get Started
  2. 30 分钟快速入门 Docker 教程
  3. Docker(一):Docker入门教程
  4. Spring Boot 2.0(四):使用 Docker 部署 Spring Boot
  5. Spring Boot with Docker
  6. Spring Boot Docker

Source Code

编辑推荐:
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· 展开说说关于C#中ORM框架的用法!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
点击右上角即可分享
微信分享提示