从单仓到多仓:Spring Cloud 项目的拆分与持续集成落地
写在前面
这次拆分 Spring Cloud 仓库的过程,本来只是想“让构建解耦,更快一点”,没想到一路从 GitLab 到 Docker,再到流水线和镜像管理,全成了系统级改造。过程中踩了不少坑,也积累了不少可复用的流程。这里把整个拆分与 CI/CD 部署过程记录下来,或许能给后来者一点参考。
每个初学者的项目里,都藏着未来让自己会心一笑的代码和方案。这次对 Spring Cloud 的仓库拆分与 CI/CD 改造,就是这样一次「看似笨拙却真实」的尝试。它不完美,也不优雅,但它让我第一次体会到架构演进背后的复杂与乐趣。
介绍项目

docker目录未提交,结构为:
这是本次分库项目,有auth服务,flowSpace服务,gateway服务,user服务,common公共模块组成,4个微服务都依赖父pom和common模块。
先看看目前的CICD的部分流程
# 全局规则
.global-changes-rule: &global-changes-rule
changes:
- "docker/**/*"
- "yw-common/**/*"
- pom.xml
when: always
compile-auth:
# 阶段
stage: compile
# 指定使用镜像
image: harbor.xxx.com:29443/common/java-maven-node:17-3.9-18
#规则
rules:
#当文件夹yw-auth-service下的文件有变动时触发
- changes:
- "yw-auth-service/**/*"
#全局构建
- *global-changes-rule
# 脚本
script:
# 登录harbor
- docker login -u $HARBOR_USER -p $HARBOR_PASS $HARBOR_URL
# 编译
- mvn clean package -pl yw-auth-service -am -Dmaven.test.skip=true -Dfile.encoding=UTF-8
# 构建镜像
- docker build -t ${HARBOR_URL}/yuwei-cloud/auth:${CI_COMMIT_SHORT_SHA} -f docker/Dockerfile-auth .
# 推送HASH值镜像
- docker push ${HARBOR_URL}/yuwei-cloud/auth:${CI_COMMIT_SHORT_SHA}
# 推送LATEST镜像
- docker tag ${HARBOR_URL}/yuwei-cloud/auth:${CI_COMMIT_SHORT_SHA} ${HARBOR_URL}/yuwei-cloud/auth:latest
- docker push ${HARBOR_URL}/yuwei-cloud/auth:latest
# 指定Runner
tags:
- ruoyi
deploy-auth:
stage: deploy
image: harbor.xxx.com:29443/common/gitlab-portainer-deploy:latest
#部署阶段禁用缓存
cache: []
script:
- python /app/deploy.py --URL "$PORTAINER_URL" --USERNAME "$PORTAINER_USERNAME" --PASSWORD "$PORTAINER_PASSWORD" --ENVIRONMENT "1Panel" --STACK "yw-cloud" --SERVICE "$CI_PROJECT_NAME" --IMAGE "$CI_REGISTRY_IMAGE:${CI_COMMIT_SHORT_SHA}" --ROLLBACK
tags:
- ruoyi
only:
- main通过gitlab.ci的rule功能实现单仓库的指定微服务构建,上面给出的yml是auth和公共部分的代码
- 当检测到docker(cicd相关代码),common公共模块,父pom方式代码变动,则触发整个项目的所有模块构建
- 当检测到对应auth模块变更时,只触发auth模块的构建
由于harbor,gitlab,portainer 3者均不在同一服务器,在10M带宽的传输下,单模块构建需要3-5分钟,全模块构建需要15-20分钟。
在开发的过程中,由于是单仓库,则会将所有的代码都从云拉取下来,虽然是一个微服务的项目,但是只体现在了部署的过程中,在开发环节与SpringBoot的开发毫无区别,多成员开发时,只需要对auth模块进行开发,却需要拉取整个代码的项目,抛开整个项目代码易泄露不谈,开发过程中由于idea可能识别到其他服务,在这过程中会出现A模块引用B模块的情况,导致项目耦合度极高,不易于项目的健康发展与维护,故有了此次项目的拆分。
分库思路
- 在gitlab中创建群组group,在group中创建下列独立仓库
- 4个微服务拆分为4个独立仓库
- common模块与父pom拆分为2个独立仓库,提交jar包与pom文件至gitlab的 Package registry (软件包镜像仓库)
- common模块通过Package registry拉取父pom,实现依赖版本管理
- 4个微服务通过Package registry拉取父pom和common模块,实现依赖版本管理和公共模块的导入

