从单仓到多仓:Spring Cloud 项目的拆分与持续集成落地

写在前面

这次拆分 Spring Cloud 仓库的过程,本来只是想“让构建解耦,更快一点”,没想到一路从 GitLab 到 Docker,再到流水线和镜像管理,全成了系统级改造。过程中踩了不少坑,也积累了不少可复用的流程。这里把整个拆分与 CI/CD 部署过程记录下来,或许能给后来者一点参考。

每个初学者的项目里,都藏着未来让自己会心一笑的代码和方案。这次对 Spring Cloud 的仓库拆分与 CI/CD 改造,就是这样一次「看似笨拙却真实」的尝试。它不完美,也不优雅,但它让我第一次体会到架构演进背后的复杂与乐趣。


介绍项目

image.png
docker目录未提交,结构为:
image.png

这是本次分库项目,有auth服务flowSpace服务gateway服务user服务common公共模块组成,4个微服务都依赖父pomcommon模块

先看看目前的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模块,实现依赖版本管理和公共模块的导入

image.png


详细流程

1.父pom

建立独立仓库yw-parent

image.png

此仓库不仅仅只是对父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,便于在其他模块与服务引用

image.png

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 项目结构虽然简单,步骤也不算复杂,但其中的坑绝不比代码少,未来回头看,也许会笑自己当初的笨拙。可正是这些不断试错与修补的过程,构成了学习的真实轨迹。希望这份记录能为后来者提供一点方向,也为未来的自己留下可供对照的起点。


参考资料

  1. 部署镜像:https://github.com/AfterYuWei/gitlab-portainer-deploy

从单仓到多仓:Spring Cloud 项目的拆分与持续集成落地
https://blog.yuweinfo.com/2025/10/06/从单仓到多仓:Spring Cloud 项目的拆分与持续集成落地/
作者
YuWei
发布于
2025年10月6日
许可协议