自定义maven编译后生成的文件路径

需求

之前项目的部署方式,是将每个子模块编译后产生的 jar 包拷贝到指定目录,然后执行脚本,该脚本的大致内容就是根据每个模块的 Dockerfile 文件构建镜像,然后将编译产生的 jar 包拷贝进镜像里面,依次执行 docker run 命令来启动程序。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#! /bin/bash

docker pull mongo:4.4.1
# 拉取其他镜像
docker pull ....


## 每个模块都有一个文件夹,编译产生的jar包和对应的Dockerfile文件都在其文件夹内
##
docker build -t boat-common:v1.0.0 ./boat-common
docker build -t boat-server:v1.0.0 ./boat-server
## ..... 省略其他编译语句


docker network create boat-network


## 然后再根据编译出来的镜像运行容器
docker run -d \
--net boat-network \
--name proxy-node-1 \
--restart=always \
-p 127.0.0.1:7050:80 \
-p 127.0.0.1:7051:10415 \
-p 127.0.0.1:7052:10416 \
-p 127.0.0.1:7053:10417 \
boat-proxy:v1.0.0

## .... 省略其他容器运行语句

这么多容器要运行,并且容器之间还有编排的关系,这里可以使用 docker-compose 去管理容器,将这么多容器划分为一个服务,以服务的级别去管理这些容器。

问题

如果在现在这个项目里面使用 docker-compose 的话有几个问题:

  • 除了基础服务(如 mongodb、redis、mqtt)外,其他容器镜像都需要依赖一个定义的镜像(这里是 boat-common)
  • 脚本文件里,需要将每个模块的 jar 包拷贝到模块目录下面,与 Dockerfile 同级。

实现

现在这个项目是一个主模块和多个子模块的目录结构,在项目根目录有一个 deploy 目录专门存放模块部署文件的文件夹,每个文件夹存放 Dockerfile 和服务运行所依赖的文件,比如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
.
├── boat-media
├── daily-check.sh
├── deploy ## 存放部署文件
│   ├── common ## 每个模块都有一个文件夹,存放Dockerfile和服务运行依赖文件
│   ├── docker-compose.yml
│   ├── logger
│   ├── media
│   ├── proxy
│   ├── server
│   ├── static
│   └── web
├── docs
├── pom.xml
├── usv-cloud-balance ## 下面都是子模块
├── usv-cloud-base
├── usv-cloud-logger
├── usv-cloud-media
├── usv-cloud-proxy
├── usv-cloud-server
└── usv-cloud-web

第一个问题可以借助 docker-compose.yaml 文件中的 build 选项来实现。docker-compose文件的编写中,除了可以指定本地镜像和 DockerHub 仓库中的镜像之外,也可以在运行时根据 Dockerfile 去构建镜像,比如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
version: '3'
services:
porxy:
image: boat-proxy:v1.0.0
## 使用build选项来动态构建所需镜像
build:
context: ./proxy
dockerfile: Dockerfile
container_name: proxy-node-1
restart: always
privileged: true
environment:
- TZ=Asia/Shanghai
ports:
- 7050:80
- 7051:10415
- 7052:10416
- 7053:10417
networks:
- boat-network
depends_on:
- mqtt

在上面的 yaml 文件中可以看到使用了 build 选项,这个选项指定为构建镜像上下文路径

  • context:上下文路径,也就是存放 Dockerfile 文件的文件夹目录地址
  • dockerfile:指定构建镜像的 Dockerfile 文件名
  • args:添加构建参数,这是只能在构建过程中访问的环境变量。
  • labels:设置构建镜像的标签。
  • target:多层构建,可以指定构建哪一层。

后面三个参数我没有使用,在当前场景下没有必要使用。

使用 build 选项就可以解决容器使用自定义镜像的问题,但是 Dockerfile 文件是需要把 jar 包拷贝进容器的,在之前的部署中都是需要手动编译并且拷贝 jar 包到指定目录下才能部署。那现在也是遇到了这个问题,要如何将每个模块编译后产生的 jar 包移动到 deploy 目录下呢?

先来看看现在的目录结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
├── deploy                    ## 存放部署文件
│   ├── common ## 每个模块都有一个文件夹,存放Dockerfile和服务运行依赖文件
│   ├── docker-compose.yml
│   ├── logger
│   ├── media
│   ├── proxy
│   ├── server
│   ├── static
│   └── web
├── pom.xml ## 项目根目录
├── usv-cloud-media
│   ├── pom.xml ## 子模块的pom文件
...忽略其他子模块,目录结构都与usv-cloud-media保持一致

在根目录中执行 mvn install -DskipTests=true 编译命令的话,最终生成的 jar 包都会是在每个子模块下的 target 目录下,比如:

1
2
3
4
5
6
7
8
9
10
11
├── usv-cloud-media
│   ├── pom.xml ## 子模块的pom文件
│ ├── target
│ │   ├── antrun
│ │   ├── classes
│ │   ├── generated-sources
│ │   ├── generated-test-sources
│ │   ├── maven-archiver
│ │   ├── maven-status
│ │   ├── test-classes
│ │   ├── usv-cloud-media-V1.0.0.jar

那有什么办法可以把每个模块所编译出来的 jar 包都放在子模块的上一级的 deploy 目录中呢?

上网冲浪了一下,发现在 pom 文件中添加 maven-antrun-plugin 插件可以解决这个问题:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<!-- 将编译好的jar复制到项目根目录/deploy/{模块}目录下 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.8</version>
<executions>
<execution>
<id>install</id>
<phase>install</phase>
<configuration>
<target>
<!-- 复制命令,将${project.build.directory}目录下的所有后缀名为jar 文件 都拷贝到 todir目录下 -->
<copy todir="../deploy/proxy" overwrite="true">
<fileset dir="${project.build.directory}" erroronmissingdir="false">
<include name="*.jar" />
</fileset>
</copy>
</target>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>

execution 标签代表着可执行命令,可以修改 maven 的命令执行过程,这里是修改了 install;

copy 是复制命令,其中 todir 是目标文件夹,overwrite 属性代表着如果存在旧文件是否覆盖。而代码中我是将文件拷贝到当前目录的上一级的 deploy 目录中。

fileset 标签中的 dir 属性代表着源文件夹,include 标签是源文件,可以使用符号匹配,这里使用了 *

在上面的代码中还是用到了一些环境变量:

project.build.directory 代表着 target 目录

还有其他环境变量,比如:

basedir 表示该 pom 文件所代表模块的根目录

project.build.finalName 代表 jar 包的前缀名,不包括后缀名。

而这样,就可以解决模块编译后的 jar 文件拷贝到指定目录,然后使用 docker-compose 去统一管理容器。


自定义maven编译后生成的文件路径
https://sunshinechen.cn/2023/06/08/自定义maven编译后生成的文件路径/
作者
sunshine
发布于
2023年6月8日
许可协议