详细流程
1.父pom
建立独立仓库yw-parent

此仓库不仅仅只是对父pom进行管理,还可以在cicd的过程进行多环境的打包等等功能
pom文件中增加GitLab Maven 仓库发布配置
<!-- GitLab Maven 仓库发布配置 -->
<distributionManagement>
<repository>
<id>gitlab.xxx.yw-cloud</id>
<url>https://gitlab.xxx.com/api/v4/projects/${projects-id}/packages/maven</url>
</repository>
</distributionManagement>.gitlab-ci.yml文件
stages:
- build
- deploy
variables:
MAVEN_CLI_OPTS: "-B -U -V -s .maven/settings.xml"
before_script:
- mkdir -p .maven
- |
cat > .maven/settings.xml <<EOF
<settings>
<servers>
<server>
<id>gitlab.xxx.yw-cloud</id>
<configuration>
<httpHeaders>
<property>
<name>Private-Token</name>
<value>\${CI_MAVEN_TOKEN}</value>
</property>
</httpHeaders>
</configuration>
</server>
</servers>
</settings>
EOF
build:
stage: build
tags:
- ruoyi
image: registry.cn-hangzhou.aliyuncs.com/xxx/java-maven-node:21-3.9-18
script:
- mvn $MAVEN_CLI_OPTS clean install
deploy:
stage: deploy
tags:
- ruoyi
image: registry.cn-hangzhou.aliyuncs.com/xxx/java-maven-node:21-3.9-18
script:
- mvn $MAVEN_CLI_OPTS versions:set -DnewVersion=$CI_COMMIT_SHORT_SHA
- mvn $MAVEN_CLI_OPTS deploy
only:
- main- cicd功能,在修改提交父pom(yw-parent)后,触发流水线,编辑父pom并上传到gitlab的 Package registry (软件包镜像仓库)
- 提交的short-sha作为版本号,区分每个版本的父pom,便于在其他模块与服务引用

