Files
conti-docs/backend/09-build-deploy.md
T
Guangfei.Zhao 1e0cbb86a2 feat: Add comprehensive documentation for integration layer, API design, config governance, observability, build/deploy, and testing strategies
- Introduced integration layer design with Resilience4j for external vendor calls.
- Established API design standards with unified response structures and global exception handling.
- Defined configuration and service governance using Kubernetes native solutions.
- Implemented observability practices including trace ID propagation and structured logging.
- Outlined build and multi-environment deployment strategies using Gradle and GitLab CI/CD.
- Specified testing strategies across different layers, utilizing JUnit, MockK, Testcontainers, and WireMock.
2026-08-12 18:23:11 +08:00

4.5 KiB
Raw Blame History

09. 构建与多环境部署

决策

Gradle 多模块统一构建,bootstrap 产出单一 jar/Docker 镜像;沿用现有 GitLab CI/CD → Azure 部署链路(见 Architecture-Diagram/gitlab-cicd-azure-deployment-diagram.drawio)。

结构约定

settings.gradle              # include 所有 platform-* / domains/*(见 01-project-structure.md
build.gradle                 # 根工程统一 Kotlin/Spring Boot 插件版本、依赖约束
bootstrap/build.gradle       # bootJar,构建出可执行 jar
Dockerfile                   # 基于 bootstrap 的 jar 打镜像
.gitlab-ci.yml                # build -> test -> docker build/push -> deploy

Dockerfile 示例(多阶段构建)

# Dockerfile
FROM eclipse-temurin:21-jdk AS build
WORKDIR /workspace
COPY . .
RUN ./gradlew :bootstrap:bootJar --no-daemon

FROM eclipse-temurin:21-jre
WORKDIR /app
COPY --from=build /workspace/bootstrap/build/libs/*.jar app.jar
ENTRYPOINT ["java", "-jar", "app.jar"]

多阶段构建的好处:最终镜像只包含 JRE + 一个 jar,不带 Gradle 缓存、源码、编译工具链,镜像体积和攻击面都更小。

GitLab CI 示例(节选)

# .gitlab-ci.yml
stages:
  - build
  - test
  - package
  - deploy

build:
  stage: build
  script:
    - ./gradlew build -x test --no-daemon

test:
  stage: test
  script:
    - ./gradlew test --no-daemon
  artifacts:
    reports:
      junit: '**/build/test-results/test/TEST-*.xml'

docker-build:
  stage: package
  script:
    - docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA .
    - docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA

deploy-uat:
  stage: deploy
  environment: uat
  only:
    - main
  script:
    - kubectl set image deployment/conti-backend conti-backend=$CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA -n retailapp-uat

具体 stage 划分、部署到 Azure AKS 的凭证配置沿用现有 gitlab-cicd-azure-deployment-diagram 里已经跑通的流程,这里只体现"单一镜像、按环境部署"这条主线。

关键规则

  • 多环境(dev/uat/prod)通过 K8s namespace + ConfigMap/Secret 区分(见 07-config-governance.md),镜像本身不区分环境,同一个镜像跨环境部署,只是挂载的 ConfigMap/Secret 和 SPRING_PROFILES_ACTIVE 不同——避免"UAT 验证过的镜像和 Prod 部署的镜像不是同一个产物"这种环境不一致风险。
  • CI 流程顺序:Gradle build(含单元测试)→ 打 Docker 镜像 → 推送镜像仓库 → GitLab CI/CD 触发 Azure/K8s 部署。
  • 模块化单体阶段只有一个部署产物(一个 Deployment);如果后续拆分微服务,每个 domain 各自补一份 Dockerfile 和 CI job,工程结构上已经按模块划好边界(见 01-project-structure.md),拆分成本较低——本质上是把 bootstrap 依赖的某个 domains/xxx 模块摘出来,单独套一层 @SpringBootApplication 入口和自己的 Dockerfile

附录:为什么坚持"一个镜像走所有环境"

一种常见但有风险的做法是:给每个环境单独打包(比如构建时注入 application-uat.yml 到镜像里),这样看起来"环境隔离更彻底",但实际引入了一个更严重的问题——UAT 验证通过的镜像和 Prod 部署的镜像,字节级别就不是同一个东西,即使代码版本号一样,构建过程中的依赖解析、基础镜像 layer 缓存状态都可能有细微差异,理论上会出现"UAT 测过没问题,Prod 部署后行为不一致"的情况,而且事后很难证明"两次构建到底有没有差异"。

"一个镜像走所有环境"Build once, deploy many)反过来保证:镜像本身在所有环境完全一致,环境差异只体现在外部注入的配置(ConfigMap/Secret/环境变量)上。这也是 The Twelve-Factor App 里"严格分离构建和运行"这条原则的直接应用。

待补充

  • 具体 CI pipeline 的完整 stage 定义和镜像版本/tag 策略。
  • 灰度发布/回滚方案。
  • Gradle 构建缓存/并行构建的 CI 加速配置。

参考链接