核心设计原则:
- 代码库「零侵入」:不包含任何 CI/CD 配置、Shell 脚本、K8s 部署文件(纯业务代码)。
- 配置 / 脚本「集中管理」:通过 CI/CD 工具的「全局配置」或「配置仓库」存储通用逻辑,避免散落。
- 流程「标准化」:无论用 GitLab/GitHub/Gitee,触发流程统一为「代码推送→CI 拉取外置配置→执行标准化流程」。
一、整体架构(通用核心,无仓库依赖)
plaintext
┌───────────────┐ ┌───────────────┐ ┌───────────────┐
│ 代码仓库 │ │ CI/CD 平台 │ │ 基础设施配置 │
│ (纯业务代码)│────▶│ (触发+执行) │────▶│ (外置存储) │
└───────────────┘ └───────────────┘ └───────────────┘
▲
│
▼
┌───────────────┐
│ 镜像仓库 │
│ (存储镜像) │
└───────────────┘
▲
│
▼
┌───────────────┐
└ Kubernetes (部署应用)
各组件职责(彻底解耦)
- 代码仓库:仅存 Java 业务代码(src、pom.xml),不包含任何与部署相关的文件。
- CI/CD 平台:接收代码推送触发,拉取外置配置,执行「构建→推镜像→部署」标准化流程(支持 Jenkins/GitLab CI/GitHub Actions 等)。
- 外置配置存储(二选一):
- 方案 A(简单):CI/CD 平台的「全局变量 + 全局共享脚本」(适合中小团队)。
- 方案 B(企业级):独立的「配置仓库」(如 Git 仓库存储脚本 / K8s 配置,CI 自动拉取)。
二、分步实现(通用流程,无仓库差异)
前置准备(一次性配置,终身复用)
- 环境就绪:K8s 集群、镜像仓库(私有)、CI/CD 平台(任选其一,以下以「Jenkins」为例,其他工具逻辑一致)。
- 外置配置准备(存储到 CI/CD 平台或配置仓库):
- 敏感信息:镜像仓库地址 / 用户名 / 密码、K8s 集群配置(kubeconfig)。
- 通用脚本:构建 Jar 包、推镜像、部署 K8s 的标准化 Shell 脚本。
- K8s 配置:Deployment/Service 的模板文件(用占位符替换动态信息)。
Step 1:代码仓库「零配置」(纯业务代码)
代码库只保留 Java 业务代码,结构如下(无任何部署相关文件):
plaintext
java-demo/
├── src/(业务代码)
│ └── main/
│ ├── java/com/example/DemoApplication.java
│ └── resources/application.yml
└── pom.xml(Maven 构建配置,仅关注业务依赖)
关键:pom.xml 标准化(仅业务相关)
无需加任何 CI/CD 相关配置,只需确保能打包成可执行 Jar 包(Spring Boot 默认支持):
xml
<build>
<finalName>java-demo</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.7.10</version>
<executions>
<execution>
<goals><goal>repackage</goal></goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
Step 2:外置配置存储(以「Jenkins 全局配置」为例,简单易落地)
所有部署相关的配置 / 脚本都存储在 CI/CD 平台,不侵入代码库。
1. 存储敏感信息(Jenkins 凭据管理)
进入 Jenkins → 凭据 → 系统 → 全局凭据,新增以下「安全凭据」(加密存储,避免泄露):
| 凭据 ID | 类型 | 内容 |
|---|---|---|
| REGISTRY_URL | 字符串 | 镜像仓库地址(如 registry.cn-hangzhou.aliyuncs.com) |
| REGISTRY_USER | 用户名密码 | 镜像仓库用户名 + 密码 |
| REGISTRY_NAMESPACE | 字符串 | 镜像仓库命名空间(如阿里云账号名) |
| KUBE_CONFIG | 字符串 | K8s 集群配置文件(kubeconfig)内容 |
2. 存储通用脚本(Jenkins 全局共享库)
通过 Jenkins 「全局共享库」存储标准化脚本(一次编写,所有项目复用):
- 新建一个独立的 Git 仓库(如
ci-shared-library),用于存储通用脚本(仅维护这一个仓库即可)。 - 仓库结构:
plaintext
ci-shared-library/
└── vars/
├── buildJar.groovy(构建 Jar 包脚本)
├── pushImage.groovy(推镜像脚本)
└── deployK8s.groovy(部署 K8s 脚本)
- 脚本内容(Groovy 语法,Jenkins 原生支持,跨项目复用):
(1)buildJar.groovy(构建 Jar 包,适配 Maven/Gradle)
groovy
def call() {
echo "=== 开始构建 Jar 包 ==="
// 自动识别构建工具(Maven/Gradle)
if (fileExists('pom.xml')) {
sh 'mvn clean package -DskipTests'
echo "Jar 包构建完成:target/java-demo.jar"
} else if (fileExists('build.gradle')) {
sh './gradlew clean build -x test'
echo "Jar 包构建完成:build/libs/java-demo.jar"
} else {
error "未找到 pom.xml 或 build.gradle,构建失败"
}
}
(2)pushImage.groovy(构建并推送镜像,内置 Dockerfile 逻辑)
groovy
def call(String imageTag) {
// 从 Jenkins 凭据中获取配置
def registryUrl = credentials('REGISTRY_URL')
def registryUser = credentials('REGISTRY_USER').username
def registryPwd = credentials('REGISTRY_USER').password
def registryNamespace = credentials('REGISTRY_NAMESPACE')
def imageName = "${registryUrl}/${registryNamespace}/java-demo:${imageTag}"
echo "=== 开始构建镜像:${imageName} ==="
// 内置 Dockerfile 逻辑(无需代码库包含 Dockerfile!)
sh """
cat > Dockerfile << 'EOF'
FROM maven:3.8.8-openjdk-11 AS builder
WORKDIR /build
COPY pom.xml .
COPY src ./src
RUN mvn clean package -DskipTests
FROM openjdk:11-jre-slim
WORKDIR /app
COPY --from=builder /build/target/java-demo.jar ./java-demo.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "java-demo.jar"]
EOF
"""
// 构建并推送镜像
sh """
echo "${registryPwd}" | docker login -u "${registryUser}" --password-stdin "${registryUrl}"
docker build -t ${imageName} .
docker push ${imageName}
"""
echo "=== 镜像推送完成:${imageName} ==="
}
(3)deployK8s.groovy(部署 K8s,内置部署文件模板)
groovy
def call(String imageTag) {
// 从 Jenkins 凭据中获取配置
def registryUrl = credentials('REGISTRY_URL')
def registryNamespace = credentials('REGISTRY_NAMESPACE')
def kubeConfig = credentials('KUBE_CONFIG')
def imageName = "${registryUrl}/${registryNamespace}/java-demo:${imageTag}"
echo "=== 开始部署到 K8s ==="
// 配置 K8s 环境
sh """
mkdir -p ~/.kube
echo "${kubeConfig}" > ~/.kube/config
chmod 600 ~/.kube/config
"""
// 内置 K8s 部署文件模板(无需代码库包含 K8s 文件!)
sh """
cat > deployment.yaml << 'EOF'
apiVersion: apps/v1
kind: Deployment
metadata:
name: java-demo-deploy
namespace: default
spec:
replicas: 2
selector:
matchLabels:
app: java-demo
template:
metadata:
labels:
app: java-demo
spec:
containers:
- name: java-demo-container
image: {{IMAGE_NAME}}
ports:
- containerPort: 8080
resources:
limits: {cpu: "1", memory: "1Gi"}
requests: {cpu: "0.5", memory: "512Mi"}
livenessProbe:
httpGet: {path: /health, port: 8080}
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet: {path: /health, port: 8080}
initialDelaySeconds: 5
periodSeconds: 5
EOF
cat > service.yaml << 'EOF'
apiVersion: v1
kind: Service
metadata:
name: java-demo-svc
namespace: default
spec:
selector: {app: java-demo}
ports: [{port: 80, targetPort: 8080}]
type: NodePort
EOF
"""
// 替换镜像名称并部署
sh """
sed -i "s|{{IMAGE_NAME}}|${imageName}|g" deployment.yaml
kubectl apply -f deployment.yaml
kubectl apply -f service.yaml
kubectl get pods -n default -l app=java-demo
"""
echo "=== K8s 部署完成 ==="
}
- Jenkins 配置共享库:
- 进入 Jenkins → 系统管理 → 系统配置 → 全局共享库。
- 名称:
ci-shared(自定义),默认版本:main(共享库的分支),仓库 URL:ci-shared-library的 Git 地址。
Step 3:配置 CI/CD 流水线(通用触发,无仓库差异)
无论代码仓库是 GitLab/GitHub/Gitee,只需在 CI/CD 平台配置「代码推送触发」,并调用全局共享脚本,无需修改代码库。
以 Jenkins 为例(Pipeline 脚本,通用适配所有仓库)
创建一个「多分支流水线」项目,配置如下:
- 源码管理:选择代码仓库类型(GitLab/GitHub/Gitee),填入仓库 URL,配置访问凭据(如 GitHub 个人令牌、GitLab 访问令牌)。
- 分支源:选择要触发的分支(如
main分支)。 - 流水线脚本:选择「从共享库加载」,脚本内容(仅 10 行左右,通用无差异):
groovy
// Jenkinsfile(存储在 Jenkins 项目配置中,无需代码库包含)
pipeline {
agent any // 选择支持 Docker 的 Jenkins 节点
triggers {
pollSCM('H/5 * * * *') // 或配置 WebHook 触发(更实时)
}
stages {
stage('构建 Jar 包') {
steps {
script {
ci-shared.buildJar() // 调用全局共享脚本
}
}
}
stage('构建并推送镜像') {
steps {
script {
def imageTag = env.GIT_COMMIT // 用 Git 提交哈希作为镜像版本
ci-shared.pushImage(imageTag) // 调用全局共享脚本
}
}
}
stage('部署到 K8s') {
steps {
script {
def imageTag = env.GIT_COMMIT
ci-shared.deployK8s(imageTag) // 调用全局共享脚本
}
}
}
}
post {
failure {
echo "部署失败,触发告警"
// 可添加邮件/钉钉告警逻辑(通用)
}
}
}
适配其他 CI/CD 工具(逻辑一致,仅配置不同)
无论用 GitLab CI、GitHub Actions 还是 Gitee Actions,核心逻辑都是「拉取外置脚本→调用标准化流程」,仅需调整「脚本加载方式」和「凭据引用方式」:
示例:GitLab CI 适配(.gitlab-ci.yml 存储在 GitLab 项目配置中,无需代码库包含)
yaml
workflow:
rules:
- if: $CI_COMMIT_BRANCH == "main"
image: ubuntu:latest
stages: [build, push-image, deploy-k8s]
# 构建 Jar 包(调用外置脚本,这里用 Git 拉取共享库)
build:
stage: build
before_script:
- git clone https://gitlab.com/your-org/ci-shared-library.git
script:
- source ci-shared-library/scripts/buildJar.sh
# 推送镜像(调用外置脚本)
push-image:
stage: push-image
before_script:
- git clone https://gitlab.com/your-org/ci-shared-library.git
- apt install -y docker.io && systemctl start docker
script:
- source ci-shared-library/scripts/pushImage.sh $CI_COMMIT_SHA
# 部署 K8s(调用外置脚本)
deploy-k8s:
stage: deploy-k8s
before_script:
- git clone https://gitlab.com/your-org/ci-shared-library.git
- apt install -y kubectl
script:
- source ci-shared-library/scripts/deployK8s.sh $CI_COMMIT_SHA
Step 4:触发流程(所有仓库通用,无需改代码)
- 本地开发:修改 Java 业务代码,推送至 GitLab/GitHub/Gitee 的
main分支。 - 自动触发:CI/CD 平台(Jenkins/GitLab CI 等)检测到代码推送,自动启动流水线。
- 执行流程:
- 拉取代码仓库的纯业务代码。
- 拉取外置的通用脚本和配置。
- 调用
buildJar构建 Jar 包。 - 调用
pushImage构建镜像(内置 Dockerfile)并推送至镜像仓库。 - 调用
deployK8s部署至 K8s 集群(内置 K8s 配置)。
- 验证结果:访问 K8s 暴露的服务地址,确认应用正常运行。
三、企业级优化(可选,进一步提升通用性和稳定性)
1. 配置仓库加密存储(方案 B 升级)
将敏感信息和脚本存储在「加密配置仓库」(如 Vault、AWS Secrets Manager 或 GitLab 加密仓库),CI/CD 工具通过 API 拉取,进一步提升安全性。
2. 多环境部署(无需改代码,仅切换配置)
在 CI/CD 平台配置「环境变量」(如 ENV=test/pre/prod),通用脚本根据环境变量自动切换 K8s 命名空间、镜像仓库、资源配置:
groovy
// deployK8s.groovy 中新增环境适配
def env = System.getenv('ENV') ?: 'test'
def namespace = env == 'prod' ? 'prod-namespace' : 'test-namespace'
sh "kubectl apply -f deployment.yaml -n ${namespace}"
3. 镜像版本规范化(通用逻辑,外置配置)
统一镜像版本格式(如 v{语义化版本}-{Git 哈希}),通过外置脚本自动生成,无需开发者手动管理:
groovy
// pushImage.groovy 中新增版本生成逻辑
def semanticVersion = sh(returnStdout: true, script: 'cat pom.xml | grep -oP \'<version>\\K[^<]+\'').trim()
def imageTag = "${semanticVersion}-${env.GIT_COMMIT.substring(0,8)}"
4. 回滚机制(通用外置,一键触发)
在 CI/CD 平台配置「手动回滚按钮」,调用外置的 rollbackK8s.groovy 脚本,无需修改代码或配置:
groovy
def call(String imageTag) {
echo "=== 回滚到镜像版本:${imageTag} ==="
sh """
sed -i "s|{{IMAGE_NAME}}|${registryUrl}/${registryNamespace}/java-demo:${imageTag}|g" deployment.yaml
kubectl apply -f deployment.yaml -n ${namespace}
"""
}
四、核心优势(真正的通用方案)
- 代码库彻底干净:仅存业务代码,新人无需关注部署逻辑,专注开发。
- 全场景复用:换代码仓库(GitLab→GitHub)、换 CI/CD 工具(Jenkins→GitLab CI)、换环境(测试→生产),均无需修改业务代码,仅需调整 CI/CD 平台的配置。
- 维护成本极低:通用脚本和配置集中管理,修改一次,所有项目自动继承(如优化镜像构建逻辑、调整 K8s 资源限制,无需逐个项目同步)。
- 安全性高:敏感信息(镜像仓库密码、K8s 配置)加密存储在 CI/CD 平台或配置仓库,不散落于代码库。
- 门槛低:开发者只需懂 Git 推送,无需掌握 Docker、K8s、Shell 脚本知识。
五、总结
这套方案的核心是「彻底解耦」—— 通过「业务代码与部署逻辑分离、配置与执行分离、敏感信息与公开代码分离」,实现了真正的跨仓库、跨工具、跨环境通用。
无论你当前用的是 GitLab、GitHub 还是 Gitee,后续切换任何平台,都无需修改一行业务代码,仅需在新的 CI/CD 平台配置「拉取外置脚本 + 引用凭据」,即可快速复用整个部署流程,真正做到「一次配置,终身复用」。

3935

被折叠的 条评论
为什么被折叠?