2.common模块
common模块与父pom模块的差距不大,主要是增加对父pom的仓库引用
pom文件
<!-- 继承父 POM -->
<parent>
<groupId>com.xxx</groupId>
<artifactId>yw-parent</artifactId>
<version>81cf439d</version>
<relativePath/>
</parent>
<repositories>
<repository>
<id>gitlab.xxx.yw-cloud</id>
<url>https://gitlab.xxx.com/api/v4/groups/${groups-id}/-/packages/maven</url>
</repository>
</repositories>
<distributionManagement>
<repository>
<id>gitlab.xxx.yw-cloud</id>
<url>https://gitlab.xxx.com/api/v4/projects/${projects-id}/packages/maven</url>
</repository>
</distributionManagement>引入整个群组的maven仓库,方便maven的导入,也可以参考distributionManagement使用项目ID的方式,实现精准的导入。
思路: 引入整个群组,上传精确仓库
.gitlab-ci.yml文件
stages:
- build
- deploy
variables:
MAVEN_CLI_OPTS: "-B -U -V -s .maven/settings.xml"
before_script:
- mkdir -p .maven
- |
cat > .maven/settings.xml <<EOF
<settings>
<servers>
<server>
<id>gitlab.xxx.yw-cloud</id>
<configuration>
<httpHeaders>
<property>
<name>Private-Token</name>
<value>\${CI_MAVEN_TOKEN}</value>
</property>
</httpHeaders>
</configuration>
</server>
</servers>
</settings>
EOF
build:
stage: build
tags:
- ruoyi
image: registry.cn-hangzhou.aliyuncs.com/xxx/java-maven-node:21-3.9-18
script:
- mvn $MAVEN_CLI_OPTS clean install
deploy:
stage: deploy
tags:
- ruoyi
image: registry.cn-hangzhou.aliyuncs.com/xxx/java-maven-node:21-3.9-18
script:
- mvn $MAVEN_CLI_OPTS versions:set -DnewVersion=$CI_COMMIT_SHORT_SHA
- mvn $MAVEN_CLI_OPTS deploy
only:
- main该文件与父pom相同
3.auth服务
pom文件
由于不需要上传到Package registry,故只需要引入私有group仓库
<!-- 继承父 POM -->
<parent>
<groupId>com.xxx</groupId>
<artifactId>yw-parent</artifactId>
<version>81cf439d</version>
<relativePath/>
</parent>
<!-- 项目公共模块 -->
<dependency>
<groupId>com.yuweinfo</groupId>
<artifactId>yw-common</artifactId>
<version>6fef139e</version>
</dependency>
<repositories>
<repository>
<id>gitlab.xxx.yw-cloud</id>
<url>https://gitlab.xxx.com/api/v4/groups/${groups-id}/-/packages/maven</url>
</repository>
</repositories>gitlab-ci.yml文件
stages:
- build
- deploy
# Maven 缓存目录
cache:
key: "maven-${CI_COMMIT_REF_SLUG}"
paths:
- .m2/repository
before_script:
- mkdir -p .maven
- |
cat > .maven/settings.xml <<EOF
<settings>
<servers>
<server>
<id>gitlab.xxx.yw-cloud</id>
<configuration>
<httpHeaders>
<property>
<name>Private-Token</name>
<value>\${CI_MAVEN_TOKEN}</value>
</property>
</httpHeaders>
</configuration>
</server>
</servers>
</settings>
EOF
build:
stage: build
image: registry.cn-hangzhou.aliyuncs.com/xxx/java-maven-node:21-3.9-18
script:
# Maven 构建,使用自定义 settings.xml
- mvn clean package -Dmaven.test.skip=true -Dfile.encoding=UTF-8 -s .maven/settings.xml -Dmaven.repo.local=.m2/repository
# 构建镜像
- docker build -t $CI_REGISTRY_IMAGE:${CI_COMMIT_SHORT_SHA} -f .gitlab/Dockerfile .
# 登录 GitLab Registry 并推送镜像
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
- docker push $CI_REGISTRY_IMAGE:${CI_COMMIT_SHORT_SHA}
- docker tag $CI_REGISTRY_IMAGE:${CI_COMMIT_SHORT_SHA} $CI_REGISTRY_IMAGE:latest
- docker push $CI_REGISTRY_IMAGE:latest
tags:
- ruoyi
only:
- main
deploy:
stage: deploy
image: registry.cn-hangzhou.aliyuncs.com/xxx/gitlab-portainer-deploy:latest
#部署阶段禁用缓存
cache: []
script:
- python /app/deploy.py --URL "$PORTAINER_URL" --USERNAME "$PORTAINER_USERNAME" --PASSWORD "$PORTAINER_PASSWORD" --ENVIRONMENT "1Panel" --STACK "yw-cloud" --SERVICE "$CI_PROJECT_NAME" --IMAGE "$CI_REGISTRY_IMAGE:${CI_COMMIT_SHORT_SHA}" --ROLLBACK
tags:
- ruoyi
only:
- main
此yml放弃将镜像上传到harbor仓库,而且上传到gitlab的Container registry,方便对镜像进行管理,其他服务只需要参考auth模块进行修改。
此时拉取独立仓库,即可单独启动并开发,必要时拉取common与父pom,提交之后修改版本号,依旧可以完成开发。
结语
此次的 Spring Cloud 项目结构虽然简单,步骤也不算复杂,但其中的坑绝不比代码少,未来回头看,也许会笑自己当初的笨拙。可正是这些不断试错与修补的过程,构成了学习的真实轨迹。希望这份记录能为后来者提供一点方向,也为未来的自己留下可供对照的起点